*地址(在printf中找到)在汇编中意味着什么? [英] What does * address(found in printf) mean in assembly?

查看:79
本文介绍了*地址(在printf中找到)在汇编中意味着什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

拆卸 printf 不会提供太多信息:

 ( gdb)disas printf 
函数printf的汇编代码转储:
0x00401b38< printf + 0> ;: jmp * 0x405130
0x00401b3e< printf + 6> ;: nop
0x00401b3f< ; printf + 7> ;: nop
汇编程序转储结束。


(gdb)disa 0x405130
函数_imp__printf的汇编代码转储:
0x00405130< _imp__printf + 0> ;: je 0x405184< _imp__vfprintf + 76>
0x00405132< _imp__printf + 2> ;:添加%al,(%eax)

如何



为什么拆卸无济于事?



<$ c $是什么? c> * 表示 0x405130 之前的意思?

解决方案

至于


在0x405130之前*是什么意思?


我不熟悉gdb的反汇编程序,但是 jmp * 0x405130 似乎是通过指针的间接跳转。而不是拆解0x405130处的内容,您应该在此处转储4个字节的内存。我敢打赌,您会在这里找到另一个地址,如果您拆解那个位置,则会找到 printf()' s代码(反汇编的可读性是另一回事)。



换句话说, _imp__printf 是一个指针到 printf(),而不是 printf()本身。



< hr>

在下面的评论中编辑更多信息后,即可进行编辑:



一小撮利特尔戳戳表明 jmp * 0x405130 是使用Intel汇编语法时 jmp [0x405130] 指令的GAS / AT& T汇编语法。



