四、静态链接

1.源代码(a.c b.c)

extern int shared;

int main()
{
        int a = 100;
        swap( &a, &shared );
        return 0;
}
int shared = 1;

void swap( int *a, int *b )
{
        *a = *a ^ *b;
        *b = *a ^ *b;
        *a = *a ^ *b;
}

结合$ readelf -S$ readelf -s的输出,可以获取到两个目标文件的Section信息和symbol信息等

2.空间和地址分配

目标文件a.o和b.o链接输出可执行文件ab,它们的Section是如何合并到输出文件中的?输出文件和虚拟内存中的地址和空间又是如何分配的?

  • 相似段合并
    • 空间与地址分配
      扫描所有的目标文件,获取各个Section的长度、属性和位置,收集符号表中的所有符号定义和符号引用;合并,计算出输出文件中各个段合并后的位置和长度,并建立映射关系
    • $ ld a.o b.o -e main -o ab -melf_i386
$ objdump -h a.o b.o ab

a.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         0000002c  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000000  00000000  00000000  00000060  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000060  2**2
                  ALLOC
  3 .comment      0000002b  00000000  00000000  00000060  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  0000008b  2**0
                  CONTENTS, READONLY
  5 .eh_frame     00000038  00000000  00000000  0000008c  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

b.o:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000038  00000000  00000000  00000034  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000004  00000000  00000000  0000006c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  00000000  00000000  00000070  2**2
                  ALLOC
  3 .comment      0000002b  00000000  00000000  00000070  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  00000000  00000000  0000009b  2**0
                  CONTENTS, READONLY
  5 .eh_frame     00000038  00000000  00000000  0000009c  2**2
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA

ab:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000064  08048094  08048094  00000094  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .eh_frame     00000058  080480f8  080480f8  000000f8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00000004  08049150  08049150  00000150  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .comment      0000002a  00000000  00000000  00000154  2**0
                  CONTENTS, READONLY

从合并后的文件ab可以看出,合并的各个段已经在虚拟内存中分配了地址(VMA)

  • 符号地址的确定
    • 符号解析与重定位
      使用第一步收集到的所有信息,读取输入文件中的Section的数据、重定位信息,进行符号解析与重定位、调整代码中的地址
    • 经过相似段合并过程,各个段在虚拟地址空间中的地址已经确定了,各个符号定义 的地址也已经确定了(段的虚拟地址加上符号定义的偏移量)
    • 重定位过程是针对代码中的符号引用的地址的修改
$ objdump -d a.o ab   部分结果,主要是main函数

a.o:     file format elf32-i386

Disassembly of section .text:

00000000 
: 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 83 e4 f0 and $0xfffffff0,%esp 6: 83 ec 20 sub $0x20,%esp 9: c7 44 24 1c 64 00 00 movl $0x64,0x1c(%esp) 10: 00 11: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp) 对shared变量的引用 18: 00 19: 8d 44 24 1c lea 0x1c(%esp),%eax 1d: 89 04 24 mov %eax,(%esp) 20: e8 fc ff ff ff call 21 对swap函数的调用 25: b8 00 00 00 00 mov $0x0,%eax 2a: c9 leave 2b: c3 ret ab: file format elf32-i386 Disassembly of section .text: 08048094
: 8048094: 55 push %ebp 8048095: 89 e5 mov %esp,%ebp 8048097: 83 e4 f0 and $0xfffffff0,%esp 804809a: 83 ec 20 sub $0x20,%esp 804809d: c7 44 24 1c 64 00 00 movl $0x64,0x1c(%esp) 80480a4: 00 80480a5: c7 44 24 04 50 91 04 movl $0x8049150,0x4(%esp) 对shared变量的地址引用&shared 80480ac: 08 80480ad: 8d 44 24 1c lea 0x1c(%esp),%eax 80480b1: 89 04 24 mov %eax,(%esp) 80480b4: e8 07 00 00 00 call 80480c0 对swap函数的调用 80480b9: b8 00 00 00 00 mov $0x0,%eax 80480be: c9 leave 80480bf: c3 ret

c7 44 24 是movl指令,后边的4个字节是地址,可以看到链接过程,对符号地址做了重定位修正

重定位过程的完成需要重定位表的协助,.text的重定位表是.rel.text

  • 重定位表每一个表项的结构体
typedef struct
{
 Elf32_Addr    r_offset;       /* Address */
 Elf32_Word    r_info;         /* Relocation type and symbol index */
} Elf32_Rel;

offset 代表相对于要修正的段的偏移地址,r_info 包含了重定位符号的信息(符号表的下标)

你可能感兴趣的:(四、静态链接)