CSAPP基本版第七章学习日志(三):关于main.c和sum.c在ubantu上的链接过程

之前初步介绍了链接,在这里将会用实例作进一步解释。
main.c代码内容:

/* main.c */
/* $begin main */
int sum(int *a, int n);

int array[2] = {1, 2};

int main() 
{
    int val = sum(array, 2);
    return val;
}
/* $end main */

sum.c代码内容:

/* sum.c */
/* $begin sum */
int sum(int *a, int n)
{
    int i, s = 0;
    
    for (i = 0; i < n; i++) { 
        s += a[i];
    }
    return s;
}        
/* $end sum */

注:这是一个小的运行示例,可以帮助说明链接是如何工作的一些重要知识点
通过读代码,可以知道sum.c文件定义了一个函数sum,功能是实现数组值的相加,而main.c文件定义了一个sum函数,一个全局变量array数组和一个主函数main。在主函数main里引用了sum函数,但是,该.c文件并未对sum函数的内容进行定义。这导致如果单独编译驱动main.c文件时前三个阶段可以顺利进行而因缺少链接无法生成可执行目标文件。因此我们先通过在命令行输入gcc -c main.c sum.c得到这两个模块的可重定位目标文件(main.o和sum.o)然后逐步分析其过程。
gcc -Wall -Og -o prog main.o sum.o
在生成可重定位目标文件后,进行此操作即可得可执行目标文件,这里命名为prog。
其中,

  • -Wall表示允许发出gcc提供的所有有用的报警信息
  • -Og表示启用全局优化
  • -o表示设定输出文件名,不加此选项会默认可执行文件名为a.out

注意此处要加上两个可重定位目标文件才能链接成功生成可执行目标文件。
gcc -Wall -Og -S main.c

  • -S表示只对文件进行预处理和编译两个阶段,在这里是让main.c文件形成对应main.s文件,里面是相应的汇编代码,可以用文本编辑器查看

知识补充:目标文件格式

  • 目标代码:指编译器和汇编器处理源代码后所生成的机器语言目标代码,即.o文件里的代码
  • 目标文件:指包含目标代码的文件,即.o文件

标准的目标文件格式有:

  • 在Windows上:PE格式,称为可移植可执行(Portable Executable,简称PE)
  • 在Linux等类UNIX上:ELF格式,称为可执行可链接(Executable and Linkable Format,简称ELF)

下面主要介绍ELF格式。
典型的ELF可重定位目标文件

来源:网课-计算机系统基础(一):程序的表示、转换与链接(第十周)

  • ELF头:包括16字节标识信息、文件类型(.o,exec,.so)、机器类型(如IA-32)、节头表的偏移、节头表的表项大小以及表项个数并且有指向节头表的指针。
  • .text:已编译程序的机器代码,即编译后的代码部分。
  • .rodata:只读数据,如printf语句中的格式串和switch跳转表等。
  • .data:已初始化的全局变量和静态C变量。注意局部C变量在运行时被保存在栈中,既不出现在.data节中,也不出现在.bss节中。
  • .bss:未初始化的全局变量和静态C变量,以及所有被初始化为0的全局或静态变量。在目标文件中仅是占位符,不占据任何实际磁盘空间。区分初始化和非初始化是为了空间效率。并且它仅在节头表里表示长度。
  • .symtab:一个符号表,它存放在程序中定义和引用的函数和全局变量的信息,它不包括局部变量。
  • .rel.text:一个.text节中位置的列表,有.text节的重定位信息。当链接器把这个目标文件和其他文件组合时,需重新修改代码段的指令中的地址信息。
  • .rel.data:被模块引用或定义的所有全局变量的重定位信息,即.data节的重定位信息。
  • .debug:一个调试用符号表(gcc -g)。
  • .line:原始C源程序中的行号和.text节中机器指令之间的映射。当用-g选项调用编译器驱动程序时,才会得到这张表。
  • .strtab:一个字符串表,包含symtab和debug节中符号(是变量名或函数名的字符串)及节名。
  • 节头表:每个节的节名、偏移和大小。

objdump -dx main.o
objdump是gcc的工具,可以查看编译后文件的组成。

  • -d表示将代码段反汇编
  • -x显示所有可用的头信息,包括符号表、重定位入口,使用此选项可以将文件内容做标注,方便我们查看理解

以下是在机器终端上运行的结果:

main.o:     文件格式 elf64-x86-64
main.o
体系结构:i386:x86-64, 标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000

节:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000021  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
  1 .data         00000008  0000000000000000  0000000000000000  00000068  2**3
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  00000070  2**0
                  ALLOC
  3 .comment      0000002b  0000000000000000  0000000000000000  00000070  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  0000000000000000  0000000000000000  0000009b  2**0
                  CONTENTS, READONLY
  5 .eh_frame     00000038  0000000000000000  0000000000000000  000000a0  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 main.c
0000000000000000 l    d  .text	0000000000000000 .text
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 l    d  .bss	0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack	0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame	0000000000000000 .eh_frame
0000000000000000 l    d  .comment	0000000000000000 .comment
0000000000000000 g     O .data	0000000000000008 array
0000000000000000 g     F .text	0000000000000021 main
0000000000000000         *UND*	0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000         *UND*	0000000000000000 sum



Disassembly of section .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 83 ec 10          	sub    $0x10,%rsp
   8:	be 02 00 00 00       	mov    $0x2,%esi
   d:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # 14 <main+0x14>
			10: R_X86_64_PC32	array-0x4
  14:	e8 00 00 00 00       	callq  19 <main+0x19>
			15: R_X86_64_PLT32	sum-0x4
  19:	89 45 fc             	mov    %eax,-0x4(%rbp)
  1c:	8b 45 fc             	mov    -0x4(%rbp),%eax
  1f:	c9                   	leaveq 
  20:	c3                   	retq   

由反汇编信息可知,开头标注了该结果是在x86-64机器上跑出来的结果,并且由于这是一个可重定位目标文件而非可执行目标文件,因此起始地址并不是明确值而是0。再看节部分,大部分节名都有对应,其中File off指明了每个节在ELF结构中的偏移地址(不是实际地址),Size指明了每个节所占大小,例.data节地址00000068加上长度00000008(均为十六进制数)正好为00000070,即.bss节的地址(注:.text节和.data节之间有空余所以.data节地址不为.text节地址加.text节长)
再下面SYMBOL TABLE显示了符号表,可以看到它存放了赋初值的全局变量array和函数main的信息
最后显示了main.o的汇编代码,注意

  14:	e8 00 00 00 00       	callq  19 <main+0x19>
			15: R_X86_64_PLT32	sum-0x4

是对函数sum的调用,由于函数sum未定义,因此调用指令call(即汇编的e8)后的数为0,并记录了PC(该条指令下一条指令地址)为0x19
objdump -dx -j .data main.o

  • -j name显示指定名称为name的section的信息。

这里即在main.o的反汇编里仅显示.data节信息

main.o:     文件格式 elf64-x86-64
main.o
体系结构:i386:x86-64, 标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000

节:
Idx Name          Size      VMA               LMA               File off  Algn
  1 .data         00000008  0000000000000000  0000000000000000  00000068  2**3
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 g     O .data	0000000000000008 array



Disassembly of section .data:

0000000000000000 <array>:
   0:	01 00 00 00 02 00 00 00                             ........

运用该指令我们可以只看到.data节的相关信息,注意最后反汇编.data节里存放的全局变量array,由于它已被初始化,且机器为小端模式,因此0000000000000000<array>: 0: 01 00 00 00 02 00 00 00 ........
01 00 00 00 02 00 00 00即为初始化的两个数1,2。
readelf -s main.o
readelf程序是一个查看目标文件内容的很方便的工具,其中

  • -s显示符号表段中的项。

因此我们可以看到main.o文件的符号表中信息:

Symbol table '.symtab' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS main.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     8: 0000000000000000     8 OBJECT  GLOBAL DEFAULT    3 array
     9: 0000000000000000    33 FUNC    GLOBAL DEFAULT    1 main
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
    11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND sum

  1. 其中Value表符号的地址,由于是可重定位目标文件,因此符号表显示它们的地址为0。
  2. Size为目标的大小,可以看到已被定义的符号array和main有大小,未链接所以不清楚内容的sum符号大小为0。
  3. Type表示类型,例FUNC是函数,OBJECT是数组数据,NOTYPE为无类型。
  4. Bind表示符号是本地的还是全局的。array、main和sum都是全局符号。GLOBAL 即该符号对外部文件的可见,LOCAL 即该符号只在这个文件中可见
  5. Vis表示符号可以是默认的、受保护的、隐藏的或内部的。
  6. Ndx为索引,对应objdump -dx main.o所展示的Idx来说明是哪个节,UND表示未知。
  7. Name为变量名称。

可以看到在8,9,11三个条目中
8:全局符号array是位于.data节中偏移量为0的8字节目标,因为数组中有两个int型元素所以占8B。
9:全局符号main是位于.text节偏移量为0的33字节函数。
11:全局符号sum是未定义的符号,它在其它模块定义,且未链接,所以不知道它的信息。
objdump -dx sum.o
与上面的objdump -dx main.o同理,这里是看sum.o的头信息

sum.o:     文件格式 elf64-x86-64
sum.o
体系结构:i386:x86-64, 标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000

节:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00000045  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  0000000000000000  0000000000000000  00000085  2**0
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00000000  0000000000000000  0000000000000000  00000085  2**0
                  ALLOC
  3 .comment      0000002b  0000000000000000  0000000000000000  00000085  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  0000000000000000  0000000000000000  000000b0  2**0
                  CONTENTS, READONLY
  5 .eh_frame     00000038  0000000000000000  0000000000000000  000000b0  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 sum.c
0000000000000000 l    d  .text	0000000000000000 .text
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 l    d  .bss	0000000000000000 .bss
0000000000000000 l    d  .note.GNU-stack	0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame	0000000000000000 .eh_frame
0000000000000000 l    d  .comment	0000000000000000 .comment
0000000000000000 g     F .text	0000000000000045 sum



Disassembly of section .text:

