嵌入式C语言自我修养06:U-boot镜像自拷贝分析:se

  

6.1 GNU C的扩展关键字:属性

  

GNU C增加一个atttribute关键字用来声明一个函数,变量或类型的特殊属性。声明这个特殊属性有什么用呢?主要用途就是指导编译器在编译程序时进行特定方面的优化或代码检查,比如,我们可以通过使用属性声明指定某个变量的数据边界对齐方式。

  

属性的使用非常简单,当我们定义一个函数,变量或类型时,直接在它们名字旁边添加下面的属性声明即可:

  
 <代码> __atttribute__((属性)) 
  

这里需要注意的是:属性后面是两对小括号,不能图方便只写一对,否则编译可能通不过。括号里面代的属性表的就是要声明的属性。现在属性支持十几种属性:

  
      <李> 节   <李> 对齐   <李> 包装   <李> 格式   <李>弱李   <李> 别名   <李> noinline李   <李> always_inline李   <李>……   
  

在这些属性中,对齐和用包装来显式指定一个变量的存储边界对齐方式。一般来讲,我们定义一个变量,编译器会根据变量类型,按照默认的规则来给这个变量分配大小,按照默认的边界对齐方式分配一个地址。而使用atttribute这个属性声明,就相当于告诉编译器:按照我们指定的边界地址对齐去给这个变量分配存储空间。

  
 <代码> char c2 __attribute__((对齐(8))=4;
  int global_val __attribute__ (((" . data "))节); 
  

有些属性可能还有自己的参数。比如对齐(8)表示这个变量按8字节地址对齐,参数也要使用小括号括起来。如果属性的参数是一个字符串,小括号里的参数还要用双引号引起来。

  

当然,我们也可以对一个变量同时添加多个属性说明。在定义时,各个属性之间用逗号隔开就可以了。

  
 <代码> char c2 __attribute__((包装、对齐(4)));
  char c2 __attribute__((包装、对齐(4)))=4;
  __attribute__((包装、对齐(4)))char c2=4;  
  

在上面的示例中,我们对一个变量添加2个属性声明,这两个属性都放在atttribute(())的2对小括号里面,属性之间用逗号隔开。这里还有一个细节,就是属性声明要紧挨着变量,上面的三种定义方式都是没有问题的,但下面的定义方式在编译的时候可能就通不过。

  
 <代码> char c2=4 __attribute__((包装、对齐(4))), 
  

6.2属性声明:部分

  

在本节教程中,我们先讲一下节这个属性。使用atttribute来声明一个部分属性,主要用途是在程序编译时,将一个函数或变量放到指定的段,即部分中。

  

在讲解这个功能之前,为了照顾一下对计算机编译,链接过程不是很了解的同学,我们先讲一讲程序的编译,链接过程。

  

程序的编译,链接过程

  

一个可执行目标文件,它主要由代码段,数据段,BSS段构成。代码段主要存放编译生成的可执行指令代码,数据段和BSS段用来存放全局变量,未初始化的全局变量。代码段,数据段和BSS段构成了一个可执行文件的主要部分。

  

除了这三个段,可执行文件中还包含其它一些段。用编译器的专业术语讲,还会包含其它一些部分,比如只读数据段,符号表等等。我们可以使用下面的readelf命令,去查看一个可执行文件中各个节的信息。

  
 <代码> gcc - o美元。出“
  readelf - s a.o ut美元
  
  这里有31节标题,从偏移0 x1848:
  节标题:
  (Nr)名称类型Addr大小
  [0]零000000 000000 00000000
  [1].interp PROGBITS 08048154 000154 000013
  [2].note。ABI-tag注意08048168 000168 000020
  [3].note.gnu。build-i注意08048188 000188 000024
  [4].gnu。哈希GNU_HASH 080481 ac 0001 ac 000020
  [5].dynsym DYNSYM 000040 cc 0001 cc 080481
  [6].dynstr STRTAB 0804820 c 0804820 c 000045
  [7].gnu。版本VERSYM 08048252 000252 000008
  [8].gnu。version_r凡尔纳0804825 c 0804825 c 000020
  [9].rel。达因REL 0804827 c 0804827 c 000008
  [10].rel。plt REL 08048284 000284 000008
  [11].init PROGBITS 0804828 c 0804828 c 000023
  [13].plt。有PROGBITS 080482 d0 0002 d0 000008
  [14]。text PROGBITS 080482 e0 0002 e0 000172
  [15].fini PROGBITS 08048454 000454 000014
  [16].rodata PROGBITS 08048468 000468 000008
  [17].eh_frame_hdr PROGBITS 08048470 000470 08048470 c
  [18].eh_frame PROGBITS 0804849 c 0804849 c 0000 c0
  [19].init_array INIT_ARRAY 08049 f08 000 f08 000004
  [20].fini_array FINI_ARRAY 08049 f0c 000 f0c 000004
  [21].jcr PROGBITS 08049 f10 000 f10 000004
  [22].dynamic动态08049 f14 000 f14 0000 e8
  [23].got PROGBITS 08049 ffc 000 ffc 000004
  [24].got。plt PROGBITS 0804 a000 001000 000010
  0804年[25]. data PROGBITS a020 001020 00004 c
  [26].bss NOBITS 0804 a06c 00106 c 000004
  [27].comment PROGBITS 00000000 000034 c 00106
  [28].shstrtab STRTAB 00000000 00173 d 00000000 a
  [29].symtab SYMTAB 00000000 0010 a0 000470
  [30].strtab STRTAB 00000000 001510 00000000 d 

嵌入式C语言自我修养06:U-boot镜像自拷贝分析:se