第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

使用內(nèi)聯(lián)匯編用 C 調(diào)用 golang 函數(shù)時(shí),“mov”的內(nèi)存引用過(guò)多

使用內(nèi)聯(lián)匯編用 C 調(diào)用 golang 函數(shù)時(shí),“mov”的內(nèi)存引用過(guò)多

Go
互換的青春 2023-05-08 16:02:20
我正在嘗試從我的 C 代碼中調(diào)用 golang 函數(shù)。Golang 不使用標(biāo)準(zhǔn)的 x86_64 調(diào)用約定,所以我不得不求助于自己實(shí)現(xiàn)轉(zhuǎn)換。由于 gcc 不想將 cdecl 與 x86_64 約定混合使用,我嘗試使用內(nèi)聯(lián)匯編調(diào)用該函數(shù):void go_func(struct go_String filename, void* key, int error){    void* f_address = (void*)SAVEECDSA;    asm volatile("  sub     rsp, 0xe0;           \t\n\                    mov     [rsp+0xe0], rbp;   \t\n\                    mov     [rsp], %0;            \t\n\                    mov     [rsp+0x8], %1;       \t\n\                    mov    [rsp+0x18], %2;       \t\n\                    call    %3;                     \t\n\                    mov     rbp, [rsp+0xe0];   \t\n\                    add     rsp, 0xe0;"                              :                    : "g"(filename.str), "g"(filename.len), "g"(key), "g"(f_address)                    : );    return;}可悲的是,編譯器總是向我拋出一個(gè)我不明白的錯(cuò)誤:./code.c:241: Error: too many memory references for `mov'這對(duì)應(yīng)于這一行:mov     [rsp+0x18], %2;       \t\n\如果我刪除它,編譯工作。我不明白我的錯(cuò)誤是什么......我正在使用 -masm=intel 標(biāo)志進(jìn)行編譯,因此我使用了 Intel 語(yǔ)法。有人可以幫幫我嗎?
查看完整描述

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à)。


查看完整回答
反對(duì) 回復(fù) 2023-05-08
?
精慕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;

}


查看完整回答
反對(duì) 回復(fù) 2023-05-08
  • 2 回答
  • 0 關(guān)注
  • 300 瀏覽
慕課專(zhuān)欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢(xún)優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)