本文介绍了如何使用相对于RIP的变量引用,例如“ [RIP + _a]”?在x86-64 GAS Intel语法中工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

请考虑x64 Intel汇编中的以下变量引用,其中在 .data 部分中声明了变量 a 。 :

Consider the following variable reference in x64 Intel assembly, where the variable a is declared in the .data section:

mov eax, dword ptr [rip + _a]

我很难理解此变量引用的工作方式。由于 a 是对应于变量运行时地址(带重定位)的符号,所以 [rip + _a] 取消引用 a 的正确内存位置?实际上, rip 保留当前指令的地址,该地址是一个大的正整数,因此加法会导致错误的地址 a

I have trouble understanding how this variable reference works. Since a is a symbol corresponding to the runtime address of the variable (with relocation), how can [rip + _a] dereference the correct memory location of a? Indeed, rip holds the address of the current instruction, which is a large positive integer, so the addition results in an incorrect address of a?

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

Conversely, if I use x86 syntax (which is very intuitive):

mov eax, dword ptr [_a]

,我得到以下信息错误:在64位模式下不支持32位绝对寻址

, I get the following error: 32-bit absolute addressing is not supported in 64-bit mode.

任何解释吗?

  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语法看起来像符号+ RIP ,但这实际上是针对 <$ c $的 符号 c> RIP

GAS syntax for RIP-relative addressing looks like symbol + RIP, but it actually means symbol with respect to RIP.

数字文字存在不一致之处:

There's an inconsistency with numeric literals:


  • [rip + 10] 或AT& T 10(%rip)表示该指令末尾的10个字节

  • [rip + a] 或AT& T a(% rip)的意思是计算 rel32 的位移以达到 a 不是 RIP +符号值。 (GAS手册特殊解释)

  • [a] 或AT& T a 是绝对地址,使用disp32寻址模式。 OS X不支持此功能,因为OS X的图像基址始终在低32位之外。 (或对于到/来自al / ax / eax / rax,可以使用64位绝对 moffs 编码,但您不希望这样做)。

  • [rip + 10] or AT&T 10(%rip) means 10 bytes past the end of this instruction
  • [rip + a] or AT&T a(%rip) means to calculate a rel32 displacement to reach a, not RIP + symbol value. (The GAS manual documents this special interpretation)
  • [a] or AT&T a is an absolute address, using a disp32 addressing mode. This isn't supported on OS X, where the image base address is always outside the low 32 bits. (Or for mov to/from al/ax/eax/rax, a 64-bit absolute moffs encoding is available, but you don't want that).

Linux位置相关的可执行文件 do 将静态代码/数据放入虚拟地址空间的低31位(2GiB)中,因此您可以/应该使用 mov edi ,sym ,但是在OS X上,如果您需要寄存器中的地址,最好的选择是 lea rdi,[sym + RIP] 。 。

Linux position-dependent executables do put static code/data in the low 31 bits (2GiB) of virtual address space, so you can/should use mov edi, sym there, but on OS X your best option is lea rdi, [sym+RIP] if you need an address in a register. Unable to move variables in .data to registers with Mac x86 Assembly.

(在OS X中,约定是C变量/函数名称在asm中以 _ 开头在手写的asm中,您不需要没有来执行不想访问的符号的操作

(In OS X, the convention is that C variable/function names are prepended with _ in asm. In hand-written asm you don't have to do this for symbols you don't want to access from C.)

在这方面,NASM的混乱程度要小得多:

NASM is much less confusing in this respect:


  • [rel a] 表示 [a] 的RIP相对寻址

  • [abs a] 表示 [disp32]

  • 默认rel 默认abs 设置用于的内容] 。默认是(不幸的是)默认abs ,所以您几乎总是想要一个默认rel

  • [rel a] means RIP-relative addressing for [a]
  • [abs a] means [disp32].
  • default rel or default abs sets what's used for [a]. The default is (unfortunately) default abs, so you almost always want a default rel.
.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):

gcc -nostdlib foo.s && objdump -drwC -Mintel a.out (on Linux; I don't have 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 会向您显示没有任何可用于链接器填充的重定位,它们都是在组装时完成的。)

(Disassembling the .o with objdump -dr will show you that there aren't any relocations for the linker to fill in, they were all done at assemble time.)

请注意,只有 .set z,sym 会进行尊重计算。 x y 是纯数字文字而非标签的原始内容,因此即使指令本身使用了 [x + RIP] ,我们仍然得到 [RIP + 8]

Notice that only .set z, sym resulted in a with-respect-to calculation. x and y were original from plain numeric literals, not labels, so even though the instruction itself used [x + RIP], we still got [RIP + 8].

(仅适用于Linux非PIE):解决绝对 8 wrt的问题。 RIP,您需要使用AT& T语法 incb 8-。(%rip)。我不知道该如何在GAS intel_syntax 中编写该代码; [8-。 + RIP] 被拒绝,并出现错误:- 的无效操作数(* ABS *和.text部分)。

(Linux non-PIE only): To address absolute 8 wrt. RIP, you'd need AT&T syntax incb 8-.(%rip). I don't know how to write that in GAS intel_syntax; [8 - . + RIP] is rejected with Error: invalid operands (*ABS* and .text sections) for '-'.

当然,您不能在OS X上执行此操作,除非绝对地址位于图像范围内。但是可能没有重定位可以容纳要为32位rel32计算的64位绝对地址。

Of course you can't do that anyway on OS X, except maybe for absolute addresses that are in range of the image base. But there's probably no relocation that can hold the 64-bit absolute address to be calculated for a 32-bit rel32.

这篇关于如何使用相对于RIP的变量引用,例如“ [RIP + _a]”?在x86-64 GAS Intel语法中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-07 03:09