Какая польза от директивы ассемблера.byte в сборке GNU?

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

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

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

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

4 ответа

Решение

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

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

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

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

      .byte 0x66
      mov $12, %eax
    

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

Минимальный работоспособный пример

.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"

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

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

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

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

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

.byte  74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value.
Другие вопросы по тегам