Какая польза от директивы ассемблера .byte в сборке GNU? - PullRequest
13 голосов
/ 03 сентября 2011

При прохождении некоторого кода C, имеющего встроенную сборку, я натолкнулся на директиву .byte (с точкой в ​​начале).

При проверке ссылки на сборку в Интернете я обнаружил, что она используется для резервирования байта в памяти.

Но в коде не было метки перед оператором. Поэтому мне было интересно, что такое использование немаркированной директивы .byte или любой другой директивы хранения данных.

Например, если я наберу код .byte 0x0a, как я могу его использовать?

Ответы [ 4 ]

8 голосов
/ 03 сентября 2011

Есть несколько возможностей ... вот пара, о которой я могу подумать:

  1. Вы можете получить к нему доступ по отношению к метке, которая появляется после директивы .byte. Пример:

      .byte 0x0a
    label:
      mov (label - 1), %eax
    
  2. На основании окончательного связанного макета программы, возможно, директивы .byte будут выполнены как код. Обычно в этом случае у вас тоже есть ярлык ...

  3. Некоторые ассемблеры не поддерживают генерацию префиксов команд x86 для размера операнда и т. Д. В коде, написанном для этих ассемблеров, вы часто будете видеть что-то вроде:

      .byte 0x66
      mov $12, %eax
    

    Чтобы ассемблер выдал код, который вы хотите иметь.

4 голосов

Пример минимального запуска

.byte выплевывает байты, где бы вы ни находились. Независимо от того, есть метка или нет, указывающая на байт, не имеет значения.

Если вы оказались в текстовом сегменте, то этот байт может выполняться как код.

Карл упомянул об этом, но вот полный пример, чтобы дать ему возможность углубиться: реализация Linux x86_64 true с добавлением nop:

.global _start
_start:
    mov $60, %rax
    nop
    mov $0, %rdi
    syscall

производит точно такой же исполняемый файл, как:

.global _start
_start:
    mov $60, %rax
    .byte 0x90
    mov $0, %rdi
    syscall

, поскольку nop кодируется как байт 0x90.

Один вариант использования: новые инструкции

Один случай использования - это когда новые инструкции добавляются в ISA процессора, но только самые передовые версии ассемблера будут поддерживать его.

Так что сопровождающие проекта могут выбрать встроенные байты напрямую, чтобы сделать их компилируемыми на старых ассемблерах.

См., Например, этот обходной путь Spectre для ядра Linux с аналогичной директивой .inst: https://github.com/torvalds/linux/blob/94710cac0ef4ee177a63b5227664b38c95bbf703/arch/arm/include/asm/barrier.h#L23

#define CSDB    ".inst  0xe320f014"

Была добавлена ​​новая инструкция для Spectre, и ядро ​​пока решило жестко ее кодировать.

4 голосов
/ 22 августа 2015

Вот пример со встроенной сборкой:

#include <stdio.h>
void main() {
   int dst;
   // .byte 0xb8 0x01 0x00 0x00 0x00 = mov $1, %%eax
   asm (".byte 0xb8, 0x01, 0x00, 0x00, 0x00\n\t"
    "mov %%eax, %0"
    : "=r" (dst)
    : : "eax"  // tell the compiler we clobber eax
   );
   printf ("dst value : %d\n", dst);
return;
}

(см. вывод asm компилятора, а также разборка окончательного двоичного файла в проводнике компилятора Godbolt .)

Вы можете заменить .byte 0xb8, 0x01, 0x00, 0x00, 0x00 на mov $1, %%eax результат запуска будет таким же.Это указывало на то, что это может быть байт, который может представлять, например, какую-либо инструкцию или другие.

0 голосов
/ 03 сентября 2011

.byte - это директива, которая позволяет объявлять постоянный байт, известный только при проверке, без какого-либо контекста.

Из Руководства по сборке GNU:

.byte  74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value.
...