Shu*_*eng 14 assembly x86-64 gnu-assembler intel-syntax addressing-mode
考虑 x64 Intel 程序集中的以下变量引用,其中变量a在.data节中声明:
mov eax, dword ptr [rip + _a]
Run Code Online (Sandbox Code Playgroud)
我很难理解这个变量引用是如何工作的。既然a是对应于变量运行时地址的符号(带重定位),如何[rip + _a]解引用正确的内存位置a?事实上,rip保存当前指令的地址,它是一个大的正整数,所以加法会导致错误的地址a?
相反,如果我使用 x86 语法(非常直观):
mov eax, dword ptr [_a]
Run Code Online (Sandbox Code Playgroud)
,我收到以下错误:64 位模式不支持 32 位绝对寻址。
有什么解释吗?
1 int a = 5;
2
3 int main() {
4 int b = a;
5 return b;
6 }
Run Code Online (Sandbox Code Playgroud)
编译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
Run Code Online (Sandbox Code Playgroud)
Pet*_*des 17
RIP 相对寻址的 GAS 语法看起来像symbol + current_address(RIP),但它实际上意味着symbol 相对于 RIP.
与数字文字不一致:
[rip + 10]或 AT&T10(%rip)表示此指令结束后的 10 个字节
[rip + a]或 AT&Ta(%rip)表示计算rel32要达到的位移a,而不是RIP + 符号值。(GAS 手册记录了此特殊解释)
[a]或者AT&Ta是绝对地址,使用disp32寻址方式。这在 OS X 上不受支持,其中图像基地址始终在低 32 位之外。(或者对于movto/from al/ax/eax/rax,可以使用 64 位绝对moffs编码,但您不希望那样)。
Linux 位置相关可执行文件确实将静态代码/数据放在虚拟地址空间的低 31 位 (2GiB) 中,因此您可以/应该mov edi, sym在那里使用,但在 OS X 上,lea rdi, [sym+RIP]如果您需要寄存器中的地址,则最好的选择。 无法将 .data 中的变量移动到 Mac x86 Assembly 的寄存器。
(在Mac OS X中,惯例是,C变量/函数名是附带_在ASM在手写ASM你不具备为您不想从C访问符号做到这一点)
NASM 在这方面不那么令人困惑:
[rel a] 表示 RIP 相对寻址 [a][abs a]是指[disp32]。default rel或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]
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
(反汇编.owithobjdump -dr会告诉你没有任何需要链接器填充的重定位,它们都是在汇编时完成的。)
请注意,这仅.set z, sym导致了关于计算。 x并且y最初来自纯数字文字,而不是标签,因此即使指令本身使用了[x + RIP],我们仍然得到[RIP + 8].
(仅限 Linux 非 PIE):解决绝对8wrt。RIP,你需要 AT&T 语法incb 8-.(%rip)。我不知道如何在 GAS 中编写它intel_syntax; [8 - . + RIP]被拒绝Error: invalid operands (*ABS* and .text sections) for '-'。
当然,您无论如何都不能在 OS X 上这样做,除非可能是在图像库范围内的绝对地址。但是可能没有重定位可以保存要为 32 位 rel32 计算的 64 位绝对地址。
有关的:
| 归档时间: |
|
| 查看次数: |
2893 次 |
| 最近记录: |