【问题标题】:Offset before square bracket in x86 intel asm on GCCGCC 上 x86 intel asm 中方括号前的偏移量
【发布时间】:2020-08-22 14:51:57
【问题描述】:

在我找到的所有文档中,没有提到 Intel 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] 版本一起组装/反汇编,并比较机器代码和反汇编以查看它们的比较。

标签: gcc assembly x86 gnu-assembler intel-syntax


【解决方案1】:

是的,这只是[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 部分。除了 FS 和 GS,64 位模式下段基数固定为 0,即使在 32 位模式下,主流操作系统也使用平面内存模型,因此可以忽略段基数。我指出这一点只是因为 x86 术语中的“偏移”确实具有与“位移”不同的特定技术含义,以防您关心使用与英特尔手册相匹配的术语。


出于某种原因,GCC 对语法的选择取决于 -fno-pie 与否。 https://godbolt.org/z/iK9jh6(在现代 GNU/Linux 发行版上,如 Arch 系统,-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],它也受支持。在这两种情况下,这意味着glob 相对于 RIP,而不是实际的RIP + 符号的绝对地址。但这是适用于任何其他注册或不注册的规则的例外。


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

【讨论】:

  • @Hritik:这只是有点相关; GAS 语法通常以 MASM 为模式,但它们绝对是独立的汇编程序。在寻址模式语法之外,它们的指令完全不同,GAS 没有 MASM 所谓的“变量”。此外,通过快速搜索,我什至没有在该 BNF 中找到 MASM 寻址模式语法的详细信息;你能引用这里相关的任何部分吗?
猜你喜欢
  • 2013-04-15
  • 2011-01-03
  • 2016-02-02
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 2012-10-26
相关资源
最近更新 更多