GCC 上 x86 intel asm 方括号前的偏移量
Offset before square bracket in x86 intel asm on GCC
从我找到的所有文档中,没有提到英特尔 x86 语法中的 offset[var+offset2]
语法,但 GCC 具有以下标志
gcc -S hello.c -o - -masm=intel
对于这个程序
#include<stdio.h>
int main(){
char c = 'h';
putchar(c);
return 0;
}
产生
.file "hello.c"
.intel_syntax noprefix
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 16
mov BYTE PTR -1[rbp], 104
movsx eax, BYTE PTR -1[rbp]
mov edi, eax
call putchar@PLT
mov eax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Arch Linux 9.3.0-1) 9.3.0"
.section .note.GNU-stack,"",@progbits
我想突出显示偏移量 -1
出现在方括号外的行 mov BYTE PTR -1[rbp], 104
。 TBH,我只是猜测它是一个偏移量,任何人都可以指导我找到强调这一点的适当文档吗?
这是一个类似的问题:Squared Brackets in x86 asm from IDA 其中一条评论确实提到它是一个偏移量,但我真的想要一个适当的文档参考。
是的,这只是 [rbp - 1]
的另一种写法,而 -1
是技术 x86 寻址模式术语中的 位移 1.
GAS 手册的 on x86 addressing modes 部分只提到了 [ebp - 4]
的可能性,没有 -4[ebp]
,但 GAS 确实 assemble
并且 AT&T 或 Intel 语法中的反汇编证实了它的含义。 x86 寻址模式受机器可以编码的内容 () 的限制,因此在某些语法的含义上没有太多回旋余地。 (此语法由 GCC 发出,因此我们可以安全地假设它是有效的。并且它与它在 AT&T 语法模式下发出的 -1(%rbp)
含义相同。)
脚注 1:整个 rbp-1
有效地址是 seg:off 地址的 offset 部分。 64位模式下segment base固定为0,除了FS和GS,即使是32位主流OS也采用flat memory模型,所以可以忽略segment base。我指出这一点只是因为 x86 术语中的 "offset" 确实具有不同于 "displacement" 的特定技术含义,以防您关心使用与英特尔手册相匹配的术语。
出于某种原因,GCC 的语法选择取决于 -fno-pie
或不。 https://godbolt.org/z/iK9jh6 (On modern GNU/Linux distros like your Arch system, -fpie
is enabled by default。在 Godbolt 上不是。
如果您使用 volatile
强制写入堆栈变量,或者使用指针做其他事情,则此选择会继续启用优化:例如https://godbolt.org/z/4P92Fk。它适用于函数 args 中的任意取消引用,例如 ptr[1 + x]
。
- GCC
-fno-pie
选择 [rbp - 1]
和 [rdi+4+rsi*4]
- GCC
-fpie
选择 -1[rbp]
和 4[rdi+rsi*4]
IDK 为什么 GCC 的内部会根据 PIE 模式进行不同的选择。没有明显的原因;也许出于某种原因,他们只是在 GCC 的内部使用了不同的代码路径,或者不同的格式字符串,他们恰好做出了不同的选择。
无论有无 PIE,全局(静态存储)都被引用为 glob[rip]
,而不是 [RIP + glob]
,后者也受支持。在这两种情况下,相对于 RIP,这意味着 glob
,而不是实际的 RIP + 符号的绝对地址。但这是适用于任何其他寄存器或没有寄存器的规则的例外。
GAS .intel_syntax
是类似 MASM 的,而且 MASM 确实支持 symbol[register]
,我认为甚至 1234[register]
。位移比较正常
从我找到的所有文档中,没有提到英特尔 x86 语法中的 offset[var+offset2]
语法,但 GCC 具有以下标志
gcc -S hello.c -o - -masm=intel
对于这个程序
#include<stdio.h>
int main(){
char c = 'h';
putchar(c);
return 0;
}
产生
.file "hello.c"
.intel_syntax noprefix
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 16
mov BYTE PTR -1[rbp], 104
movsx eax, BYTE PTR -1[rbp]
mov edi, eax
call putchar@PLT
mov eax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Arch Linux 9.3.0-1) 9.3.0"
.section .note.GNU-stack,"",@progbits
我想突出显示偏移量 -1
出现在方括号外的行 mov BYTE PTR -1[rbp], 104
。 TBH,我只是猜测它是一个偏移量,任何人都可以指导我找到强调这一点的适当文档吗?
这是一个类似的问题:Squared Brackets in x86 asm from IDA 其中一条评论确实提到它是一个偏移量,但我真的想要一个适当的文档参考。
是的,这只是 [rbp - 1]
的另一种写法,而 -1
是技术 x86 寻址模式术语中的 位移 1.
GAS 手册的 on x86 addressing modes 部分只提到了 [ebp - 4]
的可能性,没有 -4[ebp]
,但 GAS 确实 assemble
并且 AT&T 或 Intel 语法中的反汇编证实了它的含义。 x86 寻址模式受机器可以编码的内容 (-1(%rbp)
含义相同。)
脚注 1:整个 rbp-1
有效地址是 seg:off 地址的 offset 部分。 64位模式下segment base固定为0,除了FS和GS,即使是32位主流OS也采用flat memory模型,所以可以忽略segment base。我指出这一点只是因为 x86 术语中的 "offset" 确实具有不同于 "displacement" 的特定技术含义,以防您关心使用与英特尔手册相匹配的术语。
出于某种原因,GCC 的语法选择取决于 -fno-pie
或不。 https://godbolt.org/z/iK9jh6 (On modern GNU/Linux distros like your Arch system, -fpie
is enabled by default。在 Godbolt 上不是。
如果您使用 volatile
强制写入堆栈变量,或者使用指针做其他事情,则此选择会继续启用优化:例如https://godbolt.org/z/4P92Fk。它适用于函数 args 中的任意取消引用,例如 ptr[1 + x]
。
- GCC
-fno-pie
选择[rbp - 1]
和[rdi+4+rsi*4]
- GCC
-fpie
选择-1[rbp]
和4[rdi+rsi*4]
IDK 为什么 GCC 的内部会根据 PIE 模式进行不同的选择。没有明显的原因;也许出于某种原因,他们只是在 GCC 的内部使用了不同的代码路径,或者不同的格式字符串,他们恰好做出了不同的选择。
无论有无 PIE,全局(静态存储)都被引用为 glob[rip]
,而不是 [RIP + glob]
,后者也受支持。在这两种情况下,相对于 RIP,这意味着 glob
,而不是实际的 RIP + 符号的绝对地址。但这是适用于任何其他寄存器或没有寄存器的规则的例外。
GAS .intel_syntax
是类似 MASM 的,而且 MASM 确实支持 symbol[register]
,我认为甚至 1234[register]
。位移比较正常