免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 4660 | 回复: 15
打印 上一主题 下一主题

请教共享库内部的plt调用问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-01-02 09:52 |只看该作者 |倒序浏览
我写了一个简单的共享库,包含两个函数sum()和_sum(),前者调用后者。
编译后的共享库会有一个自己的plt表,在sum()中调用_sum()的地方会翻译成调用plt项。
我的问题是:这条调用plt项的指令在被映射到不同的进程中时,为什么call的地址不同,这部分代码不是共享的吗?

用objdump共享库的显示如下(注意地址4af处call指令,被映射到不同进程后call的地址会不同,为什么?):
Contents of section .got.plt:
1650 74150000 00000000 00000000 4e030000
1660 5e030000 6e030000 7e030000 8e030000

00000378 <_sum@plt>:
378:   jmp    *0x18(%ebx)
37e:   push   $0x18
383:   jmp    338 <_init+0x18>

sum:
a = 1;
48a:   mov    0xfffffff8(%ebx),%eax
490:   movl   $0x1,(%eax)
...
4af:   call   378 <_sum@plt>

我分别编译了两个程序,一个只链接这个库,另一个先链接别的库再链接这个库。目的是为了让这个库在两个进程中映射的地址不同。
然后我用gdb跟踪这两个程序,程序1中该库被映射到地址0x00111000起始位置,程序2中该库被映射到0x00122000起始位置。
然后我把断点设到sum上,运行到断点,然后在gdb中反汇编sum,看到的结果让我非常惊讶:
程序1中,4af处的指令是 call 0x00111378 <_sum@plt>
程序2中,4af处的指令是 call 0x00122378 <_sum@plt>

我很惊讶,这条指令在两个程序中竟然不一样。我们知道共享库的代码在各进程之间是共享的,而sum就是共享库的代码部分,那内容就应该是相同的。难道地址4af前后不是共享的,在各进程中新分配了各自的物理页?

这一点我没有搞明白,向大家请教。

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
2 [报告]
发表于 2009-01-02 10:30 |只看该作者
当然不能一样.
假设每个地址一样,你能不能为1000000000000000个不同的函数库分配各自不同的地址?显然根据抽屉原理,是不可能的,存在两个函数f1,f2地址相同.
写个程序调用f1,f2,导致矛盾.
另外,了解了解什么叫PIC(Position-independent code)

论坛徽章:
0
3 [报告]
发表于 2009-01-02 14:11 |只看该作者
不管是否PIC,问题是call这条指令时被共享的,也就是说内存中只有一份,可是call的操作数(目的地址)在不同的进程中竟然不同,这是怎么实现的?这条指令如果是编定的,那么它的操作数就应该是固定的一个。那现在显示的是不同的,我想知道call的操作数是怎么实现位置无关的。能指示点儿参考资料吗?

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
4 [报告]
发表于 2009-01-02 14:21 |只看该作者
代码被编译为PIC的,但PIC和这个call的地址是什么没有必然直接关系。这个叫符号重定位(relocation)。man elf

论坛徽章:
0
5 [报告]
发表于 2009-01-02 16:09 |只看该作者
原帖由 detian 于 2009-1-2 09:52 发表
我写了一个简单的共享库,包含两个函数sum()和_sum(),前者调用后者。
编译后的共享库会有一个自己的plt表,在sum()中调用_sum()的地方会翻译成调用plt项。
我的问题是:这条调用plt项的指令在被映射到不同的 ...


LZ应该指明自己测试所用的系统平台.

对于有虚拟内存管理的linux系统来讲:
这是正常的.
每个进程都拥有自己的程序地址空间,可以是不同的.
物理空间上共享库可以只有一份,但可以映射到不同的进程地址空间中去, 也就说相同这不同的<_sum@plt>可以通过映射("映射"这个词可能也不恰当)指向同一个物理上的代码段.

比如代码:
code1:

  1. int f()
  2. {
  3.     printf("\r\nhello,world...");
  4.     return(1);
  5. }
  6. int main()
  7. {
  8.    f();
  9.    return(0);
  10. }
复制代码


code2:

  1. int f()
  2. {
  3.     printf("\r\nhello,world...");
  4.     return(1);
  5. }
  6. int main()
  7. {
  8.    int handle;

  9.    handle=open(...);
  10.    f();
  11.    close(handle);
  12.    return(0);
  13. }
复制代码


#gdb a.out
(gdb)disass f
//此处结果大同小异,所以省略...
//.....

两段代码中的call  xxxx<printf@plt> 就可能会不同. 但调用的是同一个printf代码段.