0000000000000000 <sum>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 89 7d e8          	mov    %rdi,-0x18(%rbp)
   8:	89 75 e4             	mov    %esi,-0x1c(%rbp)
   b:	c7 45 fc 00 00 00 00 	movl   $0x0,-0x4(%rbp)
  12:	c7 45 f8 00 00 00 00 	movl   $0x0,-0x8(%rbp)
  19:	eb 1d                	jmp    38 <sum+0x38>
  1b:	8b 45 f8             	mov    -0x8(%rbp),%eax
  1e:	48 98                	cltq   
  20:	48 8d 14 85 00 00 00 	lea    0x0(,%rax,4),%rdx
  27:	00 
  28:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  2c:	48 01 d0             	add    %rdx,%rax
  2f:	8b 00                	mov    (%rax),%eax
  31:	01 45 fc             	add    %eax,-0x4(%rbp)
  34:	83 45 f8 01          	addl   $0x1,-0x8(%rbp)
  38:	8b 45 f8             	mov    -0x8(%rbp),%eax
  3b:	3b 45 e4             	cmp    -0x1c(%rbp),%eax
  3e:	7c db                	jl     1b <sum+0x1b>
  40:	8b 45 fc             	mov    -0x4(%rbp),%eax
  43:	5d                   	pop    %rbp
  44:	c3                   	retq   

objdump -dx -j .data sum.o
看sum.o的.data节信息

sum.o:     文件格式 elf64-x86-64
sum.o
体系结构:i386:x86-64, 标志 0x00000011:
HAS_RELOC, HAS_SYMS
起始地址 0x0000000000000000

节:
Idx Name          Size      VMA               LMA               File off  Algn
  1 .data         00000000  0000000000000000  0000000000000000  00000085  2**0
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
0000000000000000 l    d  .data	0000000000000000 .data


objdump -dx prog
这里将两个模块链接后生成的可执行文件prog进行反汇编,可以看到它的变化:

prog:     文件格式 elf64-x86-64
prog
体系结构:i386:x86-64, 标志 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
起始地址 0x00000000000004f0

程序头:
    PHDR off    0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040 align 2**3
         filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r--
  INTERP off    0x0000000000000238 vaddr 0x0000000000000238 paddr 0x0000000000000238 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**21
         filesz 0x0000000000000850 memsz 0x0000000000000850 flags r-x
    LOAD off    0x0000000000000df0 vaddr 0x0000000000200df0 paddr 0x0000000000200df0 align 2**21
         filesz 0x0000000000000228 memsz 0x0000000000000230 flags rw-
 DYNAMIC off    0x0000000000000e00 vaddr 0x0000000000200e00 paddr 0x0000000000200e00 align 2**3
         filesz 0x00000000000001c0 memsz 0x00000000000001c0 flags rw-
    NOTE off    0x0000000000000254 vaddr 0x0000000000000254 paddr 0x0000000000000254 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
EH_FRAME off    0x00000000000006e4 vaddr 0x00000000000006e4 paddr 0x00000000000006e4 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x0000000000000df0 vaddr 0x0000000000200df0 paddr 0x0000000000200df0 align 2**0
         filesz 0x0000000000000210 memsz 0x0000000000000210 flags r--

动态节:
  NEEDED               libc.so.6
  INIT                 0x00000000000004b8
  FINI                 0x00000000000006d4
  INIT_ARRAY           0x0000000000200df0
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000000200df8
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000000000298
  STRTAB               0x0000000000000348
  SYMTAB               0x00000000000002b8
  STRSZ                0x000000000000007d
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000200fc0
  RELA                 0x00000000000003f8
  RELASZ               0x00000000000000c0
  RELAENT              0x0000000000000018
  FLAGS                0x0000000000000008
  FLAGS_1              0x0000000008000001
  VERNEED              0x00000000000003d8
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x00000000000003c6
  RELACOUNT            0x0000000000000003

版本引用:
  required from libc.so.6:
    0x09691a75 0x00 02 GLIBC_2.2.5

节:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .interp       0000001c  0000000000000238  0000000000000238  00000238  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  0000000000000254  0000000000000254  00000254  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  0000000000000274  0000000000000274  00000274  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.hash     0000001c  0000000000000298  0000000000000298  00000298  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .dynsym       00000090  00000000000002b8  00000000000002b8  000002b8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynstr       0000007d  0000000000000348  0000000000000348  00000348  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .gnu.version  0000000c  00000000000003c6  00000000000003c6  000003c6  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version_r 00000020  00000000000003d8  00000000000003d8  000003d8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .rela.dyn     000000c0  00000000000003f8  00000000000003f8  000003f8  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .init         00000017  00000000000004b8  00000000000004b8  000004b8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 10 .plt          00000010  00000000000004d0  00000000000004d0  000004d0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 11 .plt.got      00000008  00000000000004e0  00000000000004e0  000004e0  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .text         000001e2  00000000000004f0  00000000000004f0  000004f0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .fini         00000009  00000000000006d4  00000000000006d4  000006d4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .rodata       00000004  00000000000006e0  00000000000006e0  000006e0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 15 .eh_frame_hdr 00000044  00000000000006e4  00000000000006e4  000006e4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .eh_frame     00000128  0000000000000728  0000000000000728  00000728  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .init_array   00000008  0000000000200df0  0000000000200df0  00000df0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 18 .fini_array   00000008  0000000000200df8  0000000000200df8  00000df8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 19 .dynamic      000001c0  0000000000200e00  0000000000200e00  00000e00  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 20 .got          00000040  0000000000200fc0  0000000000200fc0  00000fc0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 21 .data         00000018  0000000000201000  0000000000201000  00001000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 22 .bss          00000008  0000000000201018  0000000000201018  00001018  2**0
                  ALLOC
 23 .comment      00000055  0000000000000000  0000000000000000  00001018  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
