簡體   English   中英

*地址(在printf中找到)在匯編中意味着什么?

[英]What does * address(found in printf) mean in assembly?

拆解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之前*含義是什么?

*是用於間接內存引用的AT&T匯編語法。

jmp *<addr>

表示“跳轉到存儲在<addr>中的<addr> ”。

它等效於以下Intel語法:

jmp [addr]

使用寄存器或存儲器操作數的分支尋址必須以'*'為前綴

資源

實際上,所有C編譯器都為源提供了運行時庫 - 而不僅僅是開源編譯器。 不幸的是,它們通常以難以遵循的形式編寫,並且通常不帶有設計原理文檔。

因此,處理該問題的一個非常好的資源是PJ Plauger的“標准C庫” ,它不僅提供了庫實現的源,而且還詳細說明了它的設計方式以及這種庫可能具有的特殊情況。考慮。

按照本書的某些“使用”版本的價格,這是一個竊取,應該在任何嚴肅的C程序員的書架上。

Plauger有類似的書籍,目標是我認為具有類似價值的C ++庫:

我會說拆解工作在這里很好,並且printf是在引擎蓋下使用vfprintf實現的,這幾乎是你所期望的。 請注意,匯編程序通常比C更冗長,並且需要花費時間來理解您沒有注釋源的位置。 編譯器輸出也不是教你自己匯編器的好方法。

至於

在0x405130之前*的含義是什么?

我不熟悉gdb的反匯編程序,但看起來jmp *0x405130是間接跳過指針。 而不是拆解0x405130處的內容,你應該在那里轉儲4個字節的內存。 我願意打賭你會在那里找到另一個地址,如果你拆開那個位置,你會發現printf()的代碼(反匯編的可讀性是另一個故事)。

換句話說, _imp__printf是指向printf()的指針,而不是printf()本身。


根據以下評論中的更多信息進行編輯:

在使用英特爾匯編語法時, jmp *0x405130jmp [0x405130]指令的GAS / AT&T匯編語法。

令你好奇的是你說gdb命令x/xw 0x405130顯示該地址包含0x00005274 (這似乎與你在反匯編0x405130時得到的相匹配)。 但是,這意味着jmp [0x405130]會嘗試跳轉到地址0x00005274 ,這似乎不正確(當你試圖反匯編該地址時,gdb 0x00005274說。

_imp_printf條目可能使用某種延遲綁定技術,其中第一次執行跳轉到0x405130,它命中0x00005274地址,這導致操作系統記錄陷阱並修復動態鏈接。 修復后,操作系統將使用0x405130中的正確鏈接地址重新啟動執行。 但這只是我的猜測。 我不知道你使用的系統是否做了這樣的事情(事實上,我甚至不知道你在運行什么系統),但這在技術上是可行的。 如果發生類似這樣的事情,則在第一次調用printf()之后,才會在0x405130中看到正確的地址。

我認為你需要在程序集層面單步調用printf()來查看真正發生的事情。


使用GDB會話更新了信息:

這是您遇到的問題 - 您在系統加載DLL之前查看了該過程並修復了與DLL的鏈接。 這是使用GDB調試的MinGW編譯的簡單“hello world”程序的調試會話:

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.

請注意,反匯編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 symbiol作為代碼毫無意義......

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

或作為指針......

(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現在指向的東西,它可能不是很可讀,但現在顯然它是代碼。 這是在MSVCRT.DLL中實現的printf()

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

它可能比您希望的更難閱讀,因為我不確定它是否有適當的符號(或者GDB是否可以正確讀取這些符號)。

但是, 正如我在另一個答案中提到的 ,您通常可以使用編譯器獲取C運行時例程的源代碼,無論是否為開源代碼。 MinGW沒有附帶MSVDRT.DLL的源代碼,因為那是一個Windows的東西,但你可以在Visual Studio發行版中獲得它的源代碼(或者它非常接近它) - 我認為即使是免費的VC ++ Express隨附運行時源(但我可能錯了)。

printf()很可能位於動態共享庫中。 動態鏈接器使用導入函數的地址填充表; 這就是你必須進行間接呼叫的原因。

我真的不記得這是如何運作的; 優化可能會使流程復雜化。 但是你明白了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM