Assembly 如何使用相对变量引用,例如;[RIP+;u a]";在x86-64中,Intel语法是否起作用?

Assembly 如何使用相对变量引用,例如;[RIP+;u a]";在x86-64中,Intel语法是否起作用?,assembly,x86-64,gnu-assembler,addressing-mode,intel-syntax,Assembly,X86 64,Gnu Assembler,Addressing Mode,Intel Syntax,考虑x64英特尔汇编中的以下变量引用,其中变量a在.data部分声明: mov eax, dword ptr [rip + _a] 我很难理解这个变量引用是如何工作的。由于a是与变量的运行时地址相对应的符号(带重定位),因此[rip+\u a]如何取消对a的正确内存位置的引用?实际上,rip保存当前指令的地址,它是一个大的正整数,因此加法会导致a的地址不正确 相反,如果我使用x86语法(非常直观): ,我得到以下错误:在64位模式下不支持32位绝对寻址 有什么解释吗 1 int a = 5

考虑x64英特尔汇编中的以下变量引用,其中变量
a
.data
部分声明:

mov eax, dword ptr [rip + _a]
我很难理解这个变量引用是如何工作的。由于
a
是与变量的运行时地址相对应的符号(带重定位),因此
[rip+\u a]
如何取消对
a
的正确内存位置的引用?实际上,
rip
保存当前指令的地址,它是一个大的正整数,因此加法会导致
a
的地址不正确

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

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

有什么解释吗

  1 int a = 5;
  2 
  3 int main() {
  4     int b = a;
  5     return b;
  6 }   
编译:
gcc-S-masm=intel abs\u ref.c-o abs\u 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+当前地址
(RIP),但实际上相对于
RIP
,它的意思是
symbol

与数字文字不一致:

  • [rip+10]
    或AT&T
    10(%rip)
    表示此指令结束后超过10字节

  • [rip+a]
    或AT&T
    a(%rip)
    意味着计算
    rel32
    位移以达到
    a
    ,而不是rip+符号值。(气体手册特殊解释)

  • [a]
    或AT&T
    a
    是一个绝对地址,使用disp32寻址模式。OSX上不支持这一点,因为映像基址总是在低位32位之外。(对于to/from al/ax/eax/rax,可以使用64位绝对
    MOFF
    编码,但您不希望这样)

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

(在OS X中,惯例是在asm中,C变量/函数名前面加上
。在手写asm中,对于不想从C访问的符号,不必这样做。)


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

  • [rel a]
    表示
    [a]
  • [abs a]
    表示
    [disp32]
  • default rel
    default abs
    设置用于
    [a]
    的内容。默认值是(不幸的)
    default abs
    ,因此您几乎总是想要一个
    default rel

带有
.set
符号值与标签的示例
gcc-nostlib foo.s&&objdump-drwC-Mintel a.out
(在Linux上;我没有OS X):

0000000000001000:
1000:c7 05 00 00 11 11 mov DWORD PTR[rip+0x0],0x11111111#100a#rel32=0;它来自指令的结尾,而不是rel32的结尾或其他任何地方。
000000000000100a:
100a:fe 05 08 00 inc字节PTR[rip+0x8]#1018
1010:fe 05 20 00 inc字节PTR[rip+0x20]#1036
1016:fe 05 ee ff ff inc字节PTR[rip+0xFFFFFFFFFFE]#100a
(使用
objdump-dr
分解
.o
将显示链接器没有任何要填充的重定位,它们都是在组装时完成的。)

请注意,只有
.set z,sym
会导致与计算相关的错误
x
y
源于纯数字文字,而不是标签,因此即使指令本身使用
[x+RIP]
,我们仍然得到
[RIP+8]


(仅限Linux非饼图):用于解决绝对
8
wrt。RIP,您需要AT&T语法
incb 8-.(%RIP)
。我不知道如何用GAS
intel_语法编写它
<代码>[8-.+RIP]被拒绝,错误为:'-'的无效操作数(*ABS*和.text节)

当然,在OSX上无论如何都不能这样做,除非绝对地址在映像库的范围内。但是对于32位rel32,可能没有可以保存64位绝对地址的重新定位


相关的:

  • 美国电话电报公司版本
  • PIE与非PIE可执行文件,当您必须使用位置独立代码时

哪个汇编程序接受mov eax、dword ptr[rip+\U a]?马斯姆?如果它这样做,它可能会使用正确的偏移量使
rip+\u a
指向
\u a
(即它不会使用
\u a
的地址)。在NASM中使用
mov eax,DWORD[REL\u a]
(或者将其设置为默认值)。在编写程序集时,RIP相对的东西在“相对于RIP计算此地址”中使用,而不是在“将此特定偏移量添加到RIP”中使用,因为您几乎不知道代码将在哪里。@MargaretBloom-谢谢您的回复。请参阅我的更新问题和源代码。事实上,我猜寻址应该是相对于
rip
寄存器的;然而,语法并不能很好地反映这一点,是吗?因此,您的意思是加载程序在运行时将
[rip+\u a]
替换为
a
的绝对地址;或者将
\u a
替换为
a
(可能为负)w.r.t到指令地址的相对偏移量(
mov-rax,dword-ptr[rip+\u a]
)?编辑后:这只是反汇编符号。它包含了使用RIP相对寻址和最终目标的事实。检查操作码,您将看到。“这的确是一种误导,”玛格丽特·布卢姆——非常感谢你。我希望你
  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
.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]
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>