我正在學習匯編基礎知識并且我printf經常使用(我認為我從 C/C 經驗中了解得足夠好)。我遇到了 2 個位元組(16 位)值的奇怪東西:
在 32 位模式下,使用 時printf("%hu", (unsigned short)123),我認為它會從堆疊中取出 6 個位元組(4 個用于格式字串的地址,2 個用于值)。同時現實是,4 代表地址,4 代表價值。
這是為什么?是否%hu等于公正%u?或者它只是剝離高 2 個位元組的值?
一些代碼(從 C 到 ASM 編譯,-O0):
https ://godbolt.org/z/x167zdon1
這有效:
mov eax, 123
push eax
push format ; "%hu"
call _printf
add esp, 4 4 ; works
但我認為這應該:
mov ax, 123
push eax
push format ; "%hu"
call _printf
add esp, 4 2 ; doesn't work: print gibberish, as it takes 2 bytes more to display the value....
uj5u.com熱心網友回復:
不作業...
當然:您執行了一個push eax,它將 4 個位元組壓入堆疊。因此,您必須再次從堆疊中洗掉 4 個位元組。
我遇到了 2 個位元組(16 位)值的奇怪東西。
在 x86-32 代碼中,堆疊通常應與 4 對齊。這意味著esp暫存器的值應為 4 的倍數。
出于這個原因,如果函式引數只有 16 甚至 8 位元組的值,大多數呼叫約定都需要推送 32 位的值。
是否
%hu等于公正%u?或者它只是剝離高 2 個位元組的值?
這取決于呼叫約定和庫實作:
當使用呼叫約定時,push如果引數是 16 位值,C 編譯器必須使用其高 16 位為 0 的 32 位數字,庫(printf函式)可以以%hu與%u.
當使用這樣一個數字的高 16 位可以具有任何值的呼叫約定時,該printf函式當然必須剝離高 2 個位元組。
編輯
實際上,您在示例中有兩個效果printf:
- 正如我已經寫過的,如果需要
charorshort引數,x86-32 編譯器會將 32 位值傳遞給函式。 - 在具有可變數量的引數(例如
printf)的函式中,型別的“附加”引數char或short必須int由編譯器轉換為。
假設我們在 16 位 CPU 上作業,但資料型別int為 32 位長。而且我們有一些功能void test(short x, ...);。
如果我們test(a, a);在這種情況下呼叫,編譯器會將第一個引數作為 16 位值傳遞(因為該引數具有資料型別short),第二個引數作為 32 位值傳遞(因為它是一個附加引數)。
附加引數的情況也是如此printf()- 假設它int是 32 位資料型別。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/468272.html
