liinux中lds链接脚本中定义的变量理解

本文探讨了链接脚本中定义的符号如何被C代码和汇编代码引用,重点介绍了在u-boot环境下符号的声明与使用,以及这些符号在链接过程中的角色。文章详细解释了在链接脚本中符号被视为地址的概念,以及C代码与汇编代码中引用这些符号的不同方式。

链接脚本中定义的符号(symbol)也可以认为是全局变量,在C代码和汇编代码都可以访问它。链接脚本定义的符号(变量)时代表一个地址。

下面根据u-boot中情形分两种情况讨论:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)

SECTIONS {

......

.bss __rel_dyn_start (OVERLAY) : {
  __bss_start = .;
  *(.bss*)
   . = ALIGN(4);
  __bss_end__ = .;
 }

......

}

1)符号由链接脚本声明,c代码和汇编代码只是引用该符号:

    区别: 在汇编引用链接脚本中的符号时,可以声明或不声明。

     声明:

   xxx.S中声明符号

  .globl __bss_start
  .globl __bss_end__

  注意这里没有用.word来分配变量存储空间。

  当然可以直接在汇编中引用这个符号,在start.S中定义变量:

.globl _bss_start_ofs
_bss_start_ofs:
.word __bss_start - _start

其中就直接调用__bss_start,它代表连接地址,是个绝对地址,而不是运行时地址。

而C语言则比较严格,一定要在引用之前声明该符号,常用的方式是这样:

/* Linker symbols. */
extern char __bss_start[], __bss_end__[];

把连接中的符号看成一个数组地址。当需要清零bss内存时:

/* Clear the BSS. */
memset(__bss_start, 0, __bss_end__ - __bss_start);

如果你定义成普通全局变量的话:

/* Linker symbols. */

extern char __bss_start,__bss_end__;

/* Clear the BSS. */
memset(&__bss_start, 0, &__bss_end__ - &__bss_start);

这里很容易混淆,如果按照lds定义,__bss_start和__bss_end__本身就是地址,这里再取地址有点说不过去。通过生成.map文件观察:

.bss            0x01033b2c    0x43780
                0x01033b2c                __bss_start = .                                                                @@定位器“.”这个时候也指向地址 0x01033b2c  

 *(.bss*)

.bss           0x01033b2c        0x0 arch/arm/cpu/armv7/start.o                                        @@start.o没有bss变量

 .bss           0x01033b2c        0x0 arch/arm/cpu/armv7/libarmv7.o
 .bss           0x01033b2c        0x4 arch/arm/cpu/armv7/socfpga/libsocfpga.o              @@这里分配4个字节的变量
                0x01033b2c                irq_cnt_ecc_sdram

......

.bss           0x010772ac        0x0 board/altera/socfpga/libsocfpga.o
 .bss           0x010772ac        0x0 /home/xuewt/share/new-uboot-git/20140529/u-boot-socfpga/arch/arm/lib/eabi_compat.o
 .bss           0x010772ac        0x0 /opt/altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin

                                                  /../lib/gcc/arm-linux-gnueabihf/4.7.3/libgcc.a(_udivsi3.o)
 .bss           0x010772ac        0x0 /opt/altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin

                                                 /../lib/gcc/arm-linux-gnueabihf/4.7.3/libgcc.a(_divsi3.o)
 .bss           0x010772ac        0x0 /opt/altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/

                                               ../lib/gcc/arm-linux-gnueabihf/4.7.3/libgcc.a(_lshrdi3.o)
 .bss           0x010772ac        0x0 /opt/altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/libgcc.a(_ashldi3.o)
 .bss           0x010772ac        0x0 /opt/altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/libgcc.a(_dvmd_lnx.o)

                0x010772ac                . = ALIGN (0x4)
                0x010772ac                __bss_end__ = .

从中可以看到地址 0x01033b2c 其实是变量 irq_cnt_ecc_sdram的地址,连接器在这里对地址 0x01033b2c起了个别名"__bss_start ",它是个数值常量 0x01033b2c,实际上生成的可执行文件u-boot根本就不存在这个__bss_start变量(根本没有分配空间),最最正确的理解是要用C++的引用来理解连接脚本的符号(在LD时初始化这个常量)。C代码里没有引用这个概念,数组名其实是最好的替代品,代表首地址,数组名不分配空间,它是个地址常量,是个数值比如这里的 0x01033b2c,而&0x01033b2c仍然是0x01033b2c),我们定义了array[size];数组名是array的首地址,而&array在数值上是和array的值相同,只是含义不同罢了。


这两种使用方法都会经常看到。

 

注意一个事项:u-boot的汇编代码编译时是通过GCC调用AS汇编器来编译的,允许大部分C语言的代码存在,因为汇编之前已经经过GCC预处理了,GCC是编译连接工具集合,它还可以调用连接脚本。如果用as直接汇编u-boot的.S文件,会报错。

2)全局变量由C代码或汇编代码定义,如果连接脚本引用这个变量名,它在连接脚本里代表这个全局变量的地址,

 

总结:

在连接脚本里的符号(变量)一律看成地址。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值