关于linux共享库内部的plt调用的说法

发布于 2022-09-23 13:56:47 字数 11274 浏览 21 评论 0

因为有人讨论起linux的共享库的函数调用地址的问题,为了能简单的进行探讨,特就两段简单的代码进行比较来说明linux下plt的一写简单特点:
testdll.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <fcntl.h>
  4. char buffer[100];
  5. int main()
  6. {
  7.    int handle;
  8.    handle=open("myfile",O_RDONLY);
  9.    close(handle);
  10.    return(0);
  11. }

复制代码

testdll2.c

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <fcntl.h>
  4. char buffer[100];
  5. int main()
  6. {
  7.    int handle;
  8.    printf("hello! world");
  9.    
  10.    handle=open("myfile",O_RDONLY);
  11.    close(handle);
  12.    return(0);
  13. }

复制代码

[root@localhost test]# gdb testdll
GNU gdb Red Hat Linux (6.5-25.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/i686/nosegneg/libthread_db.so.1".

(gdb) b main
Breakpoint 1 at 0x80483c5: file testdll.c, line 12.
(gdb) r
Starting program: /test/testdll

Breakpoint 1, main () at testdll.c:12
12         handle=open("myfile",O_RDONLY);
(gdb) disass main
Dump of assembler code for function main:
0x080483b4 <main+0>:    lea    0x4(%esp),%ecx
0x080483b8 <main+4>:    and    $0xfffffff0,%esp
0x080483bb <main+7>:    pushl  0xfffffffc(%ecx)
0x080483be <main+10>:   push   %ebp
0x080483bf <main+11>:   mov    %esp,%ebp
0x080483c1 <main+13>:   push   %ecx
0x080483c2 <main+14>:   sub    $0x24,%esp
0x080483c5 <main+17>:   movl   $0x0,0x4(%esp)
0x080483cd <main+25>:   movl   $0x80484d0,(%esp)
0x080483d4 <main+32>:   call   0x8048294 <open@plt>
0x080483d9 <main+37>:   mov    %eax,0xfffffff8(%ebp)
0x080483dc <main+40>:   mov    0xfffffff8(%ebp),%eax
0x080483df <main+43>:   mov    %eax,(%esp)
0x080483e2 <main+46>:   call   0x80482c4 <close@plt>
0x080483e7 <main+51>:   mov    $0x0,%eax
0x080483ec <main+56>:   add    $0x24,%esp
0x080483ef <main+59>:   pop    %ecx
0x080483f0 <main+60>:   pop    %ebp
0x080483f1 <main+61>:   lea    0xfffffffc(%ecx),%esp
0x080483f4 <main+64>:   ret   
End of assembler dump.
(gdb) n
13         close(handle);
(gdb) disass main
Dump of assembler code for function main:
0x080483b4 <main+0>:    lea    0x4(%esp),%ecx
0x080483b8 <main+4>:    and    $0xfffffff0,%esp
0x080483bb <main+7>:    pushl  0xfffffffc(%ecx)
0x080483be <main+10>:   push   %ebp
0x080483bf <main+11>:   mov    %esp,%ebp
0x080483c1 <main+13>:   push   %ecx
0x080483c2 <main+14>:   sub    $0x24,%esp
0x080483c5 <main+17>:   movl   $0x0,0x4(%esp)
0x080483cd <main+25>:   movl   $0x80484d0,(%esp)
0x080483d4 <main+32>:   call   0x8048294 <open@plt>   //调用open,这个地址不是真正的open地址
0x080483d9 <main+37>:   mov    %eax,0xfffffff8(%ebp)
0x080483dc <main+40>:   mov    0xfffffff8(%ebp),%eax
0x080483df <main+43>:   mov    %eax,(%esp)
0x080483e2 <main+46>:   call   0x80482c4 <close@plt>
0x080483e7 <main+51>:   mov    $0x0,%eax
0x080483ec <main+56>:   add    $0x24,%esp
0x080483ef <main+59>:   pop    %ecx
0x080483f0 <main+60>:   pop    %ebp
0x080483f1 <main+61>:   lea    0xfffffffc(%ecx),%esp
0x080483f4 <main+64>:   ret   
End of assembler dump.
(gdb) disass 0x8048294
Dump of assembler code for function open@plt:
0x08048294 <open@plt+0>:        jmp    *0x80495c8
0x0804829a <open@plt+6>:        push   $0x0
0x0804829f <open@plt+11>:       jmp    0x8048284
End of assembler dump.
(gdb) x 0x80495c8
0x80495c8 <_GLOBAL_OFFSET_TABLE_+12>:   0x0090cf20   //open函数的地址
(gdb)

gdb testdll2
GNU gdb Red Hat Linux (6.5-25.el5rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/i686/nosegneg/libthread_db.so.1".

(gdb) b main
Breakpoint 1 at 0x80483f5: file testdll.c, line 10.
(gdb) r
Starting program: /testdll2

Breakpoint 1, main () at testdll.c:10
10         printf("hello! world");
(gdb) disass main
Dump of assembler code for function main:
0x080483e4 <main+0>:    lea    0x4(%esp),%ecx
0x080483e8 <main+4>:    and    $0xfffffff0,%esp
0x080483eb <main+7>:    pushl  0xfffffffc(%ecx)
0x080483ee <main+10>:   push   %ebp
0x080483ef <main+11>:   mov    %esp,%ebp
0x080483f1 <main+13>:   push   %ecx
0x080483f2 <main+14>:   sub    $0x24,%esp
0x080483f5 <main+17>:   movl   $0x8048510,(%esp)
0x080483fc <main+24>:   call   0x80482e8 <printf@plt>
0x08048401 <main+29>:   movl   $0x0,0x4(%esp)
0x08048409 <main+37>:   movl   $0x804851d,(%esp)
0x08048410 <main+44>:   call   0x80482b8 <open@plt>   //调用open,这个地址不是真正的open地址
0x08048415 <main+49>:   mov    %eax,0xfffffff8(%ebp)
0x08048418 <main+52>:   mov    0xfffffff8(%ebp),%eax
0x0804841b <main+55>:   mov    %eax,(%esp)
0x0804841e <main+58>:   call   0x80482f8 <close@plt>
0x08048423 <main+63>:   mov    $0x0,%eax
0x08048428 <main+68>:   add    $0x24,%esp
0x0804842b <main+71>:   pop    %ecx
0x0804842c <main+72>:   pop    %ebp
0x0804842d <main+73>:   lea    0xfffffffc(%ecx),%esp
0x08048430 <main+76>:   ret   
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
(gdb) n
12         handle=open("myfile",O_RDONLY);
(gdb) n
13         close(handle);
(gdb) disass main
Dump of assembler code for function main:
0x080483e4 <main+0>:    lea    0x4(%esp),%ecx
0x080483e8 <main+4>:    and    $0xfffffff0,%esp
0x080483eb <main+7>:    pushl  0xfffffffc(%ecx)
0x080483ee <main+10>:   push   %ebp
0x080483ef <main+11>:   mov    %esp,%ebp
0x080483f1 <main+13>:   push   %ecx
0x080483f2 <main+14>:   sub    $0x24,%esp
0x080483f5 <main+17>:   movl   $0x8048510,(%esp)
0x080483fc <main+24>:   call   0x80482e8 <printf@plt>
0x08048401 <main+29>:   movl   $0x0,0x4(%esp)
0x08048409 <main+37>:   movl   $0x804851d,(%esp)
0x08048410 <main+44>:   call   0x80482b8 <open@plt>
0x08048415 <main+49>:   mov    %eax,0xfffffff8(%ebp)
0x08048418 <main+52>:   mov    0xfffffff8(%ebp),%eax
0x0804841b <main+55>:   mov    %eax,(%esp)
0x0804841e <main+58>:   call   0x80482f8 <close@plt>
0x08048423 <main+63>:   mov    $0x0,%eax
0x08048428 <main+68>:   add    $0x24,%esp
0x0804842b <main+71>:   pop    %ecx
0x0804842c <main+72>:   pop    %ebp
0x0804842d <main+73>:   lea    0xfffffffc(%ecx),%esp
0x08048430 <main+76>:   ret   
---Type <return> to continue, or q <return> to quit---disass 80482b8
End of assembler dump.
(gdb) disass 0x80482b8
Dump of assembler code for function open@plt:
0x080482b8 <open@plt+0>:        jmp    *0x8049614
0x080482be <open@plt+6>:        push   $0x0
0x080482c3 <open@plt+11>:       jmp    0x80482a8
End of assembler dump.
(gdb) x 0x8049614
0x8049614 <_GLOBAL_OFFSET_TABLE_+12>:   0x0090cf20   //open函数的地址
(gdb)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

╰沐子 2022-09-30 13:56:47

在testdll.c中
0x080483d4 <main+32>:   call   0x8048294 <open@plt>

0x08048294 <open@plt+0>:        jmp    *0x80495c8
0x0804829a <open@plt+6>:        push   $0x0
0x0804829f <open@plt+11>:       jmp    0x8048284

(gdb) x 0x80495c8
0x80495c8 <_GLOBAL_OFFSET_TABLE_+12>:   0x0090cf20
open@plt在0x080483d4地址处,而真正的open地址在0x80495c8处(从jmp *0x80495c8可以的出), 可以看到0x080495c8地址处的是0x0090cf20这是指向了真正open的映射.

在testdll2.c中
0x08048410 <main+44>:   call   0x80482b8 <open@plt>

0x080482b8 <open@plt+0>:        jmp    *0x8049614
0x080482be <open@plt+6>:        push   $0x0
0x080482c3 <open@plt+11>:       jmp    0x80482a8

(gdb) x 0x8049614
0x8049614 <_GLOBAL_OFFSET_TABLE_+12>:   0x0090cf20
open@plt在0x080482b8地址处,而真正的open地址在0x8049614处(从jmp *0x8049614可以的出), 可以看到0x8049614地址处的是0x0090cf20这是指向了真正open的映射.

需要说明的是0x8049614处的值在程序(这里是testdll2)运行第一此调用open的时候由stub程序修改为实际指向open的地址.  而stub程序就是

  1. 0x080482b8 <open@plt+0>:        jmp    *0x8049614
  2. 0x080482be <open@plt+6>:        push   $0x0
  3. 0x080482c3 <open@plt+11>:       jmp    0x80482a8

复制代码
开始的这段代码,当第一此修改0x8049614的值后,以后由于jmp    *0x8049614直接可以访问到open函数,因此加快了访问速度.

愛放△進行李 2022-09-30 13:56:47

为了证实stub程序是否修改jmp *xxxx中xxxx处的值,我们继续看没有运行到的close@plt

  1. 0x0804841e <main+58>:   call   0x80482f8 <close@plt>

复制代码

(gdb) disass 0x80482f8
Dump of assembler code for function close@plt:
0x080482f8 <close@plt+0>:       jmp    *0x8049624
0x080482fe <close@plt+6>:       push   $0x20
0x08048303 <close@plt+11>:      jmp    0x80482a8
End of assembler dump.
(gdb) x 0x8049624
0x8049624 <_GLOBAL_OFFSET_TABLE_+28>:   0x080482fe
(gdb)
如上大家看到的jmp    *0x8049624 中 *0x8049624实际上就是0x080482fe,也就是一个没有指向close的地址,这个地址需要stub程序去填写.

℉服软 2022-09-30 13:56:47

当call   0x80482f8 <close@plt>完成后
(gdb) x 0x8049624
0x8049624 <_GLOBAL_OFFSET_TABLE_+28>:   0x0090d5a0
(gdb)

此处的值已经被修改了。

山川志 2022-09-30 13:56:47

原帖由 system888net 于 2009-1-2 19:48 发表
在testdll.c中
0x080483d4 <main+32>:   call   0x8048294 <open@plt>

0x08048294 <open@plt+0>:        jmp    *0x80495c8
0x0804829a <open@plt+6>:        push   $0x0
0x0804829f <open@plt+11>:       jmp    0x8048284

(gdb) x 0x80495c8
0x80495c8 <_GLOBAL_OFFSET_TABLE_+12>:   0x0090cf20
open@plt在0x080483d4地址处,而真正的open地址在0x80495c8处(从jmp *0x80495c8可以的出), 可以看到0x080495c8地址处的是0x0090cf20这是指向了真正open的映射.    ...

jmp *0x80495c8 这条语句应该是来到 0x0804829a 才对

(gdb) x 0x80495c8
应该得到值为 0x0804829a 才对

>>> 不知道你这样的 0x0090cf20 是怎么得来的????

需要说明的是0x8049614处的值在程序(这里是testdll2)运行第一此调用open的时候由stub程序修改为实际指向open的地址.  而stub程序就是

[Copy to clipboard] [ - ]CODE:
0x080482b8 <open@plt+0>:        jmp    *0x8049614
0x080482be <open@plt+6>:        push   $0x0
0x080482c3 <open@plt+11>:       jmp    0x80482a8
开始的这段代码,当第一此修改0x8049614的值后,以后由于jmp    *0x8049614直接可以访问到open函数,因此加快了访问速度.

这个解释毫不靠谱!!

吝吻 2022-09-30 13:56:47

原帖由 mik 于 2009-1-2 22:30 发表

jmp *0x80495c8 这条语句应该是来到 0x0804829a 才对

(gdb) x 0x80495c8
应该得到值为 0x0804829a 才对

>>> 不知道你这样的 0x0090cf20 是怎么得来的????

这个解释毫不靠谱!!

对于没有运行到open@plt处之前是0x0804829a,一旦第一次open@plt的调用后,那么 0x80495c8的值就被修改了(比如0x0090cf20),这是为了效率的考虑,避免了第二次相同的调用再load。

⒈起吃苦の倖褔 2022-09-30 13:56:47

原帖由 system888net 于 2009-1-4 12:14 发表

对于没有运行到open@plt处之前是0x0804829a,一旦第一次open@plt的调用后,那么 0x80495c8的值就被修改了(比如0x0090cf20),这是为了效率的考虑,避免了第二次相同的调用再load。

嗯,或许你是对的,我没有 gdb 运行过

乖乖 2022-09-30 13:56:47

原帖由 system888net 于 2009-1-4 12:14 发表

对于没有运行到open@plt处之前是0x0804829a,一旦第一次open@plt的调用后,那么 0x80495c8的值就被修改了(比如0x0090cf20),这是为了效率的考虑,避免了第二次相同的调用再load。

呵呵,正是这样的

倾城花音 2022-09-30 13:56:47

谢谢楼上两位大拿捧场!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文