Assembly 如何使用相对变量引用,例如;[RIP+;u a]";在x86-64中,Intel语法是否起作用?
考虑x64英特尔汇编中的以下变量引用,其中变量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
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
与数字文字不一致:
或AT&T[rip+10]
表示此指令结束后超过10字节10(%rip)
或AT&T[rip+a]
意味着计算a(%rip)
位移以达到rel32
,而不是rip+符号值。(气体手册特殊解释)a
或AT&T[a]
是一个绝对地址,使用disp32寻址模式。OSX上不支持这一点,因为映像基址总是在低位32位之外。(对于to/from al/ax/eax/rax,可以使用64位绝对a
编码,但您不希望这样) Linux位置相关可执行文件确实将静态代码/数据放在虚拟地址空间的低位31位(2GiB),因此您可以/应该在那里使用MOFF
,但在OS X上,如果您需要寄存器中的地址,您最好的选择是mov edi,sym
leardi,[sym+RIP]
。
。在手写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)
。我不知道如何用GASintel_语法编写它
<代码>[8-.+RIP]被拒绝,错误为:'-'的无效操作数(*ABS*和.text节)
当然,在OSX上无论如何都不能这样做,除非绝对地址在映像库的范围内。但是对于32位rel32,可能没有可以保存64位绝对地址的重新定位
相关的:
- 美国电话电报公司版本
- PIE与非PIE可执行文件,当您必须使用位置独立代码时
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>