gcc -E 进行预处理(cl -E 是vs下编译器的预处理)
gcc -S main.c -o main.s 编译(翻译成汇编)
as hello.s -o main.o 汇编(翻译成2进制) 下面进行链接
gcc -c main.c -o main.o 也是对程序只进行编译,并不链接
gcc main.c -o main 对程序进行编译并链接
1、符号:它用来表示一个地址,这个地址可以是一段子程序(后来发展成函数的起始地址),也是一个变量的的起始地址
函数访问厅知道目标函数的地址,变量访问也要知道目标变量的地址,所以这两种方式都可以归结为一种方式,那就是模块间符号的引用
2、链接:
从原理上廛,综的工作主是把一些指令对其他符号地址的引用加以修正,链接过程主要包括了地址和空间分配、答号决议、重定位
3、对于函数与变量的调用在经过汇编之后,编译成的二进制中,如果是全局量或静态变量都是将地址暂时置为0,而地址则是0xFFFFFFFc,这些地址的修正都是
在链接时间才进行完成的,因此,在编译时,编译器只认答号,只能没有语法错误,就可以编译通过
4、查看objdump Elf文件结构
readelf -S 查看段表的结构
obj 文件段表结构:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000030 00 AX 0 0 4
[ 2] .rel.text REL 00000000 0003a0 000010 08 10 1 4
[ 3] .data PROGBITS 00000000 000064 000008 00 WA 0 0 4
[ 4] .rel.data REL 00000000 0003b0 000008 08 10 3 4
[ 5] .bss NOBITS 00000000 00006c 000000 00 WA 0 0 4
[ 6] .rodata PROGBITS 00000000 00006c 00000b 00 A 0 0 1
[ 7] .comment PROGBITS 00000000 000077 00002e 00 0 0 1
[ 8] .note.GNU-stack PROGBITS 00000000 0000a5 000000 00 0 0 1
[ 9] .shstrtab STRTAB 00000000 0000a5 000055 00 0 0 1
[10] .symtab SYMTAB 00000000 0002dc 0000b0 10 11 9 4
[11] .strtab STRTAB 00000000 00038c 000013 00 0 0 1
名字 类型 虚拟地址 文件中偏移 长度
可执行文件段表结构:(程序虚拟地址从08048000开始,用户栈从0xbFFFFFFF开始,共享对象从0x40000000开始)
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4
[ 3] .gnu.hash GNU_HASH 08048168 000168 000020 04 A 4 0 4
[ 4] .dynsym DYNSYM 08048188 000188 000040 10 A 5 1 4
[ 5] .dynstr STRTAB 080481c8 0001c8 000045 00 A 0 0 1
[ 6] .gnu.version VERSYM 0804820e 00020e 000008 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 08048218 000218 000020 00 A 5 1 4
[ 8] .rel.dyn REL 08048238 000238 000008 08 A 4 0 4
[ 9] .rel.plt REL 08048240 000240 000010 08 A 4 11 4
[10] .init PROGBITS 08048250 000250 000017 00 AX 0 0 4
[11] .plt PROGBITS 08048268 000268 000030 04 AX 0 0 4
[12] .text PROGBITS 080482a0 0002a0 0001b8 00 AX 0 0 16
[13] .fini PROGBITS 08048458 000458 00001c 00 AX 0 0 4
[14] .rodata PROGBITS 08048474 000474 000017 00 A 0 0 4
[15] .eh_frame_hdr PROGBITS 0804848c 00048c 00001c 00 A 0 0 4
[16] .eh_frame PROGBITS 080484a8 0004a8 000058 00 A 0 0 4
[17] .ctors PROGBITS 08049500 000500 000008 00 WA 0 0 4
[18] .dtors PROGBITS 08049508 000508 000008 00 WA 0 0 4
[19] .jcr PROGBITS 08049510 000510 000004 00 WA 0 0 4
[20] .dynamic DYNAMIC 08049514 000514 0000c8 08 WA 5 0 4
[21] .got PROGBITS 080495dc 0005dc 000004 04 WA 0 0 4
[22] .got.plt PROGBITS 080495e0 0005e0 000014 04 WA 0 0 4
[23] .data PROGBITS 080495f4 0005f4 00000c 00 WA 0 0 4
[24] .bss NOBITS 08049600 000600 000008 00 WA 0 0 4
[25] .comment PROGBITS 00000000 000600 000114 00 0 0 1
[26] .shstrtab STRTAB 00000000 000714 0000e9 00 0 0 1
[27] .symtab SYMTAB 00000000 000c88 000460 10 28 50 4
[28] .strtab STRTAB 00000000 0010e8 00024e 00 0 0 1
1、链接:
符号是链接的粘合剂,整个链接过程正是基于符号才能正确完成
,链接过程中很关键的一部分就是对符号怕管理,每个目标文件都会有一个相应的
符号表,这个表里面记录了目标文件中所用到的所有符号,每个定义的一个符号
有一个对应的值,叫符号值,对于变量 和函数来说,符号
值就是它们的地址,除了函数和变量之外,还存在其他几种不常用到的符号
分类:
1、定义在目标文件中的全局符号,可以被其他目标文件引用
2、在本目标文件中引用的全局符号,却没有定义在本目标文件,外部符号
3、段名:这种符号由编译器产生,它的值是段的起始地址
4、局部符号:这类符号只在编译单元内部可以,如果函数中的静态变量
nm main.o 可以直接查看符号表
或readelf -s main
Symbol table '.dynsym' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2: 00000000 415 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2)
3: 08048478 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
Symbol table '.symtab' contains 70 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048134 0 SECTION LOCAL DEFAULT 1
2: 08048148 0 SECTION LOCAL DEFAULT 2
3: 08048168 0 SECTION LOCAL DEFAULT 3
4: 08048188 0 SECTION LOCAL DEFAULT 4
5: 080481c8 0 SECTION LOCAL DEFAULT 5
6: 0804820e 0 SECTION LOCAL DEFAULT 6
7: 08048218 0 SECTION LOCAL DEFAULT 7
8: 08048238 0 SECTION LOCAL DEFAULT 8
9: 08048240 0 SECTION LOCAL DEFAULT 9
10: 08048250 0 SECTION LOCAL DEFAULT 10
11: 08048268 0 SECTION LOCAL DEFAULT 11
12: 080482a0 0 SECTION LOCAL DEFAULT 12
13: 08048458 0 SECTION LOCAL DEFAULT 13
14: 08048474 0 SECTION LOCAL DEFAULT 14
15: 0804848c 0 SECTION LOCAL DEFAULT 15
16: 080484a8 0 SECTION LOCAL DEFAULT 16
17: 08049500 0 SECTION LOCAL DEFAULT 17
18: 08049508 0 SECTION LOCAL DEFAULT 18
19: 08049510 0 SECTION LOCAL DEFAULT 19
20: 08049514 0 SECTION LOCAL DEFAULT 20
21: 080495dc 0 SECTION LOCAL DEFAULT 21
22: 080495e0 0 SECTION LOCAL DEFAULT 22
23: 080495f4 0 SECTION LOCAL DEFAULT 23
24: 08049600 0 SECTION LOCAL DEFAULT 24
25: 00000000 0 SECTION LOCAL DEFAULT 25
26: 080482c4 0 FUNC LOCAL DEFAULT 12 call_gmon_start
27: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
28: 08049500 0 OBJECT LOCAL DEFAULT 17 __CTOR_LIST__
29: 08049508 0 OBJECT LOCAL DEFAULT 18 __DTOR_LIST__
30: 08049510 0 OBJECT LOCAL DEFAULT 19 __JCR_LIST__
31: 08049600 4 OBJECT LOCAL DEFAULT 24 dtor_idx.5793
32: 08049604 1 OBJECT LOCAL DEFAULT 24 completed.5791
33: 080482f0 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
34: 08048350 0 FUNC LOCAL DEFAULT 12 frame_dummy
35: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
36: 08049504 0 OBJECT LOCAL DEFAULT 17 __CTOR_END__
37: 080484fc 0 OBJECT LOCAL DEFAULT 16 __FRAME_END__
38: 08049510 0 OBJECT LOCAL DEFAULT 19 __JCR_END__
39: 08048430 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux
40: 00000000 0 FILE LOCAL DEFAULT ABS main.c
41: 080495f8 4 OBJECT LOCAL DEFAULT 23 var
42: 08049500 0 NOTYPE LOCAL HIDDEN 17 __preinit_array_start
43: 08049500 0 NOTYPE LOCAL HIDDEN 17 __fini_array_end
44: 080495e0 0 OBJECT LOCAL HIDDEN 22 _GLOBAL_OFFSET_TABLE_
45: 08049500 0 NOTYPE LOCAL HIDDEN 17 __preinit_array_end
46: 08049500 0 NOTYPE LOCAL HIDDEN 17 __fini_array_start
47: 08049500 0 NOTYPE LOCAL HIDDEN 17 __init_array_end
48: 08049500 0 NOTYPE LOCAL HIDDEN 17 __init_array_start
49: 08049514 0 OBJECT LOCAL HIDDEN 20 _DYNAMIC
50: 080495f4 0 NOTYPE WEAK DEFAULT 23 data_start
51: 080495fc 4 OBJECT GLOBAL DEFAULT 23 s
52: 080483b0 5 FUNC GLOBAL DEFAULT 12 __libc_csu_fini
53: 080482a0 0 FUNC GLOBAL DEFAULT 12 _start
54: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
55: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
56: 08048474 4 OBJECT GLOBAL DEFAULT 14 _fp_hw
57: 08048458 0 FUNC GLOBAL DEFAULT 13 _fini
58: 00000000 415 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
59: 08048478 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
60: 080495f4 0 NOTYPE GLOBAL DEFAULT 23 __data_start
61: 0804847c 0 OBJECT GLOBAL HIDDEN 14 __dso_handle
62: 0804950c 0 OBJECT GLOBAL HIDDEN 18 __DTOR_END__
63: 080483c0 105 FUNC GLOBAL DEFAULT 12 __libc_csu_init
64: 08049600 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
65: 08049608 0 NOTYPE GLOBAL DEFAULT ABS _end
66: 08049600 0 NOTYPE GLOBAL DEFAULT ABS _edata
67: 08048429 0 FUNC GLOBAL HIDDEN 12 __i686.get_pc_thunk.bx
68: 08048374 48 FUNC GLOBAL DEFAULT 12 main
69: 08048250 0 FUNC GLOBAL DEFAULT 10 _init
第二章 静态链接
1、定义两个文件a.b,b.c
extern int shared;
int main(){
int a = 100;
swap(&a,&shared);
}
b.c
int shared = 12;
int swap(int *a,int *b){
int t = *a;
*a = *b;
*b =t;
}
#gcc -c a.c
#gcc -c b.c
#objdump -h a.o
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000034 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000068 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000068 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 00000068 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 00000096 2**0
CONTENTS, READONLY
#objdump -h b.o
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000022 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 00000000 00000000 00000058 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 0000005c 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 0000005c 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 0000008a 2**0
CONTENTS, READONLY
#ld a.o b.o -e main -o ab
#objdump -h ab
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000056 08048094 08048094 00000094 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 080490ec 080490ec 000000ec 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .comment 0000005c 00000000 00000000 000000f0 2**0
CONTENTS, READONLY
链接步骤:
1、扫描所有输入目标文件,将输入目标文件中的符号表中所有的符号定义和引用收集起来
统一放到一个全局符号表
2、符号解析与重定位
使用上一步中收到的所有信息,将符号进行解析与重定位
对于#inlcude 的代码在预处理阶段就复制过来了,但它要的只是一个声明
有了声明就能进行编译,但在链接时,要的就是一个定义了,你引用的一个函数或
变量,如果不在本文件内,在链接时,它会将它们都分配到自己文件内,为它们分配
空间,确定它们的地址,
在编译时,如果引用了其他文件的变量或方法(其实不光是其他文件内,自己文件也是如果),它们的地址都是不
确定的,对于变量是用一个0 暂时表示它的地址,而方法则用 0xbffffff来表示,而这个地址的确定要在链接
阶段最终确定,这也是叫重定位
3、查看重定位表
在编译a.c 到 a.o后,由于a.c 中调用了b.c 中的数据,所以a.c中要有一个重定位表,用以重定位
在b.c中定义的数据,
objdump -r a.o
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000001c R_386_32 shared
00000027 R_386_PC32 swap
偏移表示要被重定位的地方
对于函数调用全局变量调用,即使是在自己文件中定义的,也会放在重定位表中
它们在链接过程中都会被重定位
还有一点就是如果引用了外部文件中或者本文件只是声明没有定义,在符号表中都有相应信息
readelf -s a.o
Symbol table '.symtab' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS a.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 4 OBJECT LOCAL DEFAULT 3 var
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000000 0 SECTION LOCAL DEFAULT 5
8: 00000000 5 FUNC GLOBAL DEFAULT 1 change
9: 00000005 71 FUNC GLOBAL DEFAULT 1 main
10: 00000000 0 NOTYPE GLOBAL DEFAULT UND shared
11: 00000000 0 NOTYPE GLOBAL DEFAULT UND swap
第7章 动态链接
1、链接操作推迟到运行时再进行,动态链接要有操作系统的支持
2、programe1.c
#include "lib.h"
int main(){
foobar1);
return 0;
}
program2.c
#include "lib.h"
int main(){
foobar(2);
return 0;
}
lib.c
#include <stdio.h>
void foobar(int i){
printf("Printing from lib.so%d\n",i);
}
lib.h
#ifndef LIB_B
#define LIB_H
void foobar(int i);
#endif
#gcc -fPIC -shared -o lib.so lib.c (将lib.c编译成共享对象)
#gcc -o program1 program1.c ./lib.so
#gcc -o program2 program2.c ./lib.so
在查看program1 中符号表时,看到 foobar 符号的类型为UND(undefined )
这也就表明了在链接过程中并没有把此函数链接进来
52: 00000000 45 FUNC GLOBAL DEFAULT UND foobar、
解析:在静态链接时,要对没有定义的的符号进行链接进来,并重定位它们的地址,但如果要链接的符号
定义在一个动态共享对象的函数中,那么链接器就会将这个符号的引用标记为一个动态链接的符号,不对
它们进行地址重定位,把这个过程留在装载时再进行
我们可以查看动态链接符号表,也就是在要动态链接的符号:objdump -T program1
[root@localhost compile]# objdump -T program1
program1: file format elf32-i386
DYNAMIC SYMBOL TABLE:
00000000 DF *UND* 0000002d foobar
00000000 w D *UND* 00000000 __gmon_start__
00000000 w D *UND* 00000000 _Jv_RegisterClasses
00000000 DF *UND* 0000019f GLIBC_2.0 __libc_start_main
080496e0 g D *ABS* 00000000 Base _end
080496d8 g D *ABS* 00000000 Base _edata
08048558 g DO .rodata 00000004 Base _IO_stdin_used
080496d8 g D *ABS* 00000000 Base __bss_start
08048338 g DF .init 00000000 Base _init
08048538 g DF .fini 00000000 Base _fini
gcc -S main.c -o main.s 编译(翻译成汇编)
as hello.s -o main.o 汇编(翻译成2进制) 下面进行链接
gcc -c main.c -o main.o 也是对程序只进行编译,并不链接
gcc main.c -o main 对程序进行编译并链接
1、符号:它用来表示一个地址,这个地址可以是一段子程序(后来发展成函数的起始地址),也是一个变量的的起始地址
函数访问厅知道目标函数的地址,变量访问也要知道目标变量的地址,所以这两种方式都可以归结为一种方式,那就是模块间符号的引用
2、链接:
从原理上廛,综的工作主是把一些指令对其他符号地址的引用加以修正,链接过程主要包括了地址和空间分配、答号决议、重定位
3、对于函数与变量的调用在经过汇编之后,编译成的二进制中,如果是全局量或静态变量都是将地址暂时置为0,而地址则是0xFFFFFFFc,这些地址的修正都是
在链接时间才进行完成的,因此,在编译时,编译器只认答号,只能没有语法错误,就可以编译通过
4、查看objdump Elf文件结构
readelf -S 查看段表的结构
obj 文件段表结构:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000030 00 AX 0 0 4
[ 2] .rel.text REL 00000000 0003a0 000010 08 10 1 4
[ 3] .data PROGBITS 00000000 000064 000008 00 WA 0 0 4
[ 4] .rel.data REL 00000000 0003b0 000008 08 10 3 4
[ 5] .bss NOBITS 00000000 00006c 000000 00 WA 0 0 4
[ 6] .rodata PROGBITS 00000000 00006c 00000b 00 A 0 0 1
[ 7] .comment PROGBITS 00000000 000077 00002e 00 0 0 1
[ 8] .note.GNU-stack PROGBITS 00000000 0000a5 000000 00 0 0 1
[ 9] .shstrtab STRTAB 00000000 0000a5 000055 00 0 0 1
[10] .symtab SYMTAB 00000000 0002dc 0000b0 10 11 9 4
[11] .strtab STRTAB 00000000 00038c 000013 00 0 0 1
名字 类型 虚拟地址 文件中偏移 长度
可执行文件段表结构:(程序虚拟地址从08048000开始,用户栈从0xbFFFFFFF开始,共享对象从0x40000000开始)
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4
[ 3] .gnu.hash GNU_HASH 08048168 000168 000020 04 A 4 0 4
[ 4] .dynsym DYNSYM 08048188 000188 000040 10 A 5 1 4
[ 5] .dynstr STRTAB 080481c8 0001c8 000045 00 A 0 0 1
[ 6] .gnu.version VERSYM 0804820e 00020e 000008 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 08048218 000218 000020 00 A 5 1 4
[ 8] .rel.dyn REL 08048238 000238 000008 08 A 4 0 4
[ 9] .rel.plt REL 08048240 000240 000010 08 A 4 11 4
[10] .init PROGBITS 08048250 000250 000017 00 AX 0 0 4
[11] .plt PROGBITS 08048268 000268 000030 04 AX 0 0 4
[12] .text PROGBITS 080482a0 0002a0 0001b8 00 AX 0 0 16
[13] .fini PROGBITS 08048458 000458 00001c 00 AX 0 0 4
[14] .rodata PROGBITS 08048474 000474 000017 00 A 0 0 4
[15] .eh_frame_hdr PROGBITS 0804848c 00048c 00001c 00 A 0 0 4
[16] .eh_frame PROGBITS 080484a8 0004a8 000058 00 A 0 0 4
[17] .ctors PROGBITS 08049500 000500 000008 00 WA 0 0 4
[18] .dtors PROGBITS 08049508 000508 000008 00 WA 0 0 4
[19] .jcr PROGBITS 08049510 000510 000004 00 WA 0 0 4
[20] .dynamic DYNAMIC 08049514 000514 0000c8 08 WA 5 0 4
[21] .got PROGBITS 080495dc 0005dc 000004 04 WA 0 0 4
[22] .got.plt PROGBITS 080495e0 0005e0 000014 04 WA 0 0 4
[23] .data PROGBITS 080495f4 0005f4 00000c 00 WA 0 0 4
[24] .bss NOBITS 08049600 000600 000008 00 WA 0 0 4
[25] .comment PROGBITS 00000000 000600 000114 00 0 0 1
[26] .shstrtab STRTAB 00000000 000714 0000e9 00 0 0 1
[27] .symtab SYMTAB 00000000 000c88 000460 10 28 50 4
[28] .strtab STRTAB 00000000 0010e8 00024e 00 0 0 1
1、链接:
符号是链接的粘合剂,整个链接过程正是基于符号才能正确完成
,链接过程中很关键的一部分就是对符号怕管理,每个目标文件都会有一个相应的
符号表,这个表里面记录了目标文件中所用到的所有符号,每个定义的一个符号
有一个对应的值,叫符号值,对于变量 和函数来说,符号
值就是它们的地址,除了函数和变量之外,还存在其他几种不常用到的符号
分类:
1、定义在目标文件中的全局符号,可以被其他目标文件引用
2、在本目标文件中引用的全局符号,却没有定义在本目标文件,外部符号
3、段名:这种符号由编译器产生,它的值是段的起始地址
4、局部符号:这类符号只在编译单元内部可以,如果函数中的静态变量
nm main.o 可以直接查看符号表
或readelf -s main
Symbol table '.dynsym' contains 4 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
2: 00000000 415 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2)
3: 08048478 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
Symbol table '.symtab' contains 70 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048134 0 SECTION LOCAL DEFAULT 1
2: 08048148 0 SECTION LOCAL DEFAULT 2
3: 08048168 0 SECTION LOCAL DEFAULT 3
4: 08048188 0 SECTION LOCAL DEFAULT 4
5: 080481c8 0 SECTION LOCAL DEFAULT 5
6: 0804820e 0 SECTION LOCAL DEFAULT 6
7: 08048218 0 SECTION LOCAL DEFAULT 7
8: 08048238 0 SECTION LOCAL DEFAULT 8
9: 08048240 0 SECTION LOCAL DEFAULT 9
10: 08048250 0 SECTION LOCAL DEFAULT 10
11: 08048268 0 SECTION LOCAL DEFAULT 11
12: 080482a0 0 SECTION LOCAL DEFAULT 12
13: 08048458 0 SECTION LOCAL DEFAULT 13
14: 08048474 0 SECTION LOCAL DEFAULT 14
15: 0804848c 0 SECTION LOCAL DEFAULT 15
16: 080484a8 0 SECTION LOCAL DEFAULT 16
17: 08049500 0 SECTION LOCAL DEFAULT 17
18: 08049508 0 SECTION LOCAL DEFAULT 18
19: 08049510 0 SECTION LOCAL DEFAULT 19
20: 08049514 0 SECTION LOCAL DEFAULT 20
21: 080495dc 0 SECTION LOCAL DEFAULT 21
22: 080495e0 0 SECTION LOCAL DEFAULT 22
23: 080495f4 0 SECTION LOCAL DEFAULT 23
24: 08049600 0 SECTION LOCAL DEFAULT 24
25: 00000000 0 SECTION LOCAL DEFAULT 25
26: 080482c4 0 FUNC LOCAL DEFAULT 12 call_gmon_start
27: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
28: 08049500 0 OBJECT LOCAL DEFAULT 17 __CTOR_LIST__
29: 08049508 0 OBJECT LOCAL DEFAULT 18 __DTOR_LIST__
30: 08049510 0 OBJECT LOCAL DEFAULT 19 __JCR_LIST__
31: 08049600 4 OBJECT LOCAL DEFAULT 24 dtor_idx.5793
32: 08049604 1 OBJECT LOCAL DEFAULT 24 completed.5791
33: 080482f0 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
34: 08048350 0 FUNC LOCAL DEFAULT 12 frame_dummy
35: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
36: 08049504 0 OBJECT LOCAL DEFAULT 17 __CTOR_END__
37: 080484fc 0 OBJECT LOCAL DEFAULT 16 __FRAME_END__
38: 08049510 0 OBJECT LOCAL DEFAULT 19 __JCR_END__
39: 08048430 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux
40: 00000000 0 FILE LOCAL DEFAULT ABS main.c
41: 080495f8 4 OBJECT LOCAL DEFAULT 23 var
42: 08049500 0 NOTYPE LOCAL HIDDEN 17 __preinit_array_start
43: 08049500 0 NOTYPE LOCAL HIDDEN 17 __fini_array_end
44: 080495e0 0 OBJECT LOCAL HIDDEN 22 _GLOBAL_OFFSET_TABLE_
45: 08049500 0 NOTYPE LOCAL HIDDEN 17 __preinit_array_end
46: 08049500 0 NOTYPE LOCAL HIDDEN 17 __fini_array_start
47: 08049500 0 NOTYPE LOCAL HIDDEN 17 __init_array_end
48: 08049500 0 NOTYPE LOCAL HIDDEN 17 __init_array_start
49: 08049514 0 OBJECT LOCAL HIDDEN 20 _DYNAMIC
50: 080495f4 0 NOTYPE WEAK DEFAULT 23 data_start
51: 080495fc 4 OBJECT GLOBAL DEFAULT 23 s
52: 080483b0 5 FUNC GLOBAL DEFAULT 12 __libc_csu_fini
53: 080482a0 0 FUNC GLOBAL DEFAULT 12 _start
54: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
55: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
56: 08048474 4 OBJECT GLOBAL DEFAULT 14 _fp_hw
57: 08048458 0 FUNC GLOBAL DEFAULT 13 _fini
58: 00000000 415 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
59: 08048478 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
60: 080495f4 0 NOTYPE GLOBAL DEFAULT 23 __data_start
61: 0804847c 0 OBJECT GLOBAL HIDDEN 14 __dso_handle
62: 0804950c 0 OBJECT GLOBAL HIDDEN 18 __DTOR_END__
63: 080483c0 105 FUNC GLOBAL DEFAULT 12 __libc_csu_init
64: 08049600 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
65: 08049608 0 NOTYPE GLOBAL DEFAULT ABS _end
66: 08049600 0 NOTYPE GLOBAL DEFAULT ABS _edata
67: 08048429 0 FUNC GLOBAL HIDDEN 12 __i686.get_pc_thunk.bx
68: 08048374 48 FUNC GLOBAL DEFAULT 12 main
69: 08048250 0 FUNC GLOBAL DEFAULT 10 _init
第二章 静态链接
1、定义两个文件a.b,b.c
extern int shared;
int main(){
int a = 100;
swap(&a,&shared);
}
b.c
int shared = 12;
int swap(int *a,int *b){
int t = *a;
*a = *b;
*b =t;
}
#gcc -c a.c
#gcc -c b.c
#objdump -h a.o
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000034 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .data 00000000 00000000 00000000 00000068 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000068 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 00000068 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 00000096 2**0
CONTENTS, READONLY
#objdump -h b.o
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000022 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 00000000 00000000 00000058 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 0000005c 2**2
ALLOC
3 .comment 0000002e 00000000 00000000 0000005c 2**0
CONTENTS, READONLY
4 .note.GNU-stack 00000000 00000000 00000000 0000008a 2**0
CONTENTS, READONLY
#ld a.o b.o -e main -o ab
#objdump -h ab
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000056 08048094 08048094 00000094 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000004 080490ec 080490ec 000000ec 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .comment 0000005c 00000000 00000000 000000f0 2**0
CONTENTS, READONLY
链接步骤:
1、扫描所有输入目标文件,将输入目标文件中的符号表中所有的符号定义和引用收集起来
统一放到一个全局符号表
2、符号解析与重定位
使用上一步中收到的所有信息,将符号进行解析与重定位
对于#inlcude 的代码在预处理阶段就复制过来了,但它要的只是一个声明
有了声明就能进行编译,但在链接时,要的就是一个定义了,你引用的一个函数或
变量,如果不在本文件内,在链接时,它会将它们都分配到自己文件内,为它们分配
空间,确定它们的地址,
在编译时,如果引用了其他文件的变量或方法(其实不光是其他文件内,自己文件也是如果),它们的地址都是不
确定的,对于变量是用一个0 暂时表示它的地址,而方法则用 0xbffffff来表示,而这个地址的确定要在链接
阶段最终确定,这也是叫重定位
3、查看重定位表
在编译a.c 到 a.o后,由于a.c 中调用了b.c 中的数据,所以a.c中要有一个重定位表,用以重定位
在b.c中定义的数据,
objdump -r a.o
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000001c R_386_32 shared
00000027 R_386_PC32 swap
偏移表示要被重定位的地方
对于函数调用全局变量调用,即使是在自己文件中定义的,也会放在重定位表中
它们在链接过程中都会被重定位
还有一点就是如果引用了外部文件中或者本文件只是声明没有定义,在符号表中都有相应信息
readelf -s a.o
Symbol table '.symtab' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS a.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 4 OBJECT LOCAL DEFAULT 3 var
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000000 0 SECTION LOCAL DEFAULT 5
8: 00000000 5 FUNC GLOBAL DEFAULT 1 change
9: 00000005 71 FUNC GLOBAL DEFAULT 1 main
10: 00000000 0 NOTYPE GLOBAL DEFAULT UND shared
11: 00000000 0 NOTYPE GLOBAL DEFAULT UND swap
第7章 动态链接
1、链接操作推迟到运行时再进行,动态链接要有操作系统的支持
2、programe1.c
#include "lib.h"
int main(){
foobar1);
return 0;
}
program2.c
#include "lib.h"
int main(){
foobar(2);
return 0;
}
lib.c
#include <stdio.h>
void foobar(int i){
printf("Printing from lib.so%d\n",i);
}
lib.h
#ifndef LIB_B
#define LIB_H
void foobar(int i);
#endif
#gcc -fPIC -shared -o lib.so lib.c (将lib.c编译成共享对象)
#gcc -o program1 program1.c ./lib.so
#gcc -o program2 program2.c ./lib.so
在查看program1 中符号表时,看到 foobar 符号的类型为UND(undefined )
这也就表明了在链接过程中并没有把此函数链接进来
52: 00000000 45 FUNC GLOBAL DEFAULT UND foobar、
解析:在静态链接时,要对没有定义的的符号进行链接进来,并重定位它们的地址,但如果要链接的符号
定义在一个动态共享对象的函数中,那么链接器就会将这个符号的引用标记为一个动态链接的符号,不对
它们进行地址重定位,把这个过程留在装载时再进行
我们可以查看动态链接符号表,也就是在要动态链接的符号:objdump -T program1
[root@localhost compile]# objdump -T program1
program1: file format elf32-i386
DYNAMIC SYMBOL TABLE:
00000000 DF *UND* 0000002d foobar
00000000 w D *UND* 00000000 __gmon_start__
00000000 w D *UND* 00000000 _Jv_RegisterClasses
00000000 DF *UND* 0000019f GLIBC_2.0 __libc_start_main
080496e0 g D *ABS* 00000000 Base _end
080496d8 g D *ABS* 00000000 Base _edata
08048558 g DO .rodata 00000004 Base _IO_stdin_used
080496d8 g D *ABS* 00000000 Base __bss_start
08048338 g DF .init 00000000 Base _init
08048538 g DF .fini 00000000 Base _fini