第十周链接概述和目标文件格式

在线阅读PDF文档

第1讲 可执行文件生成概述

可执行文件生成过程概述(21分钟)

链接器的由来(17分钟)

注意:静态链接需要包含所调用函数的代码,而动态链接不需要。

第2讲 目标文件格式概述

链接过程的本质(14分钟)


guangwudi@debian:~/csapp$ vim main.c
guangwudi@debian:~/csapp$ vim swap.c
guangwudi@debian:~/csapp$ gcc -O2 -g -o p main.c swap.c
guangwudi@debian:~/csapp$ ./p

目标文件的两种视图(16分钟)

第3讲 ELF可重定位目标文件

可重定位文件概述(10分钟)

ELF头和节头表(26分钟)

Usage: readelf <option(s)> elf-file(s)
 Display information about the contents of ELF format files
 Options are:
  -a --all               Equivalent to: -h -l -S -s -r -d -V -A -I
  -h --file-header       Display the ELF file header
  -l --program-headers   Display the program headers
     --segments          An alias for --program-headers
  -S --section-headers   Display the sections' header
     --sections          An alias for --section-headers
  -g --section-groups    Display the section groups
  -t --section-details   Display the section details
  -e --headers           Equivalent to: -h -l -S
  -s --syms              Display the symbol table
     --symbols           An alias for --syms
     --dyn-syms          Display the dynamic symbol table
     --lto-syms          Display LTO symbol tables
     --sym-base=[0|8|10|16]
                         Force base for symbol sizes.  The options are
                         mixed (the default), octal, decimal, hexadecimal.
  -C --demangle[=STYLE]  Decode mangled/processed symbol names
                           STYLE can be "none", "auto", "gnu-v3", "java",
                           "gnat", "dlang", "rust"
     --no-demangle       Do not demangle low-level symbol names.  (default)
     --recurse-limit     Enable a demangling recursion limit.  (default)
     --no-recurse-limit  Disable a demangling recursion limit
     -U[dlexhi] --unicode=[default|locale|escape|hex|highlight|invalid]
                         Display unicode characters as determined by the current locale
                          (default), escape sequences, "<hex sequences>", highlighted
                          escape sequences, or treat them as invalid and display as
                          "{hex sequences}"
  -n --notes             Display the core notes (if present)
  -r --relocs            Display the relocations (if present)
  -u --unwind            Display the unwind info (if present)
  -d --dynamic           Display the dynamic section (if present)
  -V --version-info      Display the version sections (if present)
  -A --arch-specific     Display architecture specific information (if any)
  -c --archive-index     Display the symbol/file index in an archive
  -D --use-dynamic       Use the dynamic section info when displaying symbols
  -L --lint|--enable-checks
                         Display warning messages for possible problems
  -x --hex-dump=<number|name>
                         Dump the contents of section <number|name> as bytes
  -p --string-dump=<number|name>
                         Dump the contents of section <number|name> as strings
  -R --relocated-dump=<number|name>
                         Dump the relocated contents of section <number|name>
  -z --decompress        Decompress section before dumping it
  -w --debug-dump[a/=abbrev, A/=addr, r/=aranges, c/=cu_index, L/=decodedline,
                  f/=frames, F/=frames-interp, g/=gdb_index, i/=info, o/=loc,
                  m/=macro, p/=pubnames, t/=pubtypes, R/=Ranges, l/=rawline,
                  s/=str, O/=str-offsets, u/=trace_abbrev, T/=trace_aranges,
                  U/=trace_info]
                         Display the contents of DWARF debug sections
  -wk --debug-dump=links Display the contents of sections that link to separate
                          debuginfo files
  -P --process-links     Display the contents of non-debug sections in separate
                          debuginfo files.  (Implies -wK)
  -wK --debug-dump=follow-links
                         Follow links to separate debug info files (default)
  -wN --debug-dump=no-follow-links
                         Do not follow links to separate debug info files
  --dwarf-depth=N        Do not display DIEs at depth N or greater
  --dwarf-start=N        Display DIEs starting at offset N
  --ctf=<number|name>    Display CTF info from section <number|name>
  --ctf-parent=<name>    Use CTF archive member <name> as the CTF parent
  --ctf-symbols=<number|name>
                         Use section <number|name> as the CTF external symtab
  --ctf-strings=<number|name>
                         Use section <number|name> as the CTF external strtab
  --sframe[=NAME]        Display SFrame info from section NAME, (default '.sframe')
  -I --histogram         Display histogram of bucket list lengths
  -W --wide              Allow output width to exceed 80 characters
  -T --silent-truncation If a symbol name is truncated, do not add [...] suffix
  @<file>                Read options from <file>
  -H --help              Display this information
  -v --version           Display the version number of readelf
#include <stdio.h>
int main()
{
	printf("guangfuzhonghua!\n");
	return 0;
}

guangwudi@debian:~/csapp$ readelf -h hello.o
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          660 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         15
  Section header string table index: 14

-S輸出節頭表

guangwudi@debian:~/csapp$ readelf -S hello.o
There are 15 section headers, starting at offset 0x294:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .group            GROUP           00000000 000034 000008 04     12   6  4
  [ 2] .text             PROGBITS        00000000 00003c 00003c 00  AX  0   0  1
  [ 3] .rel.text         REL             00000000 0001e0 000020 08   I 12   2  4
  [ 4] .data             PROGBITS        00000000 000078 000000 00  WA  0   0  1
  [ 5] .bss              NOBITS          00000000 000078 000000 00  WA  0   0  1
  [ 6] .rodata           PROGBITS        00000000 000078 000011 00   A  0   0  1
  [ 7] .text.__x86.[...] PROGBITS        00000000 000089 000004 00 AXG  0   0  1
  [ 8] .comment          PROGBITS        00000000 00008d 000020 01  MS  0   0  1
  [ 9] .note.GNU-stack   PROGBITS        00000000 0000ad 000000 00      0   0  1
  [10] .eh_frame         PROGBITS        00000000 0000b0 000060 00   A  0   0  4
  [11] .rel.eh_frame     REL             00000000 000200 000010 08   I 12  10  4
  [12] .symtab           SYMTAB          00000000 000110 000090 10     13   5  4
  [13] .strtab           STRTAB          00000000 0001a0 00003f 00      0   0  1
  [14] .shstrtab         STRTAB          00000000 000210 000082 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), p (processor specific)

-s輸出符號表

guangwudi@debian:~/csapp$ readelf -s hello.o

Symbol table '.symtab' contains 9 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    2 .text
     3: 00000000     0 SECTION LOCAL  DEFAULT    6 .rodata
     4: 00000000     0 SECTION LOCAL  DEFAULT    7 .text.__x86.get_[...]
     5: 00000000    60 FUNC    GLOBAL DEFAULT    2 main
     6: 00000000     0 FUNC    GLOBAL HIDDEN     7 __x86.get_pc_thunk.ax
     7: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
     8: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND puts

第4讲 ELF可执行目标文件

可执行文件概述(13分钟)

guangwudi@debian:~/csapp$ readelf -h hello
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x1060
  Start of program headers:          52 (bytes into file)
  Start of section headers:          13784 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         11
  Size of section headers:           40 (bytes)
  Number of section headers:         30
  Section header string table index: 29

程序头表和存储器映像(21分钟)

guangwudi@debian:~/csapp$ readelf -l hello

Elf file type is DYN (Position-Independent Executable file)
Entry point 0x1060
There are 11 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00000034 0x00000034 0x00160 0x00160 R   0x4
  INTERP         0x000194 0x00000194 0x00000194 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x00000000 0x00000000 0x003d4 0x003d4 R   0x1000
  LOAD           0x001000 0x00001000 0x00001000 0x001e0 0x001e0 R E 0x1000
  LOAD           0x002000 0x00002000 0x00002000 0x00118 0x00118 R   0x1000
  LOAD           0x002ee8 0x00003ee8 0x00003ee8 0x00128 0x0012c RW  0x1000
  DYNAMIC        0x002ef0 0x00003ef0 0x00003ef0 0x000f0 0x000f0 RW  0x4
  NOTE           0x0001a8 0x000001a8 0x000001a8 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x00201c 0x0000201c 0x0000201c 0x00034 0x00034 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x002ee8 0x00003ee8 0x00003ee8 0x00118 0x00118 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt
   03     .init .plt .plt.got .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .dynamic .got .got.plt .data .bss
   06     .dynamic
   07     .note.gnu.build-id .note.ABI-tag
   08     .eh_frame_hdr
   09
   10     .init_array .fini_array .dynamic .got

第十周小测验

1以下是有关使用GCC生成C语言程序的可执行文件的叙述,其中错误的是(D )。

A.第三步汇编,将汇编语言代码汇编转换为机器指令表示的机器语言代码

B.第四步链接,将多个模块的机器语言代码链接生成可执行目标程序文件

C.第一步预处理,对#include、#define、#ifdef等预处理命令进行处理

D.第二步编译,将预处理结果编译转换为二进制形式的汇编语言程序代码

解釋:第二步编译,将预处理结果编译转换为文本形式的汇编语言程序代码

2以下是有关使用GCC生成C语言程序的可执行文件的叙述,其中错误的是(B )。

A.预处理的结果还是一个C语言源程序文件,属于可读的文本文件

B.只要在链接命令中指定所有的相关可重定位目标文件就能生成可执行文件

C.经过预处理、编译和汇编处理的结果是一个可重定位目标文件

D.每个C语言源程序文件生成一个对应的可重定位目标文件

解释:只要……就……

3以下是有关链接所带来的好处和不足的叙述,错误的是( A )。

A.使得所生成的可执行目标代码中包含了更多公共库函数代码,所占空间大

B.使得公共函数库可以为所有程序共享使用,有利于代码重用和提高效率

C.使得程序员仅需重新编译修改过的源程序模块,从而节省程序开发时间

D.使得程序员可以分模块开发程序,有利于提高大规模程序的开发效率

解释:所生成的可执行目标代码不包含公共库函数代码

4以下关于ELF目标文件格式的叙述中,错误的是( D )。

A.可重定位和可执行两种目标文件中的代码都是二进制表示的指令形式

B.可执行目标文件是ELF格式的执行视图,由不同的段组成

C.可重定位目标文件是ELF格式的链接视图,由不同的节组成

D.可重定位和可执行两种目标文件中的数据都是二进制表示的补码形式

解释:可重定位和可执行两种目标文件中的数据都是十六进制表示的补码形式

5以下关于链接器基本功能的叙述中,错误的是( C )。

A.将每个.o文件中的.data节、.text节和.bss节合并

B.根据所定义符号的首地址对符号的引用进行重定位

C.确定每个符号(包括全局变量和局部变量)的首地址

D.将每个符号引用与唯一的一个符号定义进行关联

解释:局部变量不属于符号定义

6以下关于可重定位目标文件的叙述中,错误的是( B )。

A.在.rodata节中包含相应模块内所有只读数据

B.在.data节中包含相应模块内所有变量的初始值

C.在.rel.text节和.rel.data节中包含相应模块内所有可重定位信息

D.在.text节中包含相应模块内所有机器代码

解释:.data节只包括已初始化的全局变量或静态局部变量,不包括已初始化的非静态局部变量和未初始化的变量。

7以下关于ELF目标文件的ELF头的叙述中,错误的是( D )。

A.数据结构在可重定位和可执行两种目标文件中完全一样

B.包含了节头表和程序头表各自的起始位置和长度

C.包含了操作系统版本和机器结构类型等信息

D.包含了ELF头本身的长度和目标文件的长度

解释:不包含目标文件的长度

8以下关于ELF目标文件的节头表的叙述中,错误的是( B )。

A.通过节头表可获得节的名称、类型、起始地址和长度

B.每个表项用来记录某个节的内容以及相关描述信息

C.数据结构在可重定位和可执行两种目标文件中完全一样

D.描述了每个可装入节的起始虚拟地址、对齐和存取方式

解释:没有记录某个节的内容

9以下关于ELF可重定位和可执行两种目标文件格式比较的叙述中,错误的是( B )。

A.可执行目标文件的ELF头中有具体程序入口地址,而在可重定位目标文件中则为0

B.可重定位目标文件中有初始化程序段.init节,而在可执行目标文件中则没有

C.可执行目标文件中有程序头表(段头表),而在可重定位目标文件中则没有

D.可重定位目标文件中有可重定位节.rel.text和.rel.data,而在可执行目标文件中则没有

解释:可执行目标文件中有初始化程序段.init节,而可重定位目标文件中没有

10以下关于ELF可执行目标文件的程序头表(段头表)的叙述中,错误的是( C )。

A..text节和.rodata节都包含在只读代码段,而.data节和.bss节都包含在读写数据段

B.通过段头表可获得可装入段或特殊段的类型、在文件中的偏移位置及长度

C.用于描述可执行文件中的节与主存中的存储段之间的映射关系

D.描述了每个可装入段的起始虚拟地址、存储长度、存取方式和对齐方式

解释:ELF可执行目标文件的程序头表(段头表)用于描述可执行文件中的节与虚拟空间中的存储段之间的映射关系