最近在看《CSAPP》这本神书,其中看到了第七章链接中的可重定位目标文件,自己动手在ubuntu16.04上试了一试,发现有很多都做了一些改动,在此记录
1.源程序
main.c
static int a = 1;
int buf[2] = {1,2};
void swap();
int main()
{
a = 2;
swap();
return 0;
}
swap.c
extern int buf[];
int *p0 = &buf[0];
static int* p1;
static int p3 = 1;
void swap()
{
int temp;
p1 = &buf[1];
temp = *p0;
*p0 = *p1;
*p1 = temp;
}
我现在要看的就是代码中的每个符号定义以及引用在经过编译汇编后分别位于.o文件的哪个节中
2.编译与汇编
分别执行
gcc -c main.c
与
gcc -c swap.c
得到main.o与swap.o
3.以swap.o为例,查看各个节
首先 ,ELF文件的结构
Section
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000000000 000040 00003c 00 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 000258 000090 18 I 11 1 8
[ 3] .data PROGBITS 0000000000000000 000080 00000c 00 WA 0 0 8
[ 4] .rela.data RELA 0000000000000000 0002e8 000018 18 I 11 3 8
[ 5] .bss NOBITS 0000000000000000 000090 000008 00 WA 0 0 8
[ 6] .comment PROGBITS 0000000000000000 000090 000036 01 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 0000c6 000000 00 0 0 1
[ 8] .eh_frame PROGBITS 0000000000000000 0000c8 000038 00 A 0 0 8
[ 9] .rela.eh_frame RELA 0000000000000000 000300 000018 18 I 11 8 8
[10] .shstrtab STRTAB 0000000000000000 000318 00005e 00 0 0 1
[11] .symtab SYMTAB 0000000000000000 000100 000138 18 12 10 8
[12] .strtab STRTAB 0000000000000000 000238 00001a 00 0 0 1
查看符号表
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 swap.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l O .bss 0000000000000008 p1
0000000000000008 l O .data 0000000000000004 p3
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 p0
0000000000000000 *UND* 0000000000000000 buf
0000000000000000 g F .text 000000000000003c swap
可以看到,buf由于是外部变量在这里仅仅是一个重定位项(这一点与CSAPP给的课后题目答案非常不一样,CSAPP给出的是buf在.data节这是不对的),p0,p3由于显示初始化了所以在.data节
同时, readelf -a swap.o可以得到重定位节中的相关信息
重定位节 '.rela.text' 位于偏移量 0x258 含有 6 个条目:
偏移量 信息 类型 符号值 符号名称 + 加数
000000000007 000400000002 R_X86_64_PC32 0000000000000000 .bss - 8
00000000000b 000b0000000b R_X86_64_32S 0000000000000000 buf + 4
000000000012 000a00000002 R_X86_64_PC32 0000000000000000 p0 - 4
00000000001e 000a00000002 R_X86_64_PC32 0000000000000000 p0 - 4
000000000025 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4
000000000030 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4
重定位节 '.rela.data' 位于偏移量 0x2e8 含有 1 个条目:
偏移量 信息 类型 符号值 符号名称 + 加数
000000000000 000b00000001 R_X86_64_64 0000000000000000 buf + 0
重定位节 '.rela.eh_frame' 位于偏移量 0x300 含有 1 个条目:
偏移量 信息 类型 符号值 符号名称 + 加数
000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
swap.c中与外部符号有关的部分:
extern int buf[];
int *p0 = &buf[0];
p0与buf需要在链接的时候进行重定位