gpt4 book ai didi

assembly - x86-64 GAS Intel 语法中的 RIP 相关变量引用(如 "[RIP + _a]")如何工作?

转载 作者:行者123 更新时间:2023-12-03 22:28:35 33 4
gpt4 key购买 nike

考虑以下 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),但它实际上意味着 symbol关于 RIP .
与数字文字不一致:

  • [rip + 10]或 AT&T 10(%rip)表示该指令结束后 10 个字节
  • [rip + a]或 AT&T a(%rip)表示计算 rel32排量达到a , 不是 RIP + 符号值。 (GAS手册documents this特别解释)
  • [a]或 AT&T a是绝对地址,采用disp32寻址方式。这在 OS X 上不受支持,其中图像基地址始终在低 32 位之外。 (或者对于 mov 到/来自 al/ax/eax/rax,可以使用 64 位绝对 moffs 编码,但您不希望那样)。
    Linux 位置相关可执行文件确实将静态代码/数据放在虚拟地址空间的低 31 位 (2GiB) 中,因此您可以/应该使用 mov edi, sym那里,但在 OS X 上你最好的选择是 lea rdi, [sym+RIP]如果您需要寄存器中的地址。 Unable to move variables in .data to registers with Mac x86 Assembly .

  • (在 OS X 中,约定是 C 变量/函数名称在 asm 中加上 _。在手写 asm 中,对于不想从 C 访问的符号,您不必这样做。)

    NASM 在这方面不那么令人困惑:
  • [rel a]表示 [a] 的 RIP 相对寻址
  • [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>
    (用 .o 反汇编 objdump -dr 会告诉你没有任何需要链接器填充的重定位,它们都是在汇编时完成的。)
    请注意,只有 .set z, sym导致了一个关于计算。 xy最初来自纯数字文字,而不是标签,因此即使指令本身使用 [x + RIP] , 我们还有 [RIP + 8] .

    (仅限 Linux 非 PIE):解决绝对地址 8写的。 RIP,你需要 AT&T 语法 incb 8-.(%rip) .我不知道在 GAS 中如何写 intel_syntax ; [8 - . + RIP]Error: invalid operands (*ABS* and .text sections) for '-' 拒绝.
    当然,无论如何你都不能在 OS X 上这样做,除非是在图像库范围内的绝对地址。但是可能没有重定位可以保存要为 32 位 rel32 计算的 64 位绝对地址。

    有关的:
  • How to load address of function or label into register此的 AT&T 版本
  • 32-bit absolute addresses no longer allowed in x86-64 Linux?当您必须使用与位置无关的代码时,PIE 与非 PIE 可执行文件。
  • 关于assembly - x86-64 GAS Intel 语法中的 RIP 相关变量引用(如 "[RIP + _a]")如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54745872/

    33 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com