反汇编printf
没有提供太多信息:
(gdb) disas printf
Dump of assembler code for function printf:
0x00401b38 <printf+0>: jmp *0x405130
0x00401b3e <printf+6>: nop
0x00401b3f <printf+7>: nop
End of assembler dump.
(gdb) disas 0x405130
Dump of assembler code for function _imp__printf:
0x00405130 <_imp__printf+0>: je 0x405184 <_imp__vfprintf+76>
0x00405132 <_imp__printf+2>: add %al,(%eax)
如何在引擎盖下实施?
为什么反汇编没有帮助?
*
之前0x405130
的含义是什么?
答案 0 :(得分:8)
以下是一个特定的实现,http://ftp.fr.openbsd.org/pub/OpenBSD/src/lib/libc/stdio/printf.c和http://ftp.fr.openbsd.org/pub/OpenBSD/src/lib/libc/stdio/vfprintf.c
答案 1 :(得分:3)
*
是用于间接内存引用的AT&amp; T汇编语法。即
jmp *<addr>
表示“跳转到<addr>
”中存储的地址。
它等同于以下Intel语法:
jmp [addr]
使用寄存器或存储器操作数的分支寻址必须以'*'
作为前缀
答案 2 :(得分:2)
几乎所有C编译器都为源提供了运行时库 - 而不仅仅是开源编译器。不幸的是,它们通常以难以遵循的形式编写,并且通常不附带设计原理文档。
因此,处理该问题的一个非常好的资源是P.J. Plauger's "The Standard C Library",它不仅提供了库实现的源,而且还详细说明了它的设计方式以及这种库可能具有的特殊情况。考虑
以提供本书的某些“使用”版本的价格为准,这应该是任何严肃的C程序员的书架。
Plauger有类似的书籍,目标是我认为具有类似价值的C ++库:
答案 3 :(得分:1)
我认为拆解工作在这里工作得很好,并且printf在这里使用vfprintf实现'引擎盖',这几乎是你所期望的。请注意,汇编程序通常比C更冗长,并且需要花费时间来理解您没有注释源的位置。编译器输出也不是教你自己汇编程序的好方法。
答案 4 :(得分:1)
至于
在0x405130之前*的含义是什么?
我不熟悉gdb的反汇编程序,但看起来jmp *0x405130
是间接跳过指针。而不是拆解0x405130处的内容,你应该在那里转储4个字节的内存。我愿意打赌你会在那里找到另一个地址,如果你反汇编那个位置,你会发现printf()
的代码(反汇编的可读性是另一个故事)。
换句话说,_imp__printf
是指向printf()
的指针,而不是printf()
本身。
根据以下评论中的更多信息进行编辑:
使用英特尔汇编语法时,jmp *0x405130
表示jmp [0x405130]
是x/xw 0x405130
指令的GAS / AT&amp; T汇编语法。
令人感到奇怪的是,你说gdb命令0x00005274
显示该地址包含jmp [0x405130]
(这似乎与你在反汇编0x405130时得到的内容相匹配)。但是,这意味着0x00005274
会尝试跳转到地址_imp_printf
,这似乎不正确(当您尝试反汇编该地址时,gdb也会这么说。
printf()
条目可能正在使用某种延迟绑定技术,其中第一次执行跳转到0x405130,它命中0x00005274地址,这导致操作系统记录陷阱并修复动态链接。修复后,操作系统将使用0x405130中的正确链接地址重新启动执行。但这只是我的猜测。我不知道你使用的系统是否做了这样的事情(事实上,我甚至不知道你在运行什么系统),但这在技术上是可行的。如果发生类似这样的事情,在第一次调用printf()
之前,您将无法在0x405130中看到正确的地址。
我认为你需要在汇编级别单步调用C:\temp>\mingw\bin\gdb test.exe
GNU gdb (GDB) 7.1
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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 "mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from C:\temp/test.exe...done.
(gdb) disas main
Dump of assembler code for function main:
0x004012f0 <+0>: push %ebp
0x004012f1 <+1>: mov %esp,%ebp
0x004012f3 <+3>: sub $0x8,%esp
0x004012f6 <+6>: and $0xfffffff0,%esp
0x004012f9 <+9>: mov $0x0,%eax
0x004012fe <+14>: add $0xf,%eax
0x00401301 <+17>: add $0xf,%eax
0x00401304 <+20>: shr $0x4,%eax
0x00401307 <+23>: shl $0x4,%eax
0x0040130a <+26>: mov %eax,-0x4(%ebp)
0x0040130d <+29>: mov -0x4(%ebp),%eax
0x00401310 <+32>: call 0x401850 <_alloca>
0x00401315 <+37>: call 0x4013d0 <__main>
0x0040131a <+42>: movl $0x403000,(%esp)
0x00401321 <+49>: call 0x4018b0 <printf>
0x00401326 <+54>: mov $0x0,%eax
0x0040132b <+59>: leave
0x0040132c <+60>: ret
End of assembler dump.
来查看实际情况。
使用GDB会话更新了信息:
这是您遇到的问题 - 您在系统加载DLL并修复了与DLL的链接之前查看了该过程。这是使用GDB调试的MinGW编译的简单“hello world”程序的调试会话:
printf()
请注意,反汇编(gdb) disas printf
Dump of assembler code for function printf:
0x004018b0 <+0>: jmp *0x4050f8 ; <<-- indirect jump
0x004018b6 <+6>: nop
0x004018b7 <+7>: nop
End of assembler dump.
会导致类似的间接跳转:
_imp__printf
并且(gdb) disas 0x4050f8
Dump of assembler code for function _imp__printf:
0x004050f8 <+0>: clc ; <<-- how can this be printf()?
0x004050f9 <+1>: push %ecx
0x004050fa <+2>: add %al,(%eax)
End of assembler dump.
symbiol作为代码没有任何意义......
(gdb) x/xw 0x4050f8
0x4050f8 <_imp__printf>: 0x000051f8 ; <<-- 0x000051f8 is an invalid pointer
或作为指针...
main()
现在,让我们在(gdb) break main
Breakpoint 1 at 0x40131a: file c:/temp/test.c, line 5.
(gdb) run
Starting program: C:\temp/test.exe
[New Thread 11204.0x2bc8]
Error while mapping shared library sections:
C:\WINDOWS\SysWOW64\ntdll32.dll: No such file or directory.
Breakpoint 1, main () at c:/temp/test.c:5
5 printf( "hello world\n");
设置一个断点,并运行到它:
printf()
(gdb) disas printf
Dump of assembler code for function printf:
0x004018b0 <+0>: jmp *0x4050f8
0x004018b6 <+6>: nop
0x004018b7 <+7>: nop
End of assembler dump.
看起来一样:
_imp__printf
但(gdb) x/xw 0x4050f8
0x4050f8 <_imp__printf>: 0x77bd27c2
看起来不同 - 动态链接现已修复:
_imp__printf
如果我们反汇编printf()
现在指向的内容,它可能不是非常易读,但显然它现在是代码。这是在MSVCRT.DLL中实现的(gdb) disas _imp__printf
Dump of assembler code for function printf:
0x77bd27c2 <+0>: push $0x10
0x77bd27c4 <+2>: push $0x77ba4770
0x77bd27c9 <+7>: call 0x77bc84c4 <strerror+554>
0x77bd27ce <+12>: mov $0x77bf1cc8,%esi
0x77bd27d3 <+17>: push %esi
0x77bd27d4 <+18>: push $0x1
0x77bd27d6 <+20>: call 0x77bcca49 <msvcrt!_lock+4816>
0x77bd27db <+25>: pop %ecx
0x77bd27dc <+26>: pop %ecx
0x77bd27dd <+27>: andl $0x0,-0x4(%ebp)
0x77bd27e1 <+31>: push %esi
0x77bd27e2 <+32>: call 0x77bd400d <wscanf+3544>
0x77bd27e7 <+37>: mov %eax,-0x1c(%ebp)
0x77bd27ea <+40>: lea 0xc(%ebp),%eax
0x77bd27ed <+43>: push %eax
0x77bd27ee <+44>: pushl 0x8(%ebp)
0x77bd27f1 <+47>: push %esi
0x77bd27f2 <+48>: call 0x77bd3330 <wscanf+251>
0x77bd27f7 <+53>: mov %eax,-0x20(%ebp)
0x77bd27fa <+56>: push %esi
0x77bd27fb <+57>: pushl -0x1c(%ebp)
0x77bd27fe <+60>: call 0x77bd4099 <wscanf+3684>
0x77bd2803 <+65>: add $0x18,%esp
0x77bd2806 <+68>: orl $0xffffffff,-0x4(%ebp)
0x77bd280a <+72>: call 0x77bd281d <printf+91>
0x77bd280f <+77>: mov -0x20(%ebp),%eax
0x77bd2812 <+80>: call 0x77bc84ff <strerror+613>
0x77bd2817 <+85>: ret
0x77bd2818 <+86>: mov $0x77bf1cc8,%esi
0x77bd281d <+91>: push %esi
0x77bd281e <+92>: push $0x1
0x77bd2820 <+94>: call 0x77bccab0 <msvcrt!_lock+4919>
0x77bd2825 <+99>: pop %ecx
0x77bd2826 <+100>: pop %ecx
0x77bd2827 <+101>: ret
0x77bd2828 <+102>: int3
0x77bd2829 <+103>: int3
0x77bd282a <+104>: int3
0x77bd282b <+105>: int3
0x77bd282c <+106>: int3
End of assembler dump.
:
{{1}}
它可能比您希望的更难阅读,因为我不确定它是否有适当的符号(或者GDB是否可以正确读取这些符号)。
但是,as I mentioned in another answer,您通常可以使用编译器获取C运行时例程的源代码,无论是否为开源代码。 MinGW没有附带MSVDRT.DLL的源代码,因为那是一个Windows的东西,但你可以在Visual Studio发行版中获取它的源代码(或者非常接近它的东西) - 我认为即使是免费的{{3}运行时来源(但我可能错了)。
答案 5 :(得分:0)
printf()
很可能位于动态共享库中。
动态链接器使用导入函数的地址填充表;这就是你必须进行间接呼叫的原因。
我真的不记得这是如何运作的;优化可能会使流程复杂化。 但是你明白了。