刚把csapp链接一章看完,很多地方都需要动手实际做一下,以便系统化对elf的理解。由于目前实际应用中PIC动态库使用较多,故记录了PIC的实践过程,概念及理论见csapp书本,本文主要是step by step的过程。
1. 运行环境fedora10-i386,gcc-4.3.2
2. 代码使用csapp原书中的代码。罗列如下:
Makefile:(加入-g是为了后面使用gdb方便)
- CFLAGS=-g
-
-
p2: main2.o libvector.so
-
gcc -o $@ $< -L. -lvector $(CFLAGS)
-
main2.o: main2.c
-
gcc -c $< $(CFLAGS)
-
libvector.so: addvec.c
-
gcc -shared -fPIC -o $@ $< $(CFLAGS)
-
-
PHONY: clean
-
clean:
-
@rm -f *.o
-
@rm -f *.so
-
@rm -f p2
addvec.c
- void addvec(int *x, int *y,
-
int *z, int n)
-
{
-
int i;
-
-
for (i = 0; i < n; i++)
-
z[i] = x[i] + y[i];
-
}
main2.c
- /* main2.c */
-
#include <stdio.h>
-
#include "vector.h"
-
-
int x[2] = {1, 2};
-
int y[2] = {3, 4};
-
int z[2];
-
-
int main()
-
{
-
addvec(x, y, z, 2);
-
printf("z = [%d %d]\n", z[0], z[1]);
-
return 0;
-
}
vector.h
- #ifndef _VECTOR_H_
-
#define _VECTOR_H_
-
void addvec(int *x, int *y,
-
int *z, int n);
-
void multvec(int *x, int *y,
-
int *z, int n);
-
#endif
3. 编译$make
4. 使用工具查看GOT和PLT4.1 查看程序镜像
通过objdump查看GOT
- [root@Fedora10 csapp]# objdump -d -j .got.plt p2
-
-
p2: file format elf32-i386
-
-
-
Disassembly of section .got.plt:
-
-
08049750 <_GLOBAL_OFFSET_TABLE_>:
-
8049750: 7c 96 04 08 00 00 00 00 00 00 00 00 c6 83 04 08 |...............
-
8049760: d6 83 04 08 e6 83 04 08 f6 83 04 08 ............
(注,这里.got.plt section才是GOT表,并非.got)
PLT的内容:
- [root@Fedora10 csapp]# objdump -d -j .plt p2
-
-
p2: file format elf32-i386
-
-
-
Disassembly of section .plt:
-
-
080483b0 <__gmon_start__@plt-0x10>:
-
80483b0: ff 35 54 97 04 08 pushl 0x8049754
-
80483b6: ff 25 58 97 04 08 jmp *0x8049758 #注:跳到*GOT[2],实际就是执行dynamic linker,
- #后面可看到是_dl_runtime_resolve
-
80483bc: 00 00 add %al,(%eax)
-
...
-
-
080483c0 <__gmon_start__@plt>:
-
80483c0: ff 25 5c 97 04 08 jmp *0x804975c
-
80483c6: 68 00 00 00 00 push $0x0
-
80483cb: e9 e0 ff ff ff jmp 80483b0 <_init+0x30>
-
-
080483d0 <__libc_start_main@plt>:
-
80483d0: ff 25 60 97 04 08 jmp *0x8049760
-
80483d6: 68 08 00 00 00 push $0x8
-
80483db: e9 d0 ff ff ff jmp 80483b0 <_init+0x30>
-
-
080483e0 :
-
80483e0: ff 25 64 97 04 08 jmp *0x8049764
-
80483e6: 68 10 00 00 00 push $0x10
-
80483eb: e9 c0 ff ff ff jmp 80483b0 <_init+0x30>
-
-
080483f0 :
-
80483f0: ff 25 68 97 04 08 jmp *0x8049768
-
80483f6: 68 18 00 00 00 push $0x18
-
80483fb: e9 b0 ff ff ff jmp 80483b0 <_init+0x30>
PLT可以看成一个数组,每个元素为16字节。PLT[0]比较特殊,执行它会跳转到dynamic linker,从__gmon_start__@plt开始,为PLT[1],终于PLT[4],addvec@plt。各个PLT的entry和GOT的entry对应关系都用不同颜色标出。
另外,通过readelf -r也可以看到各个PLT的函数在全局的偏移:
- [root@Fedora10 csapp]# readelf -r p2
-
-
Relocation section '.rel.dyn' at offset 0x358 contains 1 entries:
-
Offset Info Type Sym.Value Sym. Name
-
0804974c 00000106 R_386_GLOB_DAT 00000000 __gmon_start__
-
-
Relocation section '.rel.plt' at offset 0x360 contains 4 entries:
-
Offset Info Type Sym.Value Sym. Name
-
0804975c 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
-
08049760 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main
-
08049764 00000407 R_386_JUMP_SLOT 00000000 printf
-
08049768 00000507 R_386_JUMP_SLOT 00000000 addvec
4.2 运行gdb p2查看GOT的变化:
- [root@Fedora10 csapp]# gdb p2
-
GNU gdb Fedora (6.8-29.fc10)
-
Copyright (C) 2008 Free Software Foundation, Inc.
-
License GPLv3+: GNU GPL version 3 or later <
-
This is free software: you are free to change and redistribute it.
-
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
-
and "show warranty" for details.
-
This GDB was configured as "i386-redhat-linux-gnu"...
-
(gdb) b main
-
Breakpoint 1 at 0x80484c5: file main2.c, line 11.
-
(gdb) x/8x 0x08049750
-
0x8049750 <_GLOBAL_OFFSET_TABLE_>: 0x0804967c 0x00000000 0x00000000 0x080483c6
-
0x8049760 <_GLOBAL_OFFSET_TABLE_+16>: 0x080483d6 0x080483e6 0x080483f6 0x00000000
- #注:程序还没运行,这里的GOT表同objdump打印的一样
-
(gdb) r
-
Starting program: /home/test/test/csapp/p2
-
-
Breakpoint 1, main () at main2.c:11
-
11 addvec(x, y, z, 2);
-
Missing separate debuginfos, use: debuginfo-install glibc-2.9-2.i686
-
(gdb) x/8x 0x08049750
-
0x8049750 <_GLOBAL_OFFSET_TABLE_>: 0x0804967c 0x0069c658 0x00690520 0x080483c6
-
0x8049760 <_GLOBAL_OFFSET_TABLE_+16>: 0x006b55f0 0x080483e6 0x080483f6 0x00000000
- #注:程序已运行,可以看到glibc已加载,同时GOT的值已变化,该地址对应实际的__libc_start_main()
- (gdb) info symbol 0x00690520
_dl_runtime_resolve in section .text - #注:运行开始后,GOT[2]就更新成了dynamic linker的入口
-
(gdb) n
-
12 printf("z = [%d %d]\n", z[0], z[1]);
-
(gdb) n
-
z = [4 6]
-
13 return 0;
-
(gdb) x/8x 0x08049750
-
0x8049750 <_GLOBAL_OFFSET_TABLE_>: 0x0804967c 0x0069c658 0x00690520 0x080483c6
-
0x8049760 <_GLOBAL_OFFSET_TABLE_+16>: 0x006b55f0 0x006e88f0 0x001113cc 0x00000000
- #注:执行完addvec()和printf(),再看GOT中这两项的值,已改变
如果想确认更新后,地址对应的函数,可以在gdb中用
disas命令来查看反汇编内容,
如(gdb) disas
0x001113cc
阅读(1814) | 评论(0) | 转发(0) |