3

从我发现的所有文档中,没有提到offset[var+offset2]英特尔 x86 语法中的语法,但 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,我只是猜测它是一个偏移量,任何人都可以指导我找到一个适当的文档来强调这一点吗?

这是一个类似的问题:来自 IDA 的 x86 asm 中的 Squared Brackets评论确实提到它是一个偏移量,但我真的很想要一个适当的文档参考。

4

1 回答 1

5

是的,这只是另一种写作方式[rbp - 1]-1是技术 x86 寻址模式术语1的替代

GAS 手册中关于 x86 寻址模式的部分只提到了这种[ebp - 4]可能性,而不是-4[ebp],但 GAS 确实组装了它。

AT&T 或 Intel 语法中的反汇编证实了它的含义。x86 寻址模式受限于机器可以编码的内容(引用内存位置的内容。(x86 寻址模式)),因此对于某些语法的含义没有太多的回旋余地。(这个语法是由 GCC 发出的,所以我们可以安全地假设它是有效的-1(%rbp)。它的含义与它在 AT&T 语法模式下发出的意思相同。)

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


出于某种原因,GCC 对语法的选择取决于-fno-pie与否。 https://godbolt.org/z/iK9jh6 (在现代 GNU/Linux 发行版上,如 Arch 系统,-fpie默认启用。在 Godbolt 上不是)。

volatile如果您使用强制写入堆栈变量或使用指针执行其他操作,则此选择继续启用优化:例如https://godbolt.org/z/4P92Fk。它适用于任意取消引用,例如ptr[1 + x]来自函数 args。

  • 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]. 位移比较正常。

于 2020-05-07T11:30:58.207 回答