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

2024-01-06

考虑 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]或美国电话电报公司10(%rip)表示该指令结束后 10 个字节

  • [rip + a]或美国电话电报公司a(%rip)意思是计算一个rel32位移达到a, notRIP + 符号值。 (气体手册记录这个 https://sourceware.org/binutils/docs/as/i386_002dMemory.html特别解释)

  • [a]或美国电话电报公司a是绝对地址,采用disp32寻址方式。 OS X 不支持此功能,其中映像基址始终位于低 32 位之外。 (或者对于mov https://www.felixcloutier.com/x86/mov到/从 al/ax/eax/rax,64 位绝对值moffs编码可用,但您不希望这样)。

    Linux 位置相关的可执行文件do将静态代码/数据放在虚拟地址空间的低 31 位 (2GiB) 中,因此您可以/应该使用mov edi, sym在那里,但在 OS X 上你最好的选择是lea rdi, [sym+RIP]如果您需要寄存器中的地址。无法使用 Mac x86 程序集将 .data 中的变量移动到寄存器 https://stackoverflow.com/questions/50205129/unable-to-move-variables-in-data-to-registers-with-mac-x86-assembly.

(在 OS X 中,惯例是 C 变量/函数名称前面加上_在汇编中。在手写汇编中你不需要have对您不想从 C 访问的符号执行此操作。)


NASM 在这方面就不那么令人困惑了:

  • [rel a]表示 RIP 相对寻址[a]
  • [abs a] means [disp32].
  • default rel or default 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 with objdump -dr将向您显示链接器不需要填充任何重定位,它们都是在汇编时完成的。)

请注意,仅.set z, sym得出了关于计算的结果。x and y最初来自纯数字文字,而不是标签,所以即使指令本身使用[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 位绝对地址。


Related:

  • 如何将函数或标签的地址加载到寄存器中 https://stackoverflow.com/questions/57212012/how-to-load-address-of-function-or-label-into-register-in-gnu-assemblerAT&T 版本
  • x86-64 Linux 中不再允许使用 32 位绝对地址? https://stackoverflow.com/questions/43367427/32-bit-absolute-addresses-no-longer-allowed-in-x86-64-linuxPIE 与非 PIE 可执行文件,当您have使用与位置无关的代码。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

x86-64 GAS Intel 语法中的 RIP 相对变量引用(如“[RIP + _a]”)如何工作? 的相关文章

  • 什么是微编码指令?

    我看过很多参考微编码指令的文献 这些是什么以及为什么使用它们 CPU 读取机器代码并将其解码为内部控制信号 将正确的数据发送到正确的执行单元 大多数指令映射到一个内部操作 并且可以直接解码 例如 在 x86 上 add eax edx只是将
  • 内联汇编 - cdecl 和准备堆栈

    我最近一直在尝试通过使用缓冲区和不同汇编运算符的原始十六进制等效项来实现 C 中的动态函数 为了说明一个简单的跳转 byte buffer new buffer 5 buffer 0xE9 Hex for jump uint buffer
  • NOP 雪橇如何工作?

    我找不到回答这个问题的好来源 我知道 nop sled 是一种用于规避缓冲区溢出攻击中堆栈随机化的技术 但我无法理解它是如何工作的 有什么简单的例子可以说明这种方法 128 字节 nop sled 等术语是什么意思 有些攻击包括使程序跳转到
  • 如何查看JVM中JIT编译的代码?

    有什么方法可以查看 JVM 中 JIT 生成的本机代码吗 一般用法 正如其他答案所解释的 您可以使用以下 JVM 选项运行 XX UnlockDiagnosticVMOptions XX PrintAssembly 根据特定方法进行过滤 您
  • 分配内存空间的宏

    我需要让一个汇编程序员来计算帕斯卡三角形 https en wikipedia org wiki Pascal 27s triangle 这样帕斯卡三角形的每一行都与其他行分开存储在内存中 我想做一个 但我不知道如何使用宏在汇编中做到这一点
  • 现代 x86 硬件不能将单个字节存储到内存中吗?

    说到 C 的并发内存模型 Stroustrup 的C 编程语言 第 4 版 第 1 节 41 2 1 说 就像大多数现代硬件一样 机器无法加载或存储小于单词的任何内容 然而 我的 x86 处理器已经有几年的历史了 它可以并且确实存储小于单词
  • 我试图在 AAM 指令之后使用 AX 中存储的值将其除以 2,为什么它不适用于 2 位数字输出?

    英语不是我的母语 请原谅输入错误 我将在此处显示的代码是一项作业 我真的需要了解发生了什么事 我在 DosBox 0 74 和 TASM 汇编器中使用 Intel 8086 语法 当我必须除以 2 时 代码的问题在于三角形的面积 注意 程序
  • arm-thumb指令集的blx指令如何支持4MB范围

    读自https www keil com support man docs armasm armasm dom1361289866046 htm https www keil com support man docs armasm arma
  • 汇编语言中的全局_start是什么?

    这是我的汇编级代码 section text global start start mov eax 4 mov ebx 1 mov ecx mesg mov edx size int 0x80 exit mov eax 1 int 0x80
  • 为什么当设置为 TLS 选择器时,ES 和 DS 在 64 位内核上最终会归零?

    下面的 32 位程序调用set thread area 2 http linux die net man 2 set thread area在 GDT 中创建一个条目 该条目旨在用于 TLS 通常将结果选择器放入FS or GS并成功使用
  • 使用 gdb 调试反汇编库

    在Linux和Mac OS X中可以使用strapi和next来调试应用程序而无需调试信息 在 Mac OS X 上 gdb 显示在库内部调用的函数 尽管有时会在每个 stepi 指令中推进多个汇编程序指令 在 Linux 上 当我进入动态
  • 汇编指令陷阱有什么作用?

    当程序需要时 程序通常会发出软件陷阱 由操作系统提供服务 通用异常处理程序 操作系统确定陷阱的原因并做出响应 适当地 汇编指令 trap 和 BASIC 中的 TRAP 指令一样吗 答案似乎是肯定的 你能接受还是拒绝我的结论 不中断 的代码
  • 破坏/分解函数的函数

    我以前有过 here https stackoverflow com questions 4920610 c class function in assembly 已经表明 C 函数不容易用汇编表示 现在我有兴趣以一种或另一种方式阅读它们
  • Clang 使用 -nostdlib 生成崩溃代码

    我正在尝试为可执行文件设置自己的运行时环境 但无法使用 clang v3 4 1ubuntu1 目标 x86 64 pc linux gnu 来生成没有段错误的可执行文件 我已将问题简化为以下内容 如果我有一个文件 crt1 c 除了满足
  • 即使我确实为变量设置了初始值,数据段也没有被初始化

    我已经编写了一个代码 该代码应该生成某种数字列表 但是即使我为它们分配了初始值 我的数据段变量也没有被初始化 This is how DS 0000 looks when I run it 这是我的代码 但数据段只保留垃圾值 MODEL s
  • orpd等SSE2指令有什么意义?

    The orpd指令是 压缩双精度浮点值的按位逻辑或 这不是做完 全相同的事情吗por 按位逻辑或 如果是这样 拥有它还有什么意义呢 请记住 SSE1orps https www felixcloutier com x86 orps首先 实
  • 汇编-符号标志和奇偶校验标志

    我不明白什么时候设置标志标志 什么时候设置奇偶校验 据我所知 符号标志表示运算结果的符号 0表示正数 1表示负数 那么为什么在下一个代码中 mov al 5 sub al 124 SF为零 结果是负数 关于PF 为什么a和b中设置了PF a
  • 为什么不能执行 mov [eax], [ebx] [重复]

    这个问题在这里已经有答案了 我可以做这个 mov eax ebx 和这个 mov eax ebx 甚至这个 mov eax ebx 但不是这个 错误C2415 mov eax ebx 只是wtf 为什么 它与 ptr1 ptr2 相同 为什
  • 为什么 GCC 不将 a*a*a*a*a*a 优化为 (a*a*a)*(a*a*a)?

    我正在对科学应用程序进行一些数值优化 我注意到的一件事是 GCC 会优化调用pow a 2 通过将其编译成a a 但是调用pow a 6 没有优化 实际会调用库函数pow 这大大降低了性能 相比之下 英特尔 C 编译器 http en wi
  • Nasm 打印到下一行

    我用 nasm Assembly 编写了以下程序 section text global start start Input variables mov edx inLen mov ecx inMsg mov ebx 1 mov eax 4

随机推荐