Chinaunix首页 | 论坛 | 博客
  • 博客访问: 352677
  • 博文数量: 67
  • 博客积分: 2550
  • 博客等级: 少校
  • 技术积分: 990
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-17 18:24
文章分类

全部博文(67)

文章存档

2011年(6)

2010年(2)

2009年(40)

2008年(19)

我的朋友

分类: LINUX

2009-02-19 11:19:32

__attrubte__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
#define __u8    unsigned char
#define __u16   unsigned short
/* __attribute__ ((packed)) 的位置约束是放于声明的尾部“;”之前 */
struct str_struct{
        __u8    a;
        __u8    b;
        __u8    c;
        __u16   d;
} __attribute__ ((packed));
/*  当用到typedef时,要特别注意__attribute__ ((packed))放置的位置,相当于:
  *  typedef struct str_stuct str;
  *  而struct str_struct 就是上面的那个结构。
  */
typedef struct {
        __u8    a;
        __u8    b;
        __u8    c;
        __u16   d;
} __attribute__ ((packed)) str;
/* 在下面这个typedef结构中,__attribute__ ((packed))放在结构名str_temp之后,其作用是被忽略的,注意与结构str的区别。*/
typedef struct {
        __u8    a;
        __u8    b;
        __u8    c;
        __u16   d;
}str_temp __attribute__ ((packed));
typedef struct {
        __u8    a;
        __u8    b;
        __u8    c;
        __u16   d;
}str_nopacked;
int main(void)
{
        printf("sizeof str = %d\n", sizeof(str));
        printf("sizeof str_struct = %d\n", sizeof(struct str_struct));
        printf("sizeof str_temp = %d\n", sizeof(str_temp));
        printf("sizeof str_nopacked = %d\n", sizeof(str_nopacked));
        return 0;
}
编译运行:
[root@localhost root]# ./packedtest   
sizeof str = 5
sizeof str_struct = 5
sizeof str_temp = 6
sizeof str_nopacked = 6
--------------------------------------------------------------------
GNU C的一大特色就是__attribute__机制。__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。
__attribute__书写特征是:__attribute__前后都有两个下划线,并且后面会紧跟一对括弧,括弧里面是相应的__attribute__参数。
__attribute__语法格式为:
__attribute__ ((attribute-list))
其位置约束:放于声明的尾部“;”之前。
函数属性(Function Attribute):函数属性可以帮助开发者把一些特性添加到函数声明中,从而可以使编译器在错误检查方面的功能更强大。__attribute__机制也很容易同非GNU应用程序做到兼容之功效。
GNU CC需要使用 –Wall编译器来击活该功能,这是控制警告信息的一个很好的方式。
packed属性:使用该属性可以使得变量或者结构体成员使用最小的对齐方式,即对变量是一字节对齐,对域(field)是位对齐。

使用GCC __attribute__和link脚本来控制section基地址


样例代码 file: test.section.c

#include
#include

int localmemory0 __attribute__ ((section("LOCALmem")))=0;
int localmemory1 __attribute__ ((section("LOCALmem")))=0;

int globalmemory __attribute__ ((section("GLOBALmem")))=0;

int main (int argc, char * argv[])
{

        localmemory0 = 0x456;
        localmemory1 = 0x123;
        
        globalmemory = localmemory0 + localmemory1;
}

在上面的代码中定义了两个非传统Section  LOCALmem 和 GLOBALmem
要求变量 localmemroy0和变量localmemory0 存放在section  LOCALmem
而变量 globalmemory 存放在section GLOBALmem

首先使用命令行

gcc -c -o test.section.o test.section.c

或者

gcc -c -o test.section.o -fdata-sections test.section.c

获得目标代码 test.section.o
-fdata-sections选项的目的是让编译器为每一个单独申明的数据section实际分配一个section,而不是占用.bss,在某些系统上需要显式的使用这一参数

再使用objdump查看代码

objdump -S test.secton.o

