为什么使用 jmp 会阻止 Clang 汇编程序找出 .fill 的绝对表达式?

awk*_*ksp 6 macos x86 assembly clang bootloader

我正在编写一个简单的玩具引导加载程序(帖子底部的附加信息)。以下nasm代码显示了在我尝试切换到 Clang 之前的某个时刻引导加载程序的样子。当编译 using nasm -f bin -o nasm.out boot.asm,然后运行 ​​using 时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
Run Code Online (Sandbox Code Playgroud)

我很好奇我是否可以使用 Clang 作为我的汇编程序而不是 nasm,所以我尝试将程序翻译成我认为与 GAS 语法等效的内容:

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

但是,当使用编译时/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)
      ^
Run Code Online (Sandbox Code Playgroud)

如果jmp main替换为jmp *0x00或 非jmp指令,则编译成功。它不是严格等效的,但它似乎指向了一些给 Clang 问题的标签。

nasm确定用于填充的字节数没有任何问题。为什么 Clang 在我要求它做同样的事情时犹豫不决?我错过了一些微妙(或明显)的东西吗?

我总是可以手动计算出我需要多少字节的填充,但这既乏味又容易出错,而且似乎汇编程序应该能够自行完成。

我正在 macOS 10.12.6 上运行通过 Homebrew 安装的 Clang 4.0。


  • 快速引导加载程序复习(如果需要):引导扇区长 512 字节,并且需要分别在偏移 510 和 511 处具有值0x550xaa。确保这一点的简单方法是确保二进制输出的长度恰好为 512 字节,并且将0x550xaa作为其最后两个字节。

Mic*_*tch 3

这似乎是苹果汇编程序中的一个错误。虽然汇编程序是单遍,但计算. - main应该可以解析为绝对值。

\n\n

您应该能够将 替换.fill.org 510指令,将位置计数器从当前节的开头前进 510 个字节。来自手册中:

\n\n
\n

7.68 .org new-lc , 填充

\n\n

将当前节的位置计数器前进到 new-lc。new-lc 是绝对表达式或与当前子节具有相同节的\n 表达式。也就是说,\n 您可以\xe2\x80\x99t 使用 .org 来交叉部分:如果 new-lc 有错误的部分,\n .org 指令将被忽略。为了与以前的汇编器兼容,如果 new-lc 的部分是绝对的,则发出警告,然后假装 new-lc 的部分与当前子部分相同。

\n\n

[剪]

\n\n

请注意,原点是相对于该节的开头,而不是相对于该小节的开头。这与其他人\xe2\x80\x99s\n 汇编器兼容。

\n
\n\n

这应该有效:

\n\n
.code16\n.global main\nmain:\n    mov $0x0e, %ah\n    mov $\'!\', %al\n    int $0x10\n    jmp main\n.org 510\n.byte 0x55\n.byte 0xaa\n
Run Code Online (Sandbox Code Playgroud)\n\n

我能够重现您的问题clang-900.0.39.2,并使用.org该版本的工作。

\n