Почему использование jmp не позволяет ассемблеру Clang вычислить абсолютное выражение для.fill?

Я возился с написанием простого загрузчика игрушек (дополнительная информация внизу поста). Следующие nasm Код показывает, как выглядел загрузчик в какой-то момент, прежде чем я попытался переключиться на Clang. Когда скомпилировано с использованием nasm -f bin -o nasm.out boot.asm, а затем запустить с помощью qemu-system-i386 nasm.outпечатает бесконечный поток ! символы на экране:

bits 16
global main
main:
    mov ah, 0x0e
    mov al, '!'
    int 0x10
    jmp main
times 510 - ($ - $$) db 0x00
db 0x55
db 0xaa

Мне было любопытно, смогу ли я использовать Clang в качестве моего ассемблера вместо nasm, поэтому я попытался перевести программу на то, что я считаю эквивалентным синтаксису GAS:

.code16
.global main
main:
    mov $0x0e, %ah
    mov $'!', %al
    int $0x10
    jmp main
.fill 510 - (. - main)
.byte 0x55
.byte 0xaa

Однако при компиляции с использованием /usr/local/opt/llvm/bin/clang --target=i386-elf -m16 -c boot.s -o boot.oЯ получаю следующую ошибку:

boot.s:9:7: error: expected absolute expression
.fill 510 - (. - main)
      ^

Компиляция завершится успешно, если jmp main заменяется на jmp *0x00 или неjmp инструкция. Это не совсем эквивалентно, но, похоже, указывает на что-то в отношении лейбла, который вызывает проблемы с Clang.

nasm не было проблем с определением количества байтов для заполнения. Почему Кланг отказывается, когда я прошу его сделать то же самое? Есть ли какая-то тонкая (или очевидная) вещь, которую я пропустил?

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

Я использую Clang 4.0, установленный через Homebrew, на macOS 10.12.6.


  • Быстрое обновление загрузчика, если вам это нужно: загрузочный сектор имеет длину 512 байт и должен иметь значения 0x55 а также 0xaa со смещением 510 и 511 соответственно. Самый простой способ убедиться в том, что двоичный вывод имеет длину ровно 512 байт и имеет 0x55 а также 0xaa как его последние два байта.

1 ответ

Кажется, это ошибка в ассемблере Apple. Хотя ассемблер проходит один проход, расчет . - main должен быть разрешаем до абсолютного значения.

Вы должны быть в состоянии заменить .fill с .org 510 директива для продвижения счетчика местоположения 510 байт от начала текущего раздела. Из руководства:

7.68 .org new-lc, заполните

Переместите счетчик местоположения текущего раздела в new-lc. new-lc - это либо абсолютное выражение, либо выражение с тем же разделом, что и текущий подраздел. То есть вы не можете использовать.org для сечения: если new-lc имеет неправильный раздел, директива.org игнорируется. Чтобы быть совместимым с прежними ассемблерами, если раздел new-lc является абсолютным, поскольку выдает предупреждение, то делает вид, что раздел new-lc совпадает с текущим подразделом.

[Надрез]

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

Это должно работать:

.code16
.global main
main:
    mov $0x0e, %ah
    mov $'!', %al
    int $0x10
    jmp main
.org 510
.byte 0x55
.byte 0xaa

Я смог воспроизвести вашу проблему с clang-900.0.39.2и использование .org работал с этой версией.

Clang имеет свой собственный ассемблер, который не понимает весь синтаксис GNU-ассемблера. Попробуйте вместо этого собрать с ассемблером GNU, то есть используя as --32 -o boot.o boot.sтогда это должно работать.

Другие вопросы по тегам