2 回答

TA貢獻(xiàn)1942條經(jīng)驗(yàn) 獲得超3個(gè)贊
約束允許編譯器選擇內(nèi)存或寄存器,所以很明顯,如果發(fā)生這種情況, "g"你最終會(huì)得到。最多可以有 1 個(gè)內(nèi)存操作數(shù)。(與所有 x86 指令一樣,最多可以有一個(gè)顯式內(nèi)存操作數(shù)。)mov mem,memmov
"ri"對(duì)將被移動(dòng)到內(nèi)存目標(biāo)的輸入使用約束,以允許寄存器或立即但不是內(nèi)存。
此外,您正在修改 RSP,因此您無(wú)法安全地使用內(nèi)存源操作數(shù)。編譯器將假設(shè)它可以使用[rsp+16]or之類(lèi)的尋址模式[rsp-4]。所以你不能使用pushinstead of mov。
您還需要在所有被調(diào)用破壞的寄存器上聲明破壞者,因?yàn)楹瘮?shù)調(diào)用會(huì)這樣做。(或者更好的是,也許在那些被調(diào)用破壞的寄存器中請(qǐng)求輸入,這樣編譯器就不必通過(guò)像 RBX 這樣的調(diào)用保留寄存器來(lái)反彈它們。但是你需要讓這些操作數(shù)讀/寫(xiě)或聲明單獨(dú)的輸出操作數(shù)相同的寄存器讓編譯器知道它們將被修改。)
因此,提高效率的最佳選擇可能是
int ecx, edx, edi, esi; // dummy outputs as clobbers
register int r8 asm("r8d"); // for all the call-clobbered regs in the calling convention
register int r9 asm("r9d");
register int r10 asm("r10d");
register int r11 asm("r11d");
// These are the regs for x86-64 System V.
// **I don't know what Go actually clobbers.**
asm("sub rsp, 0xe0\n\t" // adjust as necessary to align the stack before a call
// "push args in reverse order"
"push %[fn_len] \n\t"
"push %[fn_str] \n\t"
"call \n\t"
"add rsp, 0xe0 + 3*8 \n\t" // pop red-zone skip space + pushed args
// real output in RAX, and dummy outputs in call-clobbered regs
: "=a"(retval), "=c"(ecx), "=d"(edx), "=D"(edi), "=S"(esi), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11)
: [fn_str] "ri" (filename.str), [fn_len] "ri" (filename.len), etc. // inputs can use the same regs as dummy outputs
: "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", // All vector regs are call-clobbered
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
"memory" // if you're passing any pointers (even read-only), or the function accesses any globals,
// best to make this a compiler memory barrier
);
請(qǐng)注意,輸出不是early -clobber,因此編譯器可以(根據(jù)其選擇)將這些寄存器用于輸入,但我們不強(qiáng)制這樣做,因此編譯器仍然可以自由使用其他寄存器或立即數(shù)。
經(jīng)過(guò)進(jìn)一步討論,Go 函數(shù)不會(huì)破壞 RBP,因此沒(méi)有理由手動(dòng)保存/恢復(fù)它。您可能想要這樣做的唯一原因是本地人可能使用 RBP 相對(duì)尋址模式,而較舊的 GCC 在不使用-fomit-frame-pointer. (我想?;蛘咭苍S我正在考慮 32 位 PIC 代碼中的 EBX。)
此外,如果您使用的是 x86-64 System V ABI,請(qǐng)注意內(nèi)聯(lián) asm 不得破壞紅色區(qū)域。編譯器假設(shè)這不會(huì)發(fā)生,并且沒(méi)有辦法在紅色區(qū)域聲明一個(gè) clobber,甚至無(wú)法-mno-redzone在每個(gè)函數(shù)的基礎(chǔ)上設(shè)置。所以你可能需要sub rsp, 128 + 0xe0。或者0xe0已經(jīng)包含足夠的空間來(lái)跳過(guò)紅色區(qū)域,如果它不是被調(diào)用者參數(shù)的一部分的話(huà)。

TA貢獻(xiàn)1845條經(jīng)驗(yàn) 獲得超8個(gè)贊
原始發(fā)布者將此解決方案添加為對(duì)他們問(wèn)題的編輯:
如果有人發(fā)現(xiàn)這個(gè),當(dāng)您嘗試使用內(nèi)聯(lián) asm 調(diào)用 golang 代碼時(shí),接受的答案對(duì)您沒(méi)有幫助!接受的答案僅有助于解決我最初的問(wèn)題,這幫助我修復(fù)了 golangcall。使用這樣的東西:**
void* __cdecl go_call(void* func, __int64 p1, __int64 p2, __int64 p3, __int64 p4){
void* ret;
asm volatile(" sub rsp, 0x28; \t\n\
mov [rsp], %[p1]; \t\n\
mov [rsp+0x8], %[p2]; \t\n\
mov [rsp+0x10], %[p3]; \t\n\
mov [rsp+0x18], %[p4]; \t\n\
call %[func_addr]; \t\n\
add rsp, 0x28; "
:
: [p1] "ri"(p1), [p2] "ri"(p2),
[p3] "ri"(p3), [p4] "ri"(p4), [func_addr] "ri"(func)
: );
return ret;
}
- 2 回答
- 0 關(guān)注
- 300 瀏覽
添加回答
舉報(bào)