簡體   English   中英

x86-64 GAS Intel 語法中像“[RIP + _a]”這樣的 RIP 相關變量引用如何工作?

[英]How do RIP-relative variable references like "[RIP + _a]" in x86-64 GAS Intel-syntax work?

考慮以下 x64 Intel 程序集中的變量引用,其中變量a.data部分聲明:

mov eax, dword ptr [rip + _a]

我很難理解這個變量引用是如何工作的。 由於a是相對應的符號的變量(以重定位)的運行時地址,如何能[rip + _a]取消引用正確存儲器的位置a 事實上, rip保存着當前指令的地址,它是一個很大的正整數,所以加法會導致a地址不正確。

相反,如果我使用 x86 語法(非常直觀):

mov eax, dword ptr [_a]

,我收到以下錯誤: 64 位模式不支持 32 位絕對尋址

有什么解釋嗎?

  1 int a = 5;
  2 
  3 int main() {
  4     int b = a;
  5     return b;
  6 }   

編譯: gcc -S -masm=intel abs_ref.c -o abs_ref

  1     .section    __TEXT,__text,regular,pure_instructions
  2     .build_version macos, 10, 14
  3     .intel_syntax noprefix
  4     .globl  _main                   ## -- Begin function main
  5     .p2align    4, 0x90
  6 _main:                                  ## @main
  7     .cfi_startproc
  8 ## %bb.0:
  9     push    rbp
 10     .cfi_def_cfa_offset 16
 11     .cfi_offset rbp, -16
 12     mov rbp, rsp
 13     .cfi_def_cfa_register rbp
 14     mov dword ptr [rbp - 4], 0
 15     mov eax, dword ptr [rip + _a]
 16     mov dword ptr [rbp - 8], eax
 17     mov eax, dword ptr [rbp - 8]
 18     pop rbp
 19     ret
 20     .cfi_endproc
 21                                         ## -- End function
 22     .section    __DATA,__data
 23     .globl  _a                      ## @a
 24     .p2align    2
 25 _a:
 26     .long   5                       ## 0x5
 27 
 28 
 29 .subsections_via_symbols

RIP 相對尋址的 GAS 語法看起來像symbol + current_address (RIP),但它實際上意味着相對於RIP symbol

與數字文字不一致:

  • [rip + 10]或 AT&T 10(%rip)表示超過此指令末尾的 10 個字節

  • [rip + a]或 AT&T a(%rip)表示計算rel32位移以達到a而不是RIP + 符號值。 (GAS 手冊記錄了此特殊解釋)

  • [a]或AT&T a是絕對地址,使用disp32尋址方式。 這在 OS X 上不受支持,其中圖像基地址始終在低 32 位之外。 (或者對於mov to/from al/ax/eax/rax,可以使用 64 位絕對moffs編碼,但您不想要那樣)。

    Linux 位置相關的可執行文件確實將靜態代碼/數據放在虛擬地址空間的低 31 位 (2GiB) 中,因此您可以/應該在那里使用mov edi, sym ,但在 OS X 上,您最好的選擇是lea rdi, [sym+RIP]如果您需要寄存器中的地址。 無法將 .data 中的變量移動到 Mac x86 Assembly 的寄存器

(在Mac OS X中,慣例是,C變量/函數名是附帶_ ASM中,在手寫ASM你不必為你不希望從C訪問符號做到這一點)


NASM 在這方面不那么令人困惑:

  • [rel a]手段RIP相對尋址為[a]
  • [abs a]表示[disp32]
  • default reldefault abs設置用於[a] 默認是(不幸的是) default abs ,所以你幾乎總是想要一個default rel

.set符號值與標簽的示例

.intel_syntax noprefix
mov  dword ptr [sym + rip], 0x11111111
sym:

.equ x, 8 
inc  byte ptr [x + rip]

.set y, 32 
inc byte ptr [y + rip]

.set z, sym
inc byte ptr [z + rip]

gcc -nostdlib foo.s && objdump -drwC -Mintel a.out (在 Linux 上;我沒有 OS X):

0000000000001000 <sym-0xa>:
    1000:       c7 05 00 00 00 00 11 11 11 11   mov    DWORD PTR [rip+0x0],0x11111111        # 100a <sym>    # rel32 = 0; it's from the end of the instruction not the end of the rel32 or anywhere else.

000000000000100a <sym>:
    100a:       fe 05 08 00 00 00       inc    BYTE PTR [rip+0x8]        # 1018 <sym+0xe>
    1010:       fe 05 20 00 00 00       inc    BYTE PTR [rip+0x20]        # 1036 <sym+0x2c>
    1016:       fe 05 ee ff ff ff       inc    BYTE PTR [rip+0xffffffffffffffee]        # 100a <sym>

(用objdump -dr反匯編.o會告訴你沒有任何需要鏈接器填充的重定位,它們都是在匯編時完成的。)

請注意,只有.set z, sym導致了關於計算。 xy最初來自純數字文字,而不是標簽,因此即使指令本身使用[x + RIP] ,我們仍然得到[RIP + 8]


(僅限 Linux 非 PIE):解決絕對8 RIP,您需要 AT&T 語法incb 8-.(%rip) 我不知道如何在 GAS intel_syntax編寫它; [8 - . + RIP] [8 - . + RIP]被拒絕, Error: invalid operands (*ABS* and .text sections) for '-'

當然,無論如何你都不能在 OS X 上這樣做,除非是在圖像庫范圍內的絕對地址。 但是可能沒有重定位可以保存要為 32 位 rel32 計算的 64 位絕對地址。


有關的:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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