Chinaunix首页 | 论坛 | 博客
  • 博客访问: 22114
  • 博文数量: 5
  • 博客积分: 235
  • 博客等级: 二等列兵
  • 技术积分: 65
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-30 20:06
文章分类

全部博文(5)

文章存档

2012年(2)

2011年(2)

2010年(1)

我的朋友

分类: LINUX

2011-09-19 20:01:27

刚把csapp链接一章看完,很多地方都需要动手实际做一下,以便系统化对elf的理解。由于目前实际应用中PIC动态库使用较多,故记录了PIC的实践过程,概念及理论见csapp书本,本文主要是step by step的过程。

1. 运行环境
fedora10-i386,gcc-4.3.2

2. 代码
使用csapp原书中的代码。罗列如下:

Makefile:(加入-g是为了后面使用gdb方便)
  1. CFLAGS=-g

  2. p2: main2.o libvector.so
  3.      gcc -o $@ $< -L. -lvector $(CFLAGS)
  4. main2.o: main2.c
  5.      gcc -c $< $(CFLAGS)
  6. libvector.so: addvec.c
  7.      gcc -shared -fPIC -o $@ $< $(CFLAGS)

  8. PHONY: clean
  9. clean:
  10.      @rm -f *.o
  11.      @rm -f *.so
  12.      @rm -f p2
addvec.c
  1. void addvec(int *x, int *y,
  2.                 int *z, int n)
  3. {
  4.         int i;

  5.         for (i = 0; i < n; i++)
  6.                 z[i] = x[i] + y[i];
  7. }
main2.c

  1. /* main2.c */
  2. #include <stdio.h>
  3. #include "vector.h"

  4. int x[2] = {1, 2};
  5. int y[2] = {3, 4};
  6. int z[2];

  7. int main()
  8. {
  9.         addvec(x, y, z, 2);
  10.         printf("z = [%d %d]\n", z[0], z[1]);
  11.         return 0;
  12. }
vector.h
  1. #ifndef _VECTOR_H_
  2. #define _VECTOR_H_
  3. void addvec(int *x, int *y,
  4.                 int *z, int n);
  5. void multvec(int *x, int *y,
  6.                 int *z, int n);
  7. #endif

3. 编译
$make

4. 使用工具查看GOT和PLT
4.1 查看程序镜像
通过objdump查看GOT
  1. [root@Fedora10 csapp]# objdump -d -j .got.plt p2

  2. p2: file format elf32-i386


  3. Disassembly of section .got.plt:

  4. 08049750 <_GLOBAL_OFFSET_TABLE_>:
  5. 8049750: 7c 96 04 08 00 00 00 00 00 00 00 00 c6 83 04 08 |...............
  6. 8049760: d6 83 04 08 e6 83 04 08 f6 83 04 08              ............
(注,这里.got.plt section才是GOT表,并非.got)