让我们感到好奇的是,您说gdb命令 x / xw 0x405130 显示该地址包含 0x00005274 (似乎与您拆卸0x405130时得到的内容相匹配)。但是,这意味着 jmp [0x405130] 会尝试跳转到地址 0x00005274 ,这似乎不正确(当您尝试反汇编该地址时,gdb会说很多。



_imp_printf 条目可能正在使用某种懒惰的绑定技术,第一次执行时跳过0x405130,它到达0x00005274地址,这将导致OS捕获陷阱并修复动态链接。修复之后,OS将使用正确的链接地址0x405130重新开始执行。但这只是我的猜测,我不知道您使用的系统是否执行了这样的操作(实际上,我什至不知道您正在运行的系统),但这在技术上是可行的。像这样的情况,直到第一次调用 printf()后,您才会在0x405130中看到正确的地址。



我认为您需要单步执行对 printf()




通过GDB会话更新的信息:



这是您遇到的问题-您正在查看系统加载DLL并修复与DLL的链接之前的过程。这是一个简单的 hello world程序的调试会话,该程序是用GGW调试的MinGW编译的:

  C:\temp> \ \mingw\bin\gdb test.exe 
GNU gdb(GDB)7.1
版权所有(C)2010 Free Software Foundation,Inc.
许可证GPLv3 +:GNU GPL版本3或更高版本< ; http://gnu.org/licenses/gpl.html>
这是免费软件:您可以自由更改和重新分发它。
在法律允许的范围内,没有担保。输入显示复制
和显示保修以获取详细信息。
此GDB被配置为 mingw32。
有关错误报告的说明,请参阅:
< http://www.gnu.org/software/gdb/bugs/> ...
从C:\读取符号temp / test.exe ...完成。

(gdb)disas main
函数main的汇编代码转储:
0x004012f0< + 0> ;:推送%ebp
0x004012f1< + 1> ;: mov%esp,%ebp
0x004012f3< + 3> ;: sub $ 0x8,%esp
0x004012f6< + 6> ;:和$ 0xfffffff0,%esp
0x004012f9< + 9> :mov $ 0x0,%eax
0x004012fe< + 14> ;:添加$ 0xf,%eax
0x00401301< + 17> ;:添加$ 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> ;:调用0x401850< _alloca>
0x00401315< + 37> ;:调用0x4013d0< __ main>
0x0040131a< + 42> ;: movl $ 0x403000,(%esp)
0x00401321< + 49> ;:呼叫0x4018b0< printf>
0x00401326< + 54> ;: mov $ 0x0,%eax
0x0040132b< + 59> ;:离开
0x0040132c< + 60> ;: ret
汇编器转储结束。

请注意,反汇编 printf()会导致类似的间接跳转:

 (gdb)disas printf 
函数printf的汇编代码转储:
0x004018b0< + 0> ;: jmp * 0x4050f8; <-间接跳转
0x004018b6< + 6> ;: nop
0x004018b7< + 7> ;: nop
汇编器转储结束。

而且 _imp__printf symbiol毫无意义作为代码...

 (gdb)disas 0x4050f8 
函数_imp__printf的汇编代码转储:
0x004050f8< + 0> ;: clc; <<-怎么可能是printf()?
0x004050f9 +1:推送%ecx
0x004050fa <+2>:添加%al,(%eax)
汇编器转储结束。

或作为指针...

 (gdb)x / xw 0x4050f8 
0x4050f8< _imp__printf> ;: 0x000051f8; <<-0x000051f8是无效的指针

现在,让我们在<$ c处设置一个断点$ c> main(),并运行到它:

 (gdb)断开主要
0x40131a处的断点1:文件c:/temp/test.c,第5行。

(gdb)运行
启动程序:C:\temp / test.exe
[新线程11204.0x2bc8]
映射共享库部分时出错:
C:\WINDOWS\SysWOW64\ntdll32.dll:没有此类文件或目录。

断点1,main()at c:/temp/test.c:5
5 printf( hello world\n);

printf()看起来相同:

 (gdb)disas printf 
函数printf的汇编代码转储:
0x004018b0< + 0> :jmp * 0x4050f8
0x004018b6< + 6> ;: nop
0x004018b7< + 7> ;: nop
汇编器转储的结尾。

_imp__printf 看起来有所不同-动态链接现在已修复:

 (gdb)x / xw 0x4050f8 
0x4050f8< _imp__printf> ;: 0x77bd27c2

如果我们反汇编 _imp__printf 现在指向的内容,它的可读性可能不高,但显然现在是代码。这是在MSVCRT.DLL中实现的 printf()

 ( gdb)disas _imp__printf 
函数printf的汇编代码转储:
0x77bd27c2< + 0> ;:推送$ 0x10
0x77bd27c4< + 2> ;:推送$ 0x77ba4770
0x77bd27c9< ; + 7> ;:呼叫0x77bc84c4< strerror + 554>
0x77bd27ce< + 12> ;:移动$ 0x77bf1cc8,%esi
0x77bd27d3< + 17> ;:推送%esi
0x77bd27d4< + 18> ;:推送$ 0x1
0x77bd276 < + 20> ;:呼叫0x77bcca49< msvcrt!_lock + 4816>
0x77bd27db< + 25> ;: pop%ecx
0x77bd27dc< + 26> ;: pop%ecx
0x77bd27dd< + 27> ;: andl $ 0x0,-0x4(%ebp)
0x77bd27e1< + 31> ;:推送%esi
0x77bd27e2< + 32> ;:呼叫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> ;:呼叫0x77bd3330< ; wscanf + 251>
0x77bd27f7< + 53> ;: mov%eax,-0x20(%ebp)
0x77bd27fa< 56> ;: push%esi
0x77bd27fb< + 57> ;: pushl -0x1c( %ebp)
0x77bd27fe< + 60> ;:呼叫0x77bd4099< wscanf + 3684>
0x77bd2803< + 65> ;:添加$ 0x18,%esp
0x77bd2806< + 68> ;: orl $ 0xffffffff,-0x4(%ebp)
0x77bd280a< + 72> ;:通话0x77bd281d< printf + 91>
0x77bd280f< + 77> ;: mov -0x20(%ebp),%eax
0x77bd2812< 80> ;:呼叫0x77bc84ff< strerror + 613>
0x77bd2817< + 85> ;: ret
0x77bd2818< + 86> ;: mov $ 0x77bf1cc8,%esi
0x77bd281d< + 91> ;:推送%esi
0x77bd281e< + 92> ;:推送$ 0x1
0x77bd2820< + 94> ;:呼叫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
汇编器转储结束。

可能比您希望的要难读,因为我不确定是否可以使用合适的符号



但是,您通常可以通过编译器获得C运行时例程的源代码,无论是否为开源。 MinGW没有附带MSVDRT.DLL的源代码,因为这是Windows的东西,但是您可以在Visual Studio发行版中获得它的源代码(或接近它的东西)-我认为即使免费的 VC ++ Express 随运行时源一起提供(但我对此可能有误)。 / p>

Disassembling printf doesn't give much info:

(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)

How is it implemented under the hood?

Why disassembling doesn't help?

What does * mean before 0x405130?

解决方案

As for

What does * mean before 0x405130?

I'm not familiar with gdb's disassembler, but it looks like the jmp *0x405130 is an indirect jump through a pointer. Instead of disassembling what's at 0x405130 you should dump the 4 bytes of memory there. I'd be willing to bet that you'll find another address there, and if you disassemble that location you'll find printf()'s code (how readable that disassembly might be is another story).

In other words, _imp__printf is a pointer to printf(), not printf() itself.


Edit from after more information in the comments below:

A litle poking around indicates that jmp *0x405130 is the GAS/AT&T assembly syntax for jmp [0x405130] instruction when using the Intel assembly syntax.

What makes this curious is that you say that the gdb command x/xw 0x405130 shows that that address contains 0x00005274 (which seems to match up with what you got when you disassembled 0x405130). However, that would mean that jmp [0x405130] would try to jump to address 0x00005274, which doesn't seem right (and gdb said as much when you tried to disassemble that address.

It's possible that the _imp_printf entry is using some sort of lazy binding technique where the first time execution jumps through 0x405130, it hits the 0x00005274 address which causes the OS to field a trap and fixup the dynamic link. After the fixup, the OS will restart execution with the correct link address in 0x405130. But this is sheer guesswork on my part. I have no idea if the system you're using does anything like this (indeed, I don't even know what system you're running on), but it's technically possible. If something like this is going on, you won't see the correct address in 0x405130 until after the first call to printf() has been made.

I think you'll need to single step through a call to printf() at the assembly level to see what's really going on.


Updated information with a GDB session:

Here's the problem you're running into - you're looking at the process before the system has loaded DLLs and fixed up the linkages to the DLLs. Here's a debugging session of a simple "hello world" program compiled with MinGW debugged with GDB:

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.

Note that disassembling printf() leads to a similar indirect jump:

(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.

And that the _imp__printf symbiol makes no sense as code...

(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.

or as a pointer...

(gdb) x/xw 0x4050f8
0x4050f8 <_imp__printf>:        0x000051f8  ; <<-- 0x000051f8 is an invalid pointer

Now, let's set a breakpoint at main(), and run to it:

(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() looks the same:

(gdb) disas printf
Dump of assembler code for function printf:
   0x004018b0 <+0>:     jmp    *0x4050f8
   0x004018b6 <+6>:     nop
   0x004018b7 <+7>:     nop
End of assembler dump.

but _imp__printf looks different - the dynamic link has now been fixed up:

(gdb) x/xw 0x4050f8
0x4050f8 <_imp__printf>:        0x77bd27c2

And if we disassemble what _imp__printf is now pointing to, it might not be very readable, but clearly it's code now. This is printf() as implemented in 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.

It's probably harder to read than you might hope because I'm not sure if proper symbols are available for it (or whether GDB can properly read those symbols).

However, as I mentioned in another answer, you can get typically get the source for C runtime routines with your compiler, whether open source or not. MinGW doesn't come with the source for MSVDRT.DLL since that's a Windows thing, but you can get the source for it (or something pretty close to it) in a Visual Studio distribution - I think that even the free VC++ Express comes with runtime source (but I might be wrong about that).

这篇关于*地址(在printf中找到)在汇编中意味着什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