链接/装载/运行(4)-静态链接

静态链接就是将多个目标文件合并为一个可执行文件。
实例文件:

/* a.c */
extern int shared;
extern void swap(int *a, int *b);
int main()
{
	int a = 100;
	swap(&a, &shared);
}

/* b.c */
int shared = 1;
void swap(int *a, int *b)
{
	*a ^= *b ^= *a ^= *b;
}

编译为目标文件:

/*
 *需要加上-fno-stack-protector,否则当链接时会提示:
 *a.o: In function `main':
 *a.c:(.text+0x44): undefined reference to `__stack_chk_fail'
*/
$ gcc -c a.c b.c -fno-stack-protector		

1 空间和地址分配

“链接器为目标文件分配地址和空间” 中的 “地址和空间” 有两个含义:

1、在输出的可执行文件中的空间
2、在装载后的虚拟地址中的虚拟地址空间
对于有实际数据的段,比如 .text 和 .data 来说,在可执行文件中和虚拟地址空间中都要分配空间;对于没有实际数据的段,比如 .bss 来说,分配空间的意义只局限于虚拟地址空间,因为它在文件中并没有内容。

注意:这里谈到的空间分配只关注于虚拟地址空间的分配。

可执行文件中的代码段和数据段都是由输入的目标文件合并而来的。
对于多个输入目标文件,链接器如何将它们的各个段合并到输出文件中呢?

1.1 按序叠加

这是最简单的方法:将输入文件按次序叠加起来,也就是将多个目标文件合并为一个大目标文件。
问题:在很多输入目标文件的情况下,输入文件会有很多零散的段。这样非常浪费空间,因为每个段都有一定的空间和地址对齐要求(生成可执行文件和装载运行时)。

1.2 相似段合并

这种方法就是讲输入文件的text段合并到输入文件的text段,其他段也是这样。
现在的链接器空间分配的策略基本上都采用这种方法,是用这种方法的链接器一般都采用两步链接的方法。

  • 空间与地址分配: 扫描说有的输入目标文件,并且获得它们的各个段的长度,属性和位置,并且将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到全局符号表中。这样就能将输入目标文件中的段进行合并,计算出输出文件中各个段合并后的长度与位置,并建立映射关系。
  • **符号解析与重定位:**使用第一步中收集到的信息,读取输入文件中段的数据,重定位信息,进行符号解析与重定位,调整代码中的地址。这一步才是链接过程的核心,特别是重定位过程。
/* 
 * 将目标文件链接成可执行文件
 * -e 指定 main 函数作为程序入口,ld 链接器的默认程序入口为 _start
 * -o 指定输出的可执行文件名称,默认为 a.out
 * /
$ ld a.o b.o -e main -o ab
/*
 * 链接前后各个段的属性
 * VMA(virtual memory address):虚拟地址;LMA(load memory address):加载地址。正常情况下这两个值应该是一样的,但是对于嵌入式系统,特别是将程序放入 ROM 的系统中 LMA 和 VMA 是不相同的。
 */
$ objdump -h a.o

a.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000027  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  0000000000000000  0000000000000000  00000067  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  00000067  2**0
                  ALLOC
  3 .comment      00000036  0000000000000000  0000000000000000  00000067  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  0000000000000000  0000000000000000  0000009d  2**0
                  CONTENTS, READONLY
  5 .eh_frame     00000038  0000000000000000  0000000000000000  000000a0  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
$ objdump -h b.o

b.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000001b  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  0000000000000000  0000000000000000  0000005c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  00000060  2**0
                  ALLOC
  3 .comment      00000036  0000000000000000  0000000000000000  00000060  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  0000000000000000  0000000000000000  00000096  2**0
                  CONTENTS, READONLY
  5 .eh_frame     00000038  0000000000000000  0000000000000000  00000098  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
$ objdump -h ab

ab:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000042  00000000004000e8  00000000004000e8  000000e8  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .eh_frame     00000058  0000000000400130  0000000000400130  00000130  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00000004  0000000000600188  0000000000600188  00000188  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .comment      00000035  0000000000000000  0000000000000000  0000018c  2**0
                  CONTENTS, R
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值