PLT的内容:
  1. [root@Fedora10 csapp]# objdump -d -j .plt p2

  2. p2: file format elf32-i386


  3. Disassembly of section .plt:

  4. 080483b0 <__gmon_start__@plt-0x10>:
  5. 80483b0: ff 35 54 97 04 08 pushl 0x8049754
  6. 80483b6: ff 25 58 97 04 08 jmp *0x8049758   #注:跳到*GOT[2],实际就是执行dynamic linker,
  7.                                             #后面可看到是_dl_runtime_resolve
  8. 80483bc: 00 00             add %al,(%eax)
  9. ...

  10. 080483c0 <__gmon_start__@plt>:
  11. 80483c0: ff 25 5c 97 04 08 jmp *0x804975c
  12. 80483c6: 68 00 00 00 00    push $0x0
  13. 80483cb: e9 e0 ff ff ff    jmp 80483b0 <_init+0x30>

  14. 080483d0 <__libc_start_main@plt>:
  15. 80483d0: ff 25 60 97 04 08 jmp *0x8049760
  16. 80483d6: 68 08 00 00 00    push $0x8
  17. 80483db: e9 d0 ff ff ff    jmp 80483b0 <_init+0x30>

  18. 080483e0 :
  19. 80483e0: ff 25 64 97 04 08 jmp *0x8049764
  20. 80483e6: 68 10 00 00 00    push $0x10
  21. 80483eb: e9 c0 ff ff ff    jmp 80483b0 <_init+0x30>

  22. 080483f0 :
  23. 80483f0: ff 25 68 97 04 08 jmp *0x8049768
  24. 80483f6: 68 18 00 00 00    push $0x18
  25. 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的函数在全局的偏移:
  1. [root@Fedora10 csapp]# readelf -r p2

  2. Relocation section '.rel.dyn' at offset 0x358 contains 1 entries:
  3. Offset Info Type Sym.Value Sym. Name
  4. 0804974c 00000106 R_386_GLOB_DAT 00000000 __gmon_start__

  5. Relocation section '.rel.plt' at offset 0x360 contains 4 entries:
  6. Offset Info Type Sym.Value Sym. Name
  7. 0804975c 00000107 R_386_JUMP_SLOT 00000000 __gmon_start__
  8. 08049760 00000307 R_386_JUMP_SLOT 00000000 __libc_start_main
  9. 08049764 00000407 R_386_JUMP_SLOT 00000000 printf
  10. 08049768 00000507 R_386_JUMP_SLOT 00000000 addvec

4.2 运行gdb p2查看GOT的变化:
  1. [root@Fedora10 csapp]# gdb p2
  2. GNU gdb Fedora (6.8-29.fc10)
  3. Copyright (C) 2008 Free Software Foundation, Inc.
  4. License GPLv3+: GNU GPL version 3 or later <
  5. This is free software: you are free to change and redistribute it.
  6. There is NO WARRANTY, to the extent permitted by law. Type "show copying"
  7. and "show warranty" for details.
  8. This GDB was configured as "i386-redhat-linux-gnu"...
  9. (gdb) b main
  10. Breakpoint 1 at 0x80484c5: file main2.c, line 11.
  11. (gdb) x/8x 0x08049750
  12. 0x8049750 <_GLOBAL_OFFSET_TABLE_>:    0x0804967c 0x00000000 0x00000000 0x080483c6
  13. 0x8049760 <_GLOBAL_OFFSET_TABLE_+16>: 0x080483d6 0x080483e6 0x080483f6 0x00000000
  14. #注:程序还没运行,这里的GOT表同objdump打印的一样
  15. (gdb) r
  16. Starting program: /home/test/test/csapp/p2

  17. Breakpoint 1, main () at main2.c:11
  18. 11 addvec(x, y, z, 2);
  19. Missing separate debuginfos, use: debuginfo-install glibc-2.9-2.i686
  20. (gdb) x/8x 0x08049750
  21. 0x8049750 <_GLOBAL_OFFSET_TABLE_>:    0x0804967c 0x0069c658 0x00690520 0x080483c6
  22. 0x8049760 <_GLOBAL_OFFSET_TABLE_+16>: 0x006b55f0 0x080483e6 0x080483f6 0x00000000
  23. #注:程序已运行,可以看到glibc已加载,同时GOT的值已变化,该地址对应实际的__libc_start_main()
  24. (gdb) info symbol 0x00690520
    _dl_runtime_resolve in section .text
  25. #注:运行开始后,GOT[2]就更新成了dynamic linker的入口
  26. (gdb) n
  27. 12 printf("z = [%d %d]\n", z[0], z[1]);
  28. (gdb) n
  29. z = [4 6]
  30. 13 return 0;
  31. (gdb) x/8x 0x08049750
  32. 0x8049750 <_GLOBAL_OFFSET_TABLE_>:    0x0804967c 0x0069c658 0x00690520 0x080483c6
  33. 0x8049760 <_GLOBAL_OFFSET_TABLE_+16>: 0x006b55f0 0x006e88f0 0x001113cc 0x00000000
  34. #注:执行完addvec()和printf(),再看GOT中这两项的值,已改变
如果想确认更新后,地址对应的函数,可以在gdb中用disas命令来查看反汇编内容
如(gdb) disas 0x001113cc

阅读(1814) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~