[英]Loading registers in gcc inline assembly? (simple?)
因此,對於所有精通匯編的人來說,這似乎是一個非常簡單的問題,但是我希望有人可以向我解釋以下兩段代碼之間的區別,因為一個導致分段錯誤,而另一個導致分段錯誤不是,但是(對我而言)它們似乎在邏輯上應該等效。
工作正常:
char *src1; int esi_out, eax;
__asm__
__volatile__(
"lodsb\n\t;"
: "=&S" (esi_out), "=&a" (eax)
: "0" (src1)
);
printf("src1 %c @ %p, esi_out: %x, eax: %x\n", *src1, src1, esi_out, eax);
並打印:
src1 w @ 0x7fffce186959, esi_out: ce18695a, eax: ce186977
因此,我的理解是,此代碼應將src1的值(這是一個地址)加載到ESI中,將該值復制到EAX中,將ESI中的地址遞增1個字節,然后退出,然后將這些值輸出到本地C變量esi_out和eax。 src1和esi_out看起來正確,但是eax似乎已關閉。 這里發生了什么?
代碼的第二部分是我們看到的段錯誤,我不太了解:
__asm__
__volatile__(
"movl %%ebx, %%esi\n\t;"
//"lodsb\n\t;"
: "=&S" (esi_out), "=&b" (ebx), "=&a" (eax)
: "1" (src1)
);
printf("src1 %c @ %p, esi_out: %x, eax: %x, ebx: %x\n",
*src1, src1, esi_out, eax, ebx);
注釋掉lodsb命令后,它會產生:
src1 w @ 0x7ffff093b959, esi_out: f093b959, eax: f093b959, ebx: f093b959
並且在沒有注釋掉lodsb命令的情況下,它會出現段錯誤。 以我的思維方式,像上面第一種情況一樣,直接加載ESI值,然后將其加載到EBX中,然后將其移動到ESI中應該是等效的,不是嗎?
我想念什么? 為什么寫入EAX的值看起來不正確? 我將等效程序直接編寫到了程序集中,並使用gdb逐步完成了該程序,並且運行良好。
任何見識將不勝感激。
從printf中%p
輸出的外觀來看,您正在編譯64位,但是asm代碼假定為32位。 嘗試
__asm__
__volatile__(
"movl %%rbx, %%rsi\n\t;"
"lodsb\n\t;"
: "=&S" (esi_out), "=&b" (ebx), "=&a" (eax)
: "1" (src1)
);
printf("src1 %c @ %p, esi_out: %x, eax: %x, ebx: %x\n",
*src1, src1, esi_out, eax, ebx);
您還應該將esi_out
和ebx
聲明為指針類型( void*
或char*
)或uintptr_t
。
發生的事情是lodsb在64位模式下使用RSI作為其源地址,但是您只將指針值的低32位放入RSI中,因此它不包含有效地址,因此存在段錯誤。 正如Slagh所說,lodsb只能修改a寄存器(a1)的低8位。 您應該屏蔽掉其他位(eax和0xff),清除rax(xor%rax,%rax)或將eax聲明為char
。
如果您感到驚訝,則通常也應該找到有關x86_64匯編的資源。
您的第一個問題lodsb
正在修改AL,而不是在修改EAX的其余部分。 您的EAX值ce186977
的最后一個字節為0x77,對於小寫字母“ w”為十六進制。
不幸的是,我不熟悉GCC匯編語法-當您運行代碼並跨過movl
,目的地是哪個寄存器? 在我看來,EBX正在編寫ESI。 您的代碼之前EBX中有什么?
您有一些錯誤:
您使用的是64位架構,因此int
不足以容納指針。 esi_out
變量應為64位寬,或者最好使用ptrdiff_t
。 並且您應該將其命名為rsi_out
;-)
64位模式下的lodsb
指令隱式引用rsi
而不是esi
。 在movl %%ebx, %%esi
之前的指令中movl %%ebx, %%esi
您僅設置了rsi
的下半部分,隱式清除了上半部分。 將其更改為movq %%rbx, %%rsi
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.