获得如下结果

test.section.o:     file format elf32-i386

Disassembly of section .text:

00000000 :
   0:   55                          push   %ebp
   1:   89 e5                     mov    %esp,%ebp
   3:   83 ec 08                sub    $0x8,%esp
   6:   83 e4 f0                 and    $0xfffffff0,%esp
   9:   b8 00 00 00 00      mov    $0x0,%eax
   e:   29 c4                      sub    %eax,%esp
  10:   c7 05 00 00 00 00 56    movl   $0x456,0x0
  17:   04 00 00
  1a:   c7 05 00 00 00 00 23    movl   $0x123,0x0
  21:   01 00 00
  24:   a1 00 00 00 00             mov    0x0,%eax
  29:   03 05 00 00 00 00       add    0x0,%eax
  2f:   a3 00 00 00 00              mov    %eax,0x0
  34:   c9                                 leave
  35:   c3                                 ret

注意到两条movl指令分别将数据存放到localmemory0和localmemory1,在leave指令之前的mov将加法结果存放到globalmemory中
由于是目标文件,变量符号对于的地址没有经过解析和分配,指令中变量对应的地址都是0x0。

使用一个link脚本script来控制链接器ld输出section的基地址。

file: sections.script

SECTIONS
{
  .text :
  {
    *(.text)
   }

  LOCALmem 0x1f0000 :
  {
    *(LOCALmem)
   }

  GLOBALmem 0xff0000 :
  {
    *(GLOBALmem)
  }

}

使用命令行:

ld -o test.section.elf -T section.script test.section.o

获得elf可执行文件链接结果 test.section.elf

这时使用 objdump 观看链接结构

命令行:

objdump -S test.section.elf

可以得到:

test.section.elf:     file format elf32-i386

Disassembly of section .text:

00000000 :
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 08                sub    $0x8,%esp
   6:   83 e4 f0                and    $0xfffffff0,%esp
   9:   b8 00 00 00 00          mov    $0x0,%eax
   e:   29 c4                   sub    %eax,%esp
  10:   c7 05 00 00 1f 00 56    movl   $0x456,0x1f0000
  17:   04 00 00
  1a:   c7 05 04 00 1f 00 23    movl   $0x123,0x1f0004
  21:   01 00 00
  24:   a1 04 00 1f 00          mov    0x1f0004,%eax
  29:   03 05 00 00 1f 00       add    0x1f0000,%eax
  2f:   a3 00 00 ff 00          mov    %eax,0xff0000
  34:   c9                      leave
  35:   c3                      ret

使用 objdump -s test.section.elf 观察elf文件中所有内容可以看到:

test.section.elf:     file format elf32-i386

Contents of section .text:
 0000 5589e583 ec0883e4 f0b80000 000029c4  U.............).
 0010 c7050000 1f005604 0000c705 04001f00  ......V.........
 0020 23010000 a104001f 00030500 001f00a3  #...............
 0030 0000ff00 c9c3                        ......
Contents of section LOCALmem:
 1f0000 00000000 00000000                    ........
Contents of section GLOBALmem:
 ff0000 00000000                             ....
Contents of section .data:
Contents of section .comment:
 0000 00474343 3a202847 4e552920 332e322e  .GCC: (GNU) 3.2.
 0010 32203230 30333032 32322028 52656420  2 20030222 (Red
 0020 48617420 4c696e75 7820332e 322e322d  Hat Linux 3.2.2-
 0030 352900                               5).

Section LOCALmem从0x1f0000开始, 而Section GLOBALmem从0xff0000开始
程序正文段.text从0地址开始

如果将section.script中对于.text部分的内容去掉,那么ld产生的elf文件中.text部分
将紧接在GLOBALmem部分之后,从0xff0004开始


阅读(1595) | 评论(0) | 转发(0) |
0

上一篇:AT&T语法

下一篇:ubuntu chkconfig

给主人留下些什么吧!~~