Почему использование 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
тогда это должно работать.