0000000000000238 l    d  .interp	0000000000000000              .interp
0000000000000254 l    d  .note.ABI-tag	0000000000000000              .note.ABI-tag
0000000000000274 l    d  .note.gnu.build-id	0000000000000000              .note.gnu.build-id
0000000000000298 l    d  .gnu.hash	0000000000000000              .gnu.hash
00000000000002b8 l    d  .dynsym	0000000000000000              .dynsym
0000000000000348 l    d  .dynstr	0000000000000000              .dynstr
00000000000003c6 l    d  .gnu.version	0000000000000000              .gnu.version
00000000000003d8 l    d  .gnu.version_r	0000000000000000              .gnu.version_r
00000000000003f8 l    d  .rela.dyn	0000000000000000              .rela.dyn
00000000000004b8 l    d  .init	0000000000000000              .init
00000000000004d0 l    d  .plt	0000000000000000              .plt
00000000000004e0 l    d  .plt.got	0000000000000000              .plt.got
00000000000004f0 l    d  .text	0000000000000000              .text
00000000000006d4 l    d  .fini	0000000000000000              .fini
00000000000006e0 l    d  .rodata	0000000000000000              .rodata
00000000000006e4 l    d  .eh_frame_hdr	0000000000000000              .eh_frame_hdr
0000000000000728 l    d  .eh_frame	0000000000000000              .eh_frame
0000000000200df0 l    d  .init_array	0000000000000000              .init_array
0000000000200df8 l    d  .fini_array	0000000000000000              .fini_array
0000000000200e00 l    d  .dynamic	0000000000000000              .dynamic
0000000000200fc0 l    d  .got	0000000000000000              .got
0000000000201000 l    d  .data	0000000000000000              .data
0000000000201018 l    d  .bss	0000000000000000              .bss
0000000000000000 l    d  .comment	0000000000000000              .comment
0000000000000000 l    df *ABS*	0000000000000000              crtstuff.c
0000000000000520 l     F .text	0000000000000000              deregister_tm_clones
0000000000000560 l     F .text	0000000000000000              register_tm_clones
00000000000005b0 l     F .text	0000000000000000              __do_global_dtors_aux
0000000000201018 l     O .bss	0000000000000001              completed.7697
0000000000200df8 l     O .fini_array	0000000000000000              __do_global_dtors_aux_fini_array_entry
00000000000005f0 l     F .text	0000000000000000              frame_dummy
0000000000200df0 l     O .init_array	0000000000000000              __frame_dummy_init_array_entry
0000000000000000 l    df *ABS*	0000000000000000              main.c
0000000000000000 l    df *ABS*	0000000000000000              sum.c
0000000000000000 l    df *ABS*	0000000000000000              crtstuff.c
000000000000084c l     O .eh_frame	0000000000000000              __FRAME_END__
0000000000000000 l    df *ABS*	0000000000000000              
0000000000200df8 l       .init_array	0000000000000000              __init_array_end
0000000000200e00 l     O .dynamic	0000000000000000              _DYNAMIC
0000000000200df0 l       .init_array	0000000000000000              __init_array_start
00000000000006e4 l       .eh_frame_hdr	0000000000000000              __GNU_EH_FRAME_HDR
0000000000200fc0 l     O .got	0000000000000000              _GLOBAL_OFFSET_TABLE_
00000000000006d0 g     F .text	0000000000000002              __libc_csu_fini
0000000000000000  w      *UND*	0000000000000000              _ITM_deregisterTMCloneTable
0000000000201000  w      .data	0000000000000000              data_start
0000000000201010 g     O .data	0000000000000008              array
0000000000201018 g       .data	0000000000000000              _edata
00000000000006d4 g     F .fini	0000000000000000              _fini
0000000000000000       F *UND*	0000000000000000              __libc_start_main@@GLIBC_2.2.5
0000000000201000 g       .data	0000000000000000              __data_start
0000000000000000  w      *UND*	0000000000000000              __gmon_start__
0000000000201008 g     O .data	0000000000000000              .hidden __dso_handle
000000000000061b g     F .text	0000000000000045              sum
00000000000006e0 g     O .rodata	0000000000000004              _IO_stdin_used
0000000000000660 g     F .text	0000000000000065              __libc_csu_init
0000000000201020 g       .bss	0000000000000000              _end
00000000000004f0 g     F .text	000000000000002b              _start
0000000000201018 g       .bss	0000000000000000              __bss_start
00000000000005fa g     F .text	0000000000000021              main
0000000000201018 g     O .data	0000000000000000              .hidden __TMC_END__
0000000000000000  w      *UND*	0000000000000000              _ITM_registerTMCloneTable
0000000000000000  w    F *UND*	0000000000000000              __cxa_finalize@@GLIBC_2.2.5
00000000000004b8 g     F .init	0000000000000000              _init



