摘要:一些连接脚本示例。
关键字: 连接脚本 linker script lds文件
连接脚本的详细介绍可以参考:http://sourceware.org/binutils/docs/ld/Scripts.html#Scripts,一个简单的lds文件如下所示:
1: OUTPUT_FORMAT("elf32-i386", "elf32-i386","elf32-i386")
2: OUTPUT_ARCH(i386)
3: ENTRY(_start)
4: SECTIONS
5: {
6: .text :
7: {
8: * (.text)
9: }
10:
11: .data :
12: {
13: * (.data)
14: }
15:
16: _bss_start = . ;
17: .bss :
18: {
19: * (.bss)
20: }
21: _bss_end = . ;
22: }
但是如果在PC平台,使用了标准库的话,这个lds还不够完整。
通常情况下,ld使用默认的连接脚本,这个脚本内嵌到ld文件中了。可以使用下面的命令查看:
即使一个简单的hello.c程序,如果使用gcc直接编译,也会默认的增加一起初始化和标准库的代码,所以默认的default.lds相对来说并不简单,做测试的话,建议直接在上面增加自己的代码段。
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
测试结果是__m_section_start = . ;是不占用空间的;“.= . ;” 也不占用空间,但是为什么有的lds文件中会用这句话,有什么意义?
通配符是有效果的,所以在源程序中可以使用满足通配符的段。
上面代码是我自己测试时用的,主要是测试C语言调用连接脚本中的变量,测试代码如下(hello.c):
1: #include
2:
3: extern char __m_section_init[] ;
4: extern char __m_section_start ;
5: extern char __m_section_mid ;
6: extern char* __m_section_end ;
7:
8: int var_standard = 0x1234 ;
9:
10: #define DPRINT(x) printf( #x " is 0x%x/n", (unsigned int)x)
11:
12: int var_a __attribute__((section(".my_section"))) = 1 ;
13: int var_b __attribute__((section(".my_section1"))) = 2 ;
14: int var_c __attribute__((section(".my_section.a_1"))) = 3 ;
15:
16: int main(void)
17: {
18: DPRINT(&var_standard);
19: DPRINT(__m_section_init);
20: DPRINT(&__m_section_start);
21: DPRINT(&var_a);
22: DPRINT(&var_b);
23: DPRINT(&__m_section_mid);
24: DPRINT(&var_c);
25:
26:
27:
28: return 0;
29: }
这段代码的运行结果是:
1: &var_standard is 0x80495c4
2: __m_section_init is 0x8048418
3: &__m_section_start is 0x8048418
4: &var_a is 0x8048418
5: &var_b is 0x804841c
6: &__m_section_mid is 0x8048420
7: &var_c is 0x8048420
8: &__m_section_end is 0x8048424
注意C语言中调用连接脚本的方法,特别是__m_section_end声明为了一个指针,但是实际上在这里相当于一个int类型而已,与数组名的意义并不一样,所以后面还是得使用&符号获取连接脚本里面的值。不过推荐的做法是声明为相关长度的数组,比如unsigned char或者unsigned int类型的数组。