gcc - GCC 上 x86 intel asm 方括号前的偏移量

标签 gcc assembly x86 gnu-assembler intel-syntax

从我找到的所有文档中,没有提到英特尔 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

我想突出显示 mov BYTE PTR -1[rbp], 104 行,其中偏移 -1 出现在方括号外。 TBH,我只是猜测它是一个偏移量,任何人都可以指导我找到强调这一点的适当文档吗?

这是一个类似的问题:Squared Brackets in x86 asm from IDA评论确实提到它是一个偏移量,但我真的想要一个适当的文档引用。

最佳答案

是的,这只是 [rbp - 1] 的另一种写法,-1 是技术 x86 寻址模式中的一个位移术语1.

GAS 手册的部分 on x86 addressing modes只提到了[ebp - 4]的可能性,没有提到-4[ebp],但是GAS确实组装了它。

AT&T 或 Intel 语法中的反汇编证实了它的含义。 x86 寻址模式受机器可以编码的内容 ( Referencing the contents of a memory location. (x86 addressing modes) ) 的限制,因此在某些语法的含义上没有太多回旋余地。 (此语法由 GCC 发出,因此我们可以安全地假设它是有效的。它与它在 AT&T 语法中发出的 -1(%rbp) 含义相同模式。)

脚注 1:整个 rbp-1 有效地址是 seg:off 地址的 offset 部分。 64位模式下segment base固定为0,除了FS和GS,即使是32位主流OS也采用flat memory模型,所以可以忽略segment base。我指出这一点只是因为 x86 术语中的“偏移”确实具有与“位移”不同的特定技术含义,以防您关心使用与英特尔手册相匹配的术语。


出于某种原因,GCC 的语法选择是否取决于-fno-pie https://godbolt.org/z/iK9jh6 (在像 Arch 系统这样的现代 GNU/Linux 发行版上,-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]

我想知道为什么 GCC 的内部会根据 PIE 模式做出不同的选择。没有明显的原因;也许出于某种原因,他们只是在 GCC 内部使用了不同的代码路径,或者使用了不同的格式字符串,而他们恰好做出了不同的选择。

无论是否使用 PIE,全局(静态存储)都被引用为 glob[rip],而不是同样受支持的 [RIP + glob]。在这两种情况下,这意味着 glob 相对于 RIP,实际上并不是 RIP + 符号的绝对地址。但这是适用于任何其他注册或不注册的规则的异常(exception)。


GAS .intel_syntax 类似于 MASM,而且 MASM 确实支持 symbol[register] 我认为甚至 1234[注册]。位移比较正常。

关于gcc - GCC 上 x86 intel asm 方括号前的偏移量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61655590/

相关文章:

c - 忽略 gobble-only scanf (gcc) 的返回值

c++ - 如何以原子方式在 C++ 编码中执行 xchg 汇编指令

c - 从 C 代码调用汇编函数时出现段错误

assembly - x86 汇编中 cmove 指令的用途?

GCC交叉编译器目标库安装目录

c - 为什么 GCC 在为未声明的函数发出警告方面不一致?

gcc - 如何在编译时检查 GNU GAS 汇编代码上的 Binutils 版本?

assembly - bool 值 "notted"是如何汇编的?

delphi - 在 Delphi 中使用 Assembly 的好资源?

assembly - 汇编语言有多少种