Disassembly of section .init:

00000000000004b8 <_init>:
 4b8:	48 83 ec 08          	sub    $0x8,%rsp
 4bc:	48 8b 05 25 0b 20 00 	mov    0x200b25(%rip),%rax        # 200fe8 <__gmon_start__>
 4c3:	48 85 c0             	test   %rax,%rax
 4c6:	74 02                	je     4ca <_init+0x12>
 4c8:	ff d0                	callq  *%rax
 4ca:	48 83 c4 08          	add    $0x8,%rsp
 4ce:	c3                   	retq   

Disassembly of section .plt:

00000000000004d0 <.plt>:
 4d0:	ff 35 f2 0a 20 00    	pushq  0x200af2(%rip)        # 200fc8 <_GLOBAL_OFFSET_TABLE_+0x8>
 4d6:	ff 25 f4 0a 20 00    	jmpq   *0x200af4(%rip)        # 200fd0 <_GLOBAL_OFFSET_TABLE_+0x10>
 4dc:	0f 1f 40 00          	nopl   0x0(%rax)

Disassembly of section .plt.got:

00000000000004e0 <__cxa_finalize@plt>:
 4e0:	ff 25 12 0b 20 00    	jmpq   *0x200b12(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 4e6:	66 90                	xchg   %ax,%ax

Disassembly of section .text:

00000000000004f0 <_start>:
 4f0:	31 ed                	xor    %ebp,%ebp
 4f2:	49 89 d1             	mov    %rdx,%r9
 4f5:	5e                   	pop    %rsi
 4f6:	48 89 e2             	mov    %rsp,%rdx
 4f9:	48 83 e4 f0          	and    $0xfffffffffffffff0,%rsp
 4fd:	50                   	push   %rax
 4fe:	54                   	push   %rsp
 4ff:	4c 8d 05 ca 01 00 00 	lea    0x1ca(%rip),%r8        # 6d0 <__libc_csu_fini>
 506:	48 8d 0d 53 01 00 00 	lea    0x153(%rip),%rcx        # 660 <__libc_csu_init>
 50d:	48 8d 3d e6 00 00 00 	lea    0xe6(%rip),%rdi        # 5fa <main>
 514:	ff 15 c6 0a 20 00    	callq  *0x200ac6(%rip)        # 200fe0 <__libc_start_main@GLIBC_2.2.5>
 51a:	f4                   	hlt    
 51b:	0f 1f 44 00 00       	nopl   0x0(%rax,%rax,1)

0000000000000520 <deregister_tm_clones>:
 520:	48 8d 3d f1 0a 20 00 	lea    0x200af1(%rip),%rdi        # 201018 <__TMC_END__>
 527:	55                   	push   %rbp
 528:	48 8d 05 e9 0a 20 00 	lea    0x200ae9(%rip),%rax        # 201018 <__TMC_END__>
 52f:	48 39 f8             	cmp    %rdi,%rax
 532:	48 89 e5             	mov    %rsp,%rbp
 535:	74 19                	je     550 <deregister_tm_clones+0x30>
 537:	48 8b 05 9a 0a 20 00 	mov    0x200a9a(%rip),%rax        # 200fd8 <_ITM_deregisterTMCloneTable>
 53e:	48 85 c0             	test   %rax,%rax
 541:	74 0d                	je     550 <deregister_tm_clones+0x30>
 543:	5d                   	pop    %rbp
 544:	ff e0                	jmpq   *%rax
 546:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
 54d:	00 00 00 
 550:	5d                   	pop    %rbp
 551:	c3                   	retq   
 552:	0f 1f 40 00          	nopl   0x0(%rax)
 556:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
 55d:	00 00 00 

0000000000000560 <register_tm_clones>:
 560:	48 8d 3d b1 0a 20 00 	lea    0x200ab1(%rip),%rdi        # 201018 <__TMC_END__>
 567:	48 8d 35 aa 0a 20 00 	lea    0x200aaa(%rip),%rsi        # 201018 <__TMC_END__>
 56e:	55                   	push   %rbp
 56f:	48 29 fe             	sub    %rdi,%rsi
 572:	48 89 e5             	mov    %rsp,%rbp
 575:	48 c1 fe 03          	sar    $0x3,%rsi
 579:	48 89 f0             	mov    %rsi,%rax
 57c:	48 c1 e8 3f          	shr    $0x3f,%rax
 580:	48 01 c6             	add    %rax,%rsi
 583:	48 d1 fe             	sar    %rsi
 586:	74 18                	je     5a0 <register_tm_clones+0x40>
 588:	48 8b 05 61 0a 20 00 	mov    0x200a61(%rip),%rax        # 200ff0 <_ITM_registerTMCloneTable>
 58f:	48 85 c0             	test   %rax,%rax
 592:	74 0c                	je     5a0 <register_tm_clones+0x40>
 594:	5d                   	pop    %rbp
 595:	ff e0                	jmpq   *%rax
 597:	66 0f 1f 84 00 00 00 	nopw   0x0(%rax,%rax,1)
 59e:	00 00 
 5a0:	5d                   	pop    %rbp
 5a1:	c3                   	retq   
 5a2:	0f 1f 40 00          	nopl   0x0(%rax)
 5a6:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
 5ad:	00 00 00 

00000000000005b0 <__do_global_dtors_aux>:
 5b0:	80 3d 61 0a 20 00 00 	cmpb   $0x0,0x200a61(%rip)        # 201018 <__TMC_END__>
 5b7:	75 2f                	jne    5e8 <__do_global_dtors_aux+0x38>
 5b9:	48 83 3d 37 0a 20 00 	cmpq   $0x0,0x200a37(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 5c0:	00 
 5c1:	55                   	push   %rbp
 5c2:	48 89 e5             	mov    %rsp,%rbp
 5c5:	74 0c                	je     5d3 <__do_global_dtors_aux+0x23>
 5c7:	48 8b 3d 3a 0a 20 00 	mov    0x200a3a(%rip),%rdi        # 201008 <__dso_handle>
 5ce:	e8 0d ff ff ff       	callq  4e0 <__cxa_finalize@plt>
 5d3:	e8 48 ff ff ff       	callq  520 <deregister_tm_clones>
 5d8:	c6 05 39 0a 20 00 01 	movb   $0x1,0x200a39(%rip)        # 201018 <__TMC_END__>
 5df:	5d                   	pop    %rbp
 5e0:	c3                   	retq   
 5e1:	0f 1f 80 00 00 00 00 	nopl   0x0(%rax)
 5e8:	f3 c3                	repz retq 
 5ea:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)

00000000000005f0 <frame_dummy>:
 5f0:	55                   	push   %rbp
 5f1:	48 89 e5             	mov    %rsp,%rbp
 5f4:	5d                   	pop    %rbp
 5f5:	e9 66 ff ff ff       	jmpq   560 <register_tm_clones>

00000000000005fa <main>:
 5fa:	55                   	push   %rbp
 5fb:	48 89 e5             	mov    %rsp,%rbp
 5fe:	48 83 ec 10          	sub    $0x10,%rsp
 602:	be 02 00 00 00       	mov    $0x2,%esi
 607:	48 8d 3d 02 0a 20 00 	lea    0x200a02(%rip),%rdi        # 201010 <array>
 60e:	e8 08 00 00 00       	callq  61b <sum>
 613:	89 45 fc             	mov    %eax,-0x4(%rbp)
 616:	8b 45 fc             	mov    -0x4(%rbp),%eax
 619:	c9                   	leaveq 
 61a:	c3                   	retq   

000000000000061b <sum>:
 61b:	55                   	push   %rbp
 61c:	48 89 e5             	mov    %rsp,%rbp
 61f:	48 89 7d e8          	mov    %rdi,-0x18(%rbp)
 623:	89 75 e4             	mov    %esi,-0x1c(%rbp)
 626:	c7 45 fc 00 00 00 00 	movl   $0x0,-0x4(%rbp)
 62d:	c7 45 f8 00 00 00 00 	movl   $0x0,-0x8(%rbp)
 634:	eb 1d                	jmp    653 <sum+0x38>
 636:	8b 45 f8             	mov    -0x8(%rbp),%eax
 639:	48 98                	cltq   
 63b:	48 8d 14 85 00 00 00 	lea    0x0(,%rax,4),%rdx
 642:	00 
 643:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
 647:	48 01 d0             	add    %rdx,%rax
 64a:	8b 00                	mov    (%rax),%eax
 64c:	01 45 fc             	add    %eax,-0x4(%rbp)
 64f:	83 45 f8 01          	addl   $0x1,-0x8(%rbp)
 653:	8b 45 f8             	mov    -0x8(%rbp),%eax
 656:	3b 45 e4             	cmp    -0x1c(%rbp),%eax
 659:	7c db                	jl     636 <sum+0x1b>
 65b:	8b 45 fc             	mov    -0x4(%rbp),%eax
 65e:	5d                   	pop    %rbp
 65f:	c3                   	retq   

0000000000000660 <__libc_csu_init>:
 660:	41 57                	push   %r15
 662:	41 56                	push   %r14
 664:	49 89 d7             	mov    %rdx,%r15
 667:	41 55                	push   %r13
 669:	41 54                	push   %r12
 66b:	4c 8d 25 7e 07 20 00 	lea    0x20077e(%rip),%r12        # 200df0 <__frame_dummy_init_array_entry>
 672:	55                   	push   %rbp
 673:	48 8d 2d 7e 07 20 00 	lea    0x20077e(%rip),%rbp        # 200df8 <__init_array_end>
 67a:	53                   	push   %rbx
 67b:	41 89 fd             	mov    %edi,%r13d
 67e:	49 89 f6             	mov    %rsi,%r14
 681:	4c 29 e5             	sub    %r12,%rbp
 684:	48 83 ec 08          	sub    $0x8,%rsp
 688:	48 c1 fd 03          	sar    $0x3,%rbp
 68c:	e8 27 fe ff ff       	callq  4b8 <_init>
 691:	48 85 ed             	test   %rbp,%rbp
 694:	74 20                	je     6b6 <__libc_csu_init+0x56>
 696:	31 db                	xor    %ebx,%ebx
 698:	0f 1f 84 00 00 00 00 	nopl   0x0(%rax,%rax,1)
 69f:	00 
 6a0:	4c 89 fa             	mov    %r15,%rdx
 6a3:	4c 89 f6             	mov    %r14,%rsi
 6a6:	44 89 ef             	mov    %r13d,%edi
 6a9:	41 ff 14 dc          	callq  *(%r12,%rbx,8)
 6ad:	48 83 c3 01          	add    $0x1,%rbx
 6b1:	48 39 dd             	cmp    %rbx,%rbp
 6b4:	75 ea                	jne    6a0 <__libc_csu_init+0x40>
 6b6:	48 83 c4 08          	add    $0x8,%rsp
 6ba:	5b                   	pop    %rbx
 6bb:	5d                   	pop    %rbp
 6bc:	41 5c                	pop    %r12
 6be:	41 5d                	pop    %r13
 6c0:	41 5e                	pop    %r14
 6c2:	41 5f                	pop    %r15
 6c4:	c3                   	retq   
 6c5:	90                   	nop
 6c6:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
 6cd:	00 00 00 

00000000000006d0 <__libc_csu_fini>:
 6d0:	f3 c3                	repz retq 

Disassembly of section .fini:

00000000000006d4 <_fini>:
 6d4:	48 83 ec 08          	sub    $0x8,%rsp
 6d8:	48 83 c4 08          	add    $0x8,%rsp
 6dc:	c3                   	retq   

可执行目标文件与可重定位目标文件稍有不同。由反汇编信息可知,开头标注了该结果是在x86-64机器上跑出来的结果,并且由于这是一个可执行目标文件,因此起始地址有明确值0x00000000000004f0。可执行目标文件多了程序头表,.init节而少了两个.rel节(因为无需重定位)。init节用于定义_init函数来进行对可执行目标文件执行时初始化工作。
在这里插入图片描述
来源:网课-计算机系统基础(一):程序的表示、转换与链接(第十周)
最后显示了prog的汇编代码,注意在00000000000005fa <main>里:

  60e:	e8 08 00 00 00       	callq  61b <sum>

是对函数sum的调用,由于函数sum已链接且机器为小端模式,因此调用指令call(即汇编的e8)后的数为08 00 00 00,并记录了跳转地址为0x61b,正好是sum函数的起始地址。其中08 00 00 00为重定位值*refptr,针对重定位时PC相对寻址绝对寻址两种方法,有如下算式:

if(r.type == R_X86_64_PC32){//PC相对寻址
	refaddr = ADDR(s) + r.offset;
	*refptr = (unsigned)(ADDR(r.symbol) + r.addend - refaddr);
}
if(r.type == R_X86_64_32){//绝对寻址
	*refptr = (unsigned)(ADDR(r.symbol) + r.addend);

其中refaddr为重定位地址;ADDR(s)ADDR(r.symbol) 为节的运行时地址(这里为.text节并且同时为main首地址,即引用函数的地址)和符号运行时地址(这里为sum函数首地址,及被引用函数的地址)ADDR(s)和ADDR(r.symbol)由可执行目标文件可知;r.offset为偏移量;*refptr为重定位值,也即偏移地址;r.addend为修正值。
在本例中,比较main的可重定位文件

14:	e8 00 00 00 00       	callq  19 <main+0x19>//19为PC值
			15: R_X86_64_PLT32	sum-0x4//15为偏移量r.offset,sum-0x4表示修正值r.addend为-4

和可执行目标文件

00000000000005fa <main>: //00000000000005fa为ADDR(s)
 5fa:	55                   	push   %rbp
 5fb:	48 89 e5             	mov    %rsp,%rbp
 5fe:	48 83 ec 10          	sub    $0x10,%rsp
 602:	be 02 00 00 00       	mov    $0x2,%esi
 607:	48 8d 3d 02 0a 20 00 	lea    0x200a02(%rip),%rdi        # 201010 <array>
 60e:	e8 08 00 00 00       	callq  61b <sum>//*refptr为8
 613:	89 45 fc             	mov    %eax,-0x4(%rbp)
 616:	8b 45 fc             	mov    -0x4(%rbp),%eax
 619:	c9                   	leaveq 
 61a:	c3                   	retq   

000000000000061b <sum>: //000000000000061b为ADDR(r.symbol)
 61b:	55                   	push   %rbp
 61c:	48 89 e5             	mov    %rsp,%rbp
 61f:	48 89 7d e8          	mov    %rdi,-0x18(%rbp)
 623:	89 75 e4             	mov    %esi,-0x1c(%rbp)
 626:	c7 45 fc 00 00 00 00 	movl   $0x0,-0x4(%rbp)
 62d:	c7 45 f8 00 00 00 00 	movl   $0x0,-0x8(%rbp)
 634:	eb 1d                	jmp    653 <sum+0x38>
 636:	8b 45 f8             	mov    -0x8(%rbp),%eax
 639:	48 98                	cltq   
 63b:	48 8d 14 85 00 00 00 	lea    0x0(,%rax,4),%rdx
 642:	00 
 643:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
 647:	48 01 d0             	add    %rdx,%rax
 64a:	8b 00                	mov    (%rax),%eax
 64c:	01 45 fc             	add    %eax,-0x4(%rbp)
 64f:	83 45 f8 01          	addl   $0x1,-0x8(%rbp)
 653:	8b 45 f8             	mov    -0x8(%rbp),%eax
 656:	3b 45 e4             	cmp    -0x1c(%rbp),%eax
 659:	7c db                	jl     636 <sum+0x1b>
 65b:	8b 45 fc             	mov    -0x4(%rbp),%eax
 65e:	5d                   	pop    %rbp
 65f:	c3                   	retq   

由以上信息,即可进行相关计算refaddr = ADDR(s) + r.offset=0x5fa+0x15=0x60f
*refptr = (unsigned)(ADDR(r.symbol) + r.addend - refaddr)=0x61b+(-4)-0x60f=8

objdump -dx -j .data prog
只看可执行目标文件的.data节内容如下

prog:     文件格式 elf64-x86-64
prog
体系结构:i386:x86-64, 标志 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
起始地址 0x00000000000004f0

程序头:
    PHDR off    0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040 align 2**3
         filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r--
  INTERP off    0x0000000000000238 vaddr 0x0000000000000238 paddr 0x0000000000000238 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**21
         filesz 0x0000000000000850 memsz 0x0000000000000850 flags r-x
    LOAD off    0x0000000000000df0 vaddr 0x0000000000200df0 paddr 0x0000000000200df0 align 2**21
         filesz 0x0000000000000228 memsz 0x0000000000000230 flags rw-
 DYNAMIC off    0x0000000000000e00 vaddr 0x0000000000200e00 paddr 0x0000000000200e00 align 2**3
         filesz 0x00000000000001c0 memsz 0x00000000000001c0 flags rw-
    NOTE off    0x0000000000000254 vaddr 0x0000000000000254 paddr 0x0000000000000254 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
EH_FRAME off    0x00000000000006e4 vaddr 0x00000000000006e4 paddr 0x00000000000006e4 align 2**2
         filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
   RELRO off    0x0000000000000df0 vaddr 0x0000000000200df0 paddr 0x0000000000200df0 align 2**0
         filesz 0x0000000000000210 memsz 0x0000000000000210 flags r--

动态节:
  NEEDED               libc.so.6
  INIT                 0x00000000000004b8
  FINI                 0x00000000000006d4
  INIT_ARRAY           0x0000000000200df0
  INIT_ARRAYSZ         0x0000000000000008
  FINI_ARRAY           0x0000000000200df8
  FINI_ARRAYSZ         0x0000000000000008
  GNU_HASH             0x0000000000000298
  STRTAB               0x0000000000000348
  SYMTAB               0x00000000000002b8
  STRSZ                0x000000000000007d
  SYMENT               0x0000000000000018
  DEBUG                0x0000000000000000
  PLTGOT               0x0000000000200fc0
  RELA                 0x00000000000003f8
  RELASZ               0x00000000000000c0
  RELAENT              0x0000000000000018
  FLAGS                0x0000000000000008
  FLAGS_1              0x0000000008000001
  VERNEED              0x00000000000003d8
  VERNEEDNUM           0x0000000000000001
  VERSYM               0x00000000000003c6
  RELACOUNT            0x0000000000000003

版本引用:
  required from libc.so.6:
    0x09691a75 0x00 02 GLIBC_2.2.5

节:
Idx Name          Size      VMA               LMA               File off  Algn
 21 .data         00000018  0000000000201000  0000000000201000  00001000  2**3
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
0000000000201000 l    d  .data	0000000000000000              .data
0000000000201000  w      .data	0000000000000000              data_start
0000000000201010 g     O .data	0000000000000008              array
0000000000201018 g       .data	0000000000000000              _edata
0000000000201000 g       .data	0000000000000000              __data_start
0000000000201008 g     O .data	0000000000000000              .hidden __dso_handle
0000000000201018 g     O .data	0000000000000000              .hidden __TMC_END__



Disassembly of section .data:

0000000000201000 <__data_start>:
	...

0000000000201008 <__dso_handle>:
  201008:	08 10 20 00 00 00 00 00                             .. .....

0000000000201010 <array>:
  201010:	01 00 00 00 02 00 00 00                             ........


经过上述操作,可以看到链接操作对多个可重定位目标文件进行了符号解析和重定位这两步操作,连接器解析符号引用的方法是将每个符号引用与它输入的可重定位目标文件的符号表中的一个确定的符号定义关联起来;而重定位将代码合并输入模块,并为每个符号分配运行时地址。经由这两步操作,一个可执行目标文件就形成了。这便是链接的全过程。
更多详细信息参考:网课-计算机系统基础(一):程序的表示、转换与链接(第十周)
书籍:深入理解计算机系统(CSAPP)第七章链接

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值