2014-01-19 71 views
2

查看這個用VC++ 2003/2005編譯的C代碼。爲什麼要將4字節參數傳遞給需要2字節參數的函數?

#include <stdio.h> 
#include <windows.h> 

void WINAPI SomeFunction(WORD a, WORD b) 
{ 
    printf("%d + %d = %d\n", a, b, a + b); 
} 

int main() 
{ 
    __asm { 
     MOV EAX, 5 
     MOV EBX, 6 
     PUSH EBX 
     PUSH EAX 
     CALL SomeFunction 
    } 

    return 0; 
} 

在此ASM代碼中,我(據我所知默認情況下)傳遞兩個DWORD(4個字節)參數的SomeFunction()功能需要兩個WORD(2字節)的論點,和完美的作品(輸出5 + 6 = 11)。

1)爲什麼這項工作?在調試它拋出一個分段錯誤

__asm { 
    MOV WORD PTR [EAX], 5 
    MOV WORD PTR [EBX], 6 
    PUSH EBX 
    PUSH EAX 
    CALL SomeFunction 
} 

知道該函數有兩個參數WORD,我會做到這一點。

2)爲什麼這個不是工作?

在此先感謝!

+2

「完美地工作」可能對不同的人有不同的含義。 –

+0

現在就來看看吧。 – cdonts

回答

3

第一個工作,因爲Win32 ABI說任何大小小於或等於4個字節的參數都是以4個字節的形式傳遞的,必要時填充。所以16位字實際上是以32位傳遞的。這就是你正在做的。

第二個不工作,因爲它做了不同的事情:

MOV WORD PTR [EAX], 5 

該行通過EAX移動5到開始的內存位置的16位字指向。但是EAX以前沒有裝載有效的內存地址。此外,你在推動指針(一個WORD*?)。

爲了通過在堆棧中的16位值,你可以使用:

MOV AX, 5 
MOV BX, 6 
PUSH AX 
PUSH BX 

但是去agains在Win32 ABI,因爲堆棧總是32位對齊。

有趣的是,如果你的價值(未經測試)通過這種結構,將工作:

struct WW 
{ 
    WORD a, b; 
}; 

void WINAPI SomeFunction(WW w) 
{ 
    printf("%d + %d = %d\n", w.a, w.b, w.a + w.b); 
} 

int main() 
{ 
    __asm { 
     MOV BX, 6 // the parameters are reversed, methinks 
     MOV AX, 5 
     PUSH BX 
     PUSH AX 
     CALL SomeFunction 
    } 

    return 0; 
} 

這是因爲結構域被打包在4個字節(sizeof(WW)==4),所以這就是被複制到堆棧。

當然,玩16位寄存器並不好玩。這可能是更好的做法:

MOV EAX 0x00060005 
PUSH EAX 

並一口氣複製整個32位結構。

+0

所以我的第一次ASM調用是更好的方法,即使參數爲2字節? – cdonts

+0

@cdonts:的確如此!該代碼有效,不是偶然的,而是因爲它是正確的。如果你編譯'SomeFunction(5,6)',你會看到編譯器生成一個類似的代碼。 – rodrigo

+0

完美,謝謝你的幫助! – cdonts

相關問題