链接脚本中定义的符号(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代码或汇编代码定义,如果连接脚本引用这个变量名,它在连接脚本里代表这个全局变量的地址,
总结:
在连接脚本里的符号(变量)一律看成地址。
本文探讨了链接脚本中定义的符号如何被C代码和汇编代码引用,重点介绍了在u-boot环境下符号的声明与使用,以及这些符号在链接过程中的角色。文章详细解释了在链接脚本中符号被视为地址的概念,以及C代码与汇编代码中引用这些符号的不同方式。
6807

被折叠的 条评论
为什么被折叠?