[ 本帖最后由 system888net 于 2009-1-2 16:11 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2009-01-02 16:38 |只看该作者

回复 #5 system888net 的帖子

对于LZ所关心的问题是_sum的地址问题(我理解是这样的,若理解有误的话LZ就可以更正),那么:
xxxx也不会是真正的printf(...), printf的地址(也即printf在动态库中的地址)实际上在stub中第一次运行的时候填入.
同理lZ的程序里call 0x00111378 <_sum@plt>里0x00111378也不是真正的_sum的地址. 真正的_sum地址LZ 可以跟踪进入plt里看到.

[ 本帖最后由 system888net 于 2009-1-2 16:45 编辑 ]

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
7 [报告]
发表于 2009-01-02 16:47 |只看该作者
比如静态库,静态库是目标文件(后缀名为o)的集合,目标文件是可重定位的.
我们可以用file命令,对比如一个33.o
# file 33.o
33.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped

这里的relocatable就说明了它是可重定位的,所谓可重定位就可以地址可以在使用的时候被重新换过.一般是链接器干这件事,根据链接脚本或者自动来选择不同的库内符号的地址。重新调整之后拼在一起成为一个可执行文件出来供使用。

论坛徽章:
0
8 [报告]
发表于 2009-01-02 16:55 |只看该作者
原帖由 cjaizss 于 2009-1-2 16:47 发表
比如静态库,静态库是目标文件(后缀名为o)的集合,目标文件是可重定位的.
我们可以用file命令,对比如一个33.o
# file 33.o
33.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
...


静态库是这样的.

LZ没有说的太很清楚,我理解LZ是在研究动态链接库中函数的地址.

[ 本帖最后由 system888net 于 2009-1-2 16:56 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2009-01-02 21:51 |只看该作者
看例子:
int main()
{
        printf("hello\n");
}



a.out:
08048354 <main>:
8048354:        8d 4c 24 04                  lea    0x4(%esp),%ecx
8048358:        83 e4 f0                     and    $0xfffffff0,%esp
804835b:        ff 71 fc                     pushl  0xfffffffc(%ecx)
804835e:        55                           push   %ebp
804835f:        89 e5                        mov    %esp,%ebp
8048361:        51                           push   %ecx
8048362:        83 ec 04                     sub    $0x4,%esp
8048365:        c7 04 24 58 84 04 08         movl   $0x8048458,(%esp)
804836c:        e8 0b ff ff ff               call   804827c <puts@plt>
8048371:        83 c4 04                     add    $0x4,%esp
8048374:        59                           pop    %ecx
8048375:        5d                           pop    %ebp
8048376:        8d 61 fc                     lea    0xfffffffc(%ecx),%esp
8048379:        c3                           ret   


1、
804836c:        e8 0b ff ff ff               call   804827c <puts@plt>



2、
0804827c <puts@plt>:
804827c:        ff 25 50 95 04 08            jmp    *0x8049550
8048282:        68 00 00 00 00               push   $0x0
8048287:        e9 e0 ff ff ff               jmp    804826c <_init+0x18>
--------------------------------------------------------------------------------------------------------
跳到 [0x8049550]




3、看看 [0x8049550] 是啥:

8049550:        82                           (bad)  
8049551:        82                           (bad)  
8049552:        04 08                        add    $0x8,%al
---------------------------------------------------------------------------------------------

8049550 ~ 8049553  四个字节是: 0x08048282
也就是 jmp 到 0x08048282




4、再看看 0x08048282 处:

804827c:        ff 25 50 95 04 08            jmp    *0x8049550
8048282:        68 00 00 00 00               push   $0x0
8048287:        e9 e0 ff ff ff               jmp    804826c <_init+0x18>
----------------------------------------------------------------------------------------------------
再跳到 0x084826c:


看看 0x084826c:

0804826c <puts@plt-0x10>:
804826c:        ff 35 48 95 04 08            pushl  0x8049548
8048272:        ff 25 4c 95 04 08            jmp    *0x804954c
8048278:        00 00                        add    %al,(%eax)
---------------------------------------------------------------------------------------------------------------
又跳到 [0x084954c]



5、最终去到:

08049544 <_GLOBAL_OFFSET_TABLE_>:
8049544:        78 94                        js     80494da <_DYNAMIC+0x62>
8049546:        04 08                        add    $0x8,%al
        ...
8049550:        82                           (bad)  
8049551:        82                           (bad)  
8049552:        04 08                        add    $0x8,%al
8049554:        92                           xchg   %eax,%edx
8049555:        82                           (bad)  
8049556:        04 08                        add    $0x8,%al
8049558:        a2                           .byte 0xa2
8049559:        82                           (bad)  
804955a:        04 08                        add    $0x8,%al
------------------------------------------------------------------------------------------------------
这是真正的 puts() 函数的入口地方

上面没有列出 0x804954c 处的值




将上面的共享库中的函数调用流程归纳为:

main():---->  <puts@plt>:  -----> <_GLOBAL_OFFSET_TABLE_>: -----> <puts@plt>:  ---> <puts@plt-0x10>:
-----------------------> <_GLOBAL_OFFSET_TABLE_>: ---------> /lib/ld-linux.so.2 ----------> puts()


在 linux 下所有的共享库函数调用流程都是这样:
(1)每个导入的函数生成 PLT 表格
(2)GLOBAL_OFFSET_TABLE 中存放最入动态加载器 ld-linux.so.2 入口
(3)由 ld-linux.so.2 最终动态加载共享函数实体
------------------------------------------------------------------------------
PLT 与 GOT 表是在用户程序代码中生成,/lib/ld-linux.so.2 与 <函数实体> 是在共享库中。

论坛徽章:
0
10 [报告]
发表于 2009-01-16 17:37 |只看该作者
请问  mik 是用什么指令反汇编上面的代码的,我今天试了一下objdump、gdb 都弄不出诸如下面的:
======================
08049544 <_GLOBAL_OFFSET_TABLE_>:
8049544:        78 94                        js     80494da <_DYNAMIC+0x62>
8049546:        04 08                        add    $0x8,%al
======================

的格式,请指点下,给出命令/参数,谢谢:)


原帖由 mik 于 2009-1-2 21:51 发表
看例子:
int main()
{
        printf("hello\n");
}


a.out:
08048354 :
8048354:        8d 4c 24 04                  lea    0x4(%esp),%ecx
8048358:        83 e4 f0                     and    $0xfffffff0,%esp
80 ...
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP