Смещение перед квадратной скобкой в ​​Intel asm x86 на GCC - PullRequest
3 голосов
/ 07 мая 2020

Из всех документов, которые я нашел, нет упоминания о синтаксисе вроде offset[var+offset2] в синтаксисе Intel x86, но G CC со следующими флагами

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, я просто предполагаю, что это смещение, может ли кто-нибудь направить меня к соответствующей документации, подчеркивающей это? 1015

1 Ответ

5 голосов
/ 07 мая 2020

Да, это просто другой способ написания [rbp - 1], а -1 - это смещение в технической терминологии режима адресации x86 1 .

Раздел руководства GAS о режимах адресации x86 упоминает только возможность [ebp - 4], а не -4[ebp], но GAS его собирает.

А разборка в синтаксисе AT&T или Intel подтверждает, что это означает. Режимы адресации x86 ограничены тем, что машина может кодировать ( Ссылка на содержимое ячейки памяти. (режимы адресации x86) ), поэтому не так много места для маневра в том, что может означать некоторый синтаксис. ( Этот синтаксис был сгенерирован G CC, поэтому мы можем с уверенностью предположить, что он действителен . И это означает то же самое, что -1(%rbp), которое он генерирует в режиме синтаксиса AT&T.)

Сноска 1: Весь эффективный адрес rbp-1 представляет собой смещение часть адреса seg: off. База сегмента фиксирована на 0 в 64-битном режиме, за исключением FS и GS, и даже в 32-битном режиме основные операционные системы используют плоскую модель памяти, поэтому вы можете игнорировать базу сегмента. Я указываю на это только потому, что «смещение» в терминологии x86 имеет особое c техническое значение, отдельное от «смещения», на случай, если вы хотите использовать терминологию, которая соответствует руководствам Intel.


По какой-то причине выбор синтаксиса G CC зависит от -fno-pie или нет. https://godbolt.org/z/iK9jh6 (В современных дистрибутивах GNU / Linux, таких как ваша система Arch, -fpie включен по умолчанию . На Godbolt это не так).

Этот выбор продолжается с включенной оптимизацией, если вы используете volatile для принудительной записи переменной стека или выполняете другие действия. прочее с указателями: например, https://godbolt.org/z/4P92Fk. Он применяется к произвольным разыменованиям, например ptr[1 + x] из аргументов функции.

  • G CC -fno-pie выбирает [rbp - 1] и [rdi+4+rsi*4]
  • G CC -fpie выбирает -1[rbp] и 4[rdi+rsi*4]

IDK, почему внутренние компоненты G CC выбирают по-разному в зависимости от режима P IE. Нет очевидной причины; возможно, по какой-то причине они просто используют разные пути кода во внутреннем устройстве G CC или разные строки формата, и они просто делают разные варианты.

Как с P IE, так и без него, глобальный ( stati c storage) обозначается как glob[rip], а не [RIP + glob], который также поддерживается. В обоих случаях это означает glob по отношению к RIP, а не фактический RIP + абсолютный адрес символа. Но это исключение из правила, которое применяется для любого другого регистра или без регистра.


GAS .intel_syntax похож на MASM, и MASM, безусловно, поддерживает symbol[register] а я думаю даже 1234[register]. Это более нормально для смещения.

...