免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 26618 | 回复: 2

[C] 动态链接的问题 [复制链接]

论坛徽章:
0
发表于 2020-05-14 18:34 |显示全部楼层
本帖最后由 kdx_test 于 2020-05-15 08:32 编辑

我baidu了一下,在 linux 32位系统里面,有关动态链接里 GOT表的访问,说大致为以下样式:

  1. fun@plt:
  2.         jmp *(fun@got.plt)      
  3.         push index           
  4.         jmp _init            
复制代码

至于 linux 64位系统,我也baidu了一下,似乎样式跟 上面 32位系统的是一样的,只是地址不一样(变成 0x400XXX)。

但实际上,对于 Linux 64 位系统(ubuntu17.04 64位),我自己写了一个例子测试后发现却不是这样,我的测试样式如下:
   
  1. fun@plt
  2.         jmpq   *0x20089a(%rip)            // 200fb8 <a1>, ff 25 9a 08 20 00
  3.         xchg   %ax,%ax            // 66 90
复制代码

问题:

    我的测试有问题?


附上测试过程如下(测试环境:ubuntu 17.04 64位):

  1. //代码 a1.c
  2. #include        <stdio.h>

  3. static char arr[]        = {
  4.                                 'w','x','y','z','4','4','4','4'
  5.                                 };

  6. void a1()
  7. {
  8.         printf("a1.c\n");
  9.         printf("a1:%s\n",arr);
  10. }

  11. //代码 a2.c
  12. #include        <stdio.h>

  13. static char arr[]        = "abcd12345";

  14. void a2()
  15. {
  16.         printf("a2.c\n");
  17.         printf("a2:%s\n",arr);
  18. }

  19. //代码 b1.c
  20. #include        <stdio.h>

  21. void b1()
  22. {
  23.         char arr[]        = "ghij56789";

  24.         printf("b1.c\n");
  25.         printf("b1:%s\n", arr);
  26. }

  27. //代码 b2.c
  28. #include        <stdio.h>

  29. void b2()
  30. {
  31.         char arr[]        = {
  32.                                 'k','l','m','n','2','2','2','2'
  33.                                 };
  34.         printf("b2.c\n");
  35.         printf("b2:%s\n",arr);
  36. }

  37. //代码 main.c
  38. #include        <stdio.h>

  39. void a1();
  40. void a2();
  41. void b1();
  42. void b2();

  43. int main()
  44. {
  45.         a1();
  46.         a2();
  47.         b1();
  48.         b2();

  49.         printf("main.c\n");

  50.         return 0;
  51. }

  52. //编译
  53. gcc -g -fPIC -shared a1.c -o a1.so
  54. gcc -g -fPIC -shared a2.c -o a2.so
  55. gcc -g -fPIC -shared b1.c -o b1.so
  56. gcc -g -fPIC -shared b2.c -o b2.so
  57. gcc main.c a1.so a2.so b1.so b2.so -o main -g -Xlinker -rpath ./

  58. 使用 gdb 调试
  59. > gdb main
  60. > b main
  61. > r
  62. > disass main                        
  63.                 Dump of assembler code for function main:
  64.                    0x0000555555554870 <+0>:        push   %rbp
  65.                    0x0000555555554871 <+1>:        mov    %rsp,%rbp
  66.                 => 0x0000555555554874 <+4>:        mov    $0x0,%eax
  67.                    0x0000555555554879 <+9>:        callq  0x555555554718                //实际是 call a1
  68.                    0x000055555555487e <+14>:        mov    $0x0,%eax
  69.                    0x0000555555554883 <+19>:        callq  0x555555554728
  70.                    0x0000555555554888 <+24>:        mov    $0x0,%eax
  71.                    0x000055555555488d <+29>:        callq  0x555555554738
  72.                    0x0000555555554892 <+34>:        mov    $0x0,%eax
  73.                    0x0000555555554897 <+39>:        callq  0x555555554720
  74.                    0x000055555555489c <+44>:        lea    0x91(%rip),%rdi        # 0x555555554934
  75.                    0x00005555555548a3 <+51>:        callq  0x555555554710
  76.                    0x00005555555548a8 <+56>:        mov    $0x0,%eax
  77.                    0x00005555555548ad <+61>:        pop    %rbp
  78.                    0x00005555555548ae <+62>:        retq   
  79.                 End of assembler dump.

  80.         以 call 0x555555554718 为例
  81.                 > x/16x 0x555555554718

  82.                         0x555555554718:        0x089a25ff        0x90660020        0x08aa25ff        0x90660020  
  83.                                         .......................

  84.                         转换前8个字节(小端转大端)
  85.                         
  86.                         ff 25 9a 08 20 00 66 90

  87.                         这个就是我之前提到样式

  88.                         GOT条目地址        = 当前EIP + 偏移 + sizeof(调用指令)
  89.                                         = 0x555555554718 + 0x20089a + sizeof(调用指令)
  90.                                         = 0x555555554718 + 0x20089a + 6
  91.                                         = 0x555555754FB8

  92.                 > x/16x 0x555555754FB8(GOT条目地址)

  93.                         0x555555754fb8:        0xf7bd56c0        0x00007fff        0xf7228300        0x00007fff

  94.                         转换前8个字节(小端转大端)

  95.                         c0 56 bd f7 ff 7f 00 00

  96.                         目标函数地址        = 0x7ffff7bd56c0

  97.                 > x/16x 0x7ffff7bd56c0(目标函数)

  98.                         0x7ffff7bd56c0 <a1>:        0xe5894855        0x2a3d8d48        0xe8000000        0xfffffec0
  99.                         0x7ffff7bd56d0 <a1+16>:        0x59358d48        0x48002009        0x001c3d8d        0x00b80000
  100.                         0x7ffff7bd56e0 <a1+32>:        0xe8000000        0xfffffeb8        0x00c35d90        0x08ec8348
  101.                         ........

  102.                         可见,call 0x555555554718 即 call a1 (函数a1()是在 共享库 a1.so中)
复制代码

因为上面的调试是可以“找到”共享库 a1.so 里面的 a1()函数的,所以上面的分析应该是没问题的。但这个与baidu到的资料有较大不同,主要是baidu的资料里面是涉及到了GOT条目的(例如:会有 push操作,将函数对应GOT索引压栈,然后又使用 GOT[2]里面的 _dl_runtime_resolve()函数等),这些似乎在我上面的例子里面没有碰到,但又能得到相应的结果,这是为何?是巧合还是baidu到的资料有问题(我说的是 linux 64位的资料)?

论坛徽章:
0
发表于 2020-05-14 18:42 |显示全部楼层
顶................................................

论坛徽章:
0
发表于 2020-05-15 08:33 |显示全部楼层
有人知道吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP