簡體   English   中英

在gcc內聯匯編中加載寄存器? (簡單?)

[英]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_outebx聲明為指針類型( 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM