2011-03-31 54 views
2

我想知道如何從彙編代碼調用fgets。 我讀了這些問題,這是完全一樣的這一個:How to call fgets in x86 assembly? 和這一個:How to use c library function fgets in assembly language? 但他們都不滿意的原因有兩個: 1.我真的想使用fgets,因爲我想我的代碼在Windows和Linux上運行(我正在使用NASM) 2.我查看了fgets的反彙編版本,但不幸的是它沒有提供必要的細節來重現它的命名方式stdin如何在彙編中表示。 這裏是我使用gcc -S fgets.c得到的C代碼和彙編代碼。從彙編代碼調用fgets

fgets.c

#include <stdio.h> 
int main() 
{ 
    char name[15]; 
    fgets(name, 16, stdin); 
    return 0; 
} 

fgets.s

.file "fgets.c" 
    .def ___main; .scl 2; .type 32; .endef 
    .text 
.globl _main 
    .def _main; .scl 2; .type 32; .endef 
_main: 
    pushl %ebp 
    movl %esp, %ebp 
    andl $-16, %esp 
    subl $32, %esp 
    call ___main 
    movl __imp___iob, %eax 
    movl %eax, 8(%esp) 
    movl $16, 4(%esp) 
    leal 17(%esp), %eax 
    movl %eax, (%esp) 
    call _fgets 
    movl $0, %eax 
    leave 
    ret 
    .def _fgets; .scl 2; .type 32; .endef 

首先,我不擅長讀取AT & T語法,從而容易地理解上面的組件源。 所以任何人都可以幫我弄清楚:(i)我的本地變量name位於哪裏?在ESP + 17? (ii)如果__imp___iob代表stdin,哪裏來的,以便我可以使用它?

感謝

+1

我也不喜歡AT&T的語法。使用'gcc -S -masm = intel fgets。c'得到更好的拆卸。 – 2011-04-01 00:09:28

+0

@Burr:哈哈哈,這有點不舒服。謝謝你的提示!!!救了我。 – Khan2011 2011-04-01 00:46:14

回答

4

是的,名字是在esp + 17。初始化它是明智的。在cdecl調用約定中的參數從右到左以及棧中最右邊的最深處傳遞。從CRT導出__imp___iob,你會發現它回到stdio.h頭文件中。搜索stdin。 __imp前綴是一個Microsoft公約,可以更快地導出DLL。獲得這個權利顯然是編譯器的工作。

+0

@Passant:我將'__imp_iob'追蹤回一些可能在DLL(ntdll.dll?)中定義的數據。正如你剛剛指出的那樣,編譯器在這裏做的很好,但我如何獲得該值並使用它?我可以在'.text'部分做一些'extern __imp_iob',但它是否正確?歡迎進一步的建議! – Khan2011 2011-04-01 00:49:56

+0

編譯器生成它很可能是正確的。你必須鏈接編譯器使用的同一個CRT庫。您似乎在混合工具,因此撥打電話並不容易。這是什麼意思? – 2011-04-01 01:10:08

+0

@ Khan2011:我假設你正在使用MinGW。 '__imp_iob'在'/ mingww/include/stdio.h'中聲明,並由msvcrt.dll的導入庫'libmsvcrt.a'中的鏈接器解析。您應該能夠使用相同的庫來鏈接您的彙編程序。我不確定C運行時可能需要什麼(如果有的話)特殊的初始化。通過MinGW所做的工作來解答這個問題。 – 2011-04-01 01:27:24

1

(i)在我的本地變量name在什麼位置?在ESP + 17?

是的 - 實際上'name'在你打電話時衰減到一個指針 - 你的整個數組在堆棧中。第一個字節在ESP + 17,其餘字節在後面。請注意,代碼使用leal來獲取該陣列的第一個字節的地址傳遞到fgets()

(ii)如果__imp___iob表示stdin,哪裏來的,以便我可以使用它?

您應該可以使用任何stdin被定義爲您的機器。例如,在我的Mac上,它最終成爲___stdinp。您可以追溯系統標題中的定義(從stdio.h開始)。您可能需要使用.globl指令來使彙編程序不會發出抱怨,但它應該正確鏈接。 __imp___iob看起來像你正確的選擇。

下面是我在stdio.h發現:

#if __DARWIN_UNIX03 
#define stdin __stdinp 
#define stdout __stdoutp 
#define stderr __stderrp 
#else /* !__DARWIN_UNIX03 */ 
#define stdin (&__sF[0]) 
#define stdout (&__sF[1]) 
#define stderr (&__sF[2]) 
#endif /* __DARWIN_UNIX03 */ 

額外_在我的彙編代碼是必需的,因爲編譯器是繞不把它釘住。

+0

@Norum:感謝您的明確解釋!我在'stdio.h'中得到了'stdin',但是如何在彙編代碼中使用它?我有一些代碼編譯,但嘿,無法完成這項工作!我是比較新的stackoverflow,所以我不知道在哪裏發佈我的代碼。感謝您的任何新見解! – Khan2011 2011-04-01 00:54:34