雖然內聯asm總是有點棘手,但從它調用函數特別具有挑戰性。不是我會建議「開始知道inline asm」項目。如果你還沒有,我建議通過最新的內聯asm docs。已經做了很多工作來試圖解釋內聯asm是如何工作的。
也就是說,這裏有一些想法:
1)使用多個asm語句像這是一個壞主意。正如docs所說:不要指望在彙編之後,一系列asm語句保持完全連續。如果某些指令需要在輸出中保持連續,請將它們放在一條多指令asm語句中。
2)直接修改寄存器(就像你在使用eax一樣)而不讓gcc知道你這樣做也是一個壞主意。你應該使用寄存器約束(所以gcc可以選擇它自己的寄存器)或者clobbers讓gcc知道你在跺腳。 3)當一個函數(如puts)被調用時,雖然一些寄存器在返回之前必須恢復它們的值,但有些寄存器可以被調用函數視爲暫存寄存器(即在返回之前修改而不恢復)。正如我在#2中提到的那樣,讓你的asm在不通知gcc的情況下修改寄存器是一個非常糟糕的主意。如果您知道正在調用的函數的ABI,則可以將其臨時寄存器添加到asm的clobber列表中。
4)雖然在這個特定的例子中,你使用的是一個常量字符串,通常在將asm指針傳遞給字符串,結構體,數組等時,你可能需要使用「內存」clobber來確保任何在開始執行你的asm之前,等待寫入內存。
5)實際上,lea
正在做一件非常重要的事情。 esp的值在編譯時是未知的,所以它不像你可以執行push $12345
。有人需要計算(尤其是localmsg的偏移量),然後才能將其壓入堆棧。另請參見下面的第二個示例。 6)如果你更喜歡英特爾格式(以及什麼樣的思維不正確的人),你可以使用-masm = intel。
鑑於這一切,我在這段代碼中的第一次剪切看起來像這樣。請注意,這不會破壞寄存器。這是作爲一個練習...
#include <stdio.h>
int main()
{
const char localmsg[] = "my local message";
int result;
/* Use 'volatile' since 'result' is usually not going to get used,
which might tempt gcc to discard this asm statement as unneeded. */
asm volatile ("push %[msg] \n\t" /* Push the address of the string. */
"call %[puts] \n \t" /* Call the print function. */
"add $4,%%esp" /* Clean up the stack. */
: "=a" (result) /* The result code from puts. */
: [puts] "m" (puts), [msg] "r" (localmsg)
: "memory", "esp");
printf("%d\n", result);
}
真這不避lea
由於#5。但是,如果這是真的重要的,試試這個:
#include <stdio.h>
const char localmsg[] = "my local message";
int main()
{
int result;
/* Use 'volatile' since 'result' is usually not going to get used. */
asm volatile ("push %[msg] \n\t" /* Push the address of the string. */
"call %[puts] \n \t" /* Call the print function. */
"add $4,%%esp" /* Clean up the stack. */
: "=a" (result) /* The result code. */
: [puts] "m" (puts), [msg] "i" (localmsg)
: "memory", "esp");
printf("%d\n", result);
}
作爲一個全球性的,localmsg的地址現在是在編譯時(好吧,我簡化了一下)可知,在asm生產這個樣子的:
push $__ZL8localmsg
call _puts
add $4,%esp
田田。
'asm(「push%0」:「= m」(&localmsg));'work? – markgz 2014-09-05 19:24:01
@markgz不,它抱怨說'asm聲明中需要左值'。無論如何,我認爲這不會有多大意義,因爲localmsg已經是一個指針了。 – szczurcio 2014-09-05 19:27:06
爲什麼你將localmsg標記爲輸出操作數? – 2014-09-05 20:06:39