assembly - GNU GRUB 为 Multiboot2 提供 "error: unsupported tag: 0xc"

标签 assembly x86 osdev grub2 multiboot

我尝试使用以下代码作为 Multiboot2 兼容内核的 header ,但是当我在 grub 中尝试 multiboot2 命令时,它给出了以下错误消息:

error: unsupported tag: 0xc

我的 Multiboot2 header 定义为:

section .multiboot align=4096
mbhead: dd 0xe85250d6
        dd 0
        dd 76
        dd 0 - 76 - 0xe85250d6                  ; TODO the linker and assembler get angry if we calculate this with symbols, we need to do this by hand
        dw 1                                    ; multiboot information request
        dw 0
        dd 20
        dd 1
        dd 2
        dd 6
        dw 4                                    ; console flags
        dw 0
        dd 12
        dd 0x3
        dw 5                                    ; framebuffer settings
        dw 1
        dd 12
        dd 80
        dd 25
        dd 0
        dw 0                                    ; last tag
        dw 0
        dd 8

我的project repository提供完整的源代码。我使用 make test_longmode.iso 生成 ISO。我用 QEMU 进行测试。

导致标签错误的问题是什么?如何修复它?

最佳答案

主要问题

GRUB 错误:

error: unsupported tag: 0xc

是因为您没有按照 Multiboot2 specification 对每个标签进行 8 字节对齐:

3.1.3 General tag structure

Tags constitutes a buffer of structures following each other padded when necessary in order for each tag to start at 8-bytes aligned address. Tags are terminated by a tag of type ‘0’ and size ‘8’. Every structure has following format

要轻松解决此问题,您可以在每个标记之前使用 align 8,并且可以让汇编器处理对齐。这种对齐方式不会计算到标签的长度中。

您的校验和可以更好地计算,以免因 NASM 使用截断而导致警告。这一行:

dd 0 - 76 - 0xe85250d6

可以更好地表达为:

dd 0x100000000 - 76 - 0xe85250d6
<小时/>

代码可读性

我认为这个代码片段的第一件事是它是多么不可读。引起我注意的是这条评论:

TODO the linker and assembler get angry if we calculate this with symbols, we need to do this by hand

看来您可能已经手动计算了值,因为您在尝试以其他方式执行此操作时遇到了问题。对此有帮助的 NASM 指令是 EQU directive :

3.2.4 EQU: Defining Constants

EQU defines a symbol to a given constant value: when EQU is used, the source line must contain a label. The action of EQU is to define the given label name to the value of its (only) operand. This definition is absolute, and cannot change later. So, for example,

message         db      'hello, world' 
msglen          equ     $-message

defines msglen to be the constant 12. msglen may not then be redefined later. This is not a preprocessor definition either: the value of msglen is evaluated once, using the value of $ (see section 3.5 for an explanation of $) at the point of definition, rather than being evaluated wherever it is referenced and using the value of $ at the point of reference.

通过使用 EQU,我们可以使代码更具可读性。

其次,您可以在每个标签的开头和结尾添加标签,然后让汇编器为您计算每个标签的长度。长度是每个标签的结束标签和开始标签之间的差异。

<小时/>

改进的代码

经过上述建议更改后的 NASM 汇编代码可能如下所示:

MB2_ARCH  EQU 0                                 ; 0 = x86/x86-64
MB2_LEN   EQU (mbend-mbhead)
MB2_MAGIC EQU 0xe85250d6

section .multiboot align=4096
mbhead:
        dd MB2_MAGIC                            ; Multiboot2 magic number
        dd MB2_ARCH                             ; Architecture
        dd MB2_LEN                              ; Multiboot header length
        dd 0x100000000 - MB2_LEN - MB2_ARCH - MB2_MAGIC
                                                ; Checksum

mb2_tag_info_start:
        dw 1                                    ; multiboot information request
        dw 0
        dd mb2_tag_info_end - mb2_tag_info_start
        dd 1
        dd 2
        dd 6
mb2_tag_info_end:

        align 8
mb2_tag_console_start:
        dw 4                                    ; console flags
        dw 0
        dd mb2_tag_console_end - mb2_tag_console_start
        dd 0x3
mb2_tag_console_end:

        align 8
mb2_tag_fb_start:
        dw 5                                    ; framebuffer settings
        dw 1
        dd mb2_tag_fb_end - mb2_tag_fb_start
        dd 80
        dd 25
        dd 0
mb2_tag_fb_end:

        align 8
mb2_tag_end_start:
        dw 0                                    ; last tag
        dw 0
        dd mb2_tag_end_end - mb2_tag_end_start
mb2_tag_end_end:

mbend:

这可以进一步改进,但即使这样也比原始代码片段更具可读性和自记录性。如果您更改标签或 header 的大小,系统将为您计算所有长度。如果大小发生变化,align 8 指令将为您计算正确的对齐方式。这使得代码更易于维护。

关于assembly - GNU GRUB 为 Multiboot2 提供 "error: unsupported tag: 0xc",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49310653/

相关文章:

assembly - 为什么编译器不使用 ENTER 和 LEAVE 指令?

将 C 代码转换为汇编 Mips 语言

assembly - MMX 指令和 x87 FPU 标记字

c - 用于打印字符串的自包含 C 例程

assembly - 当 eax 包含 0 时取消引用 eax 的目的是什么?

assembly - 如何在不使用标签的情况下跳转到特定行?

assembly - 像这样的除法错误 - 溢出。要手动处理此错误,请更改中断向量表中 INT 0 的地址

linux - 同一处理器上两个内核之间的缓存一致性问题

osdev - 内存映射 I/O 地址从何而来?

程序集 32 位保护模式,标签未指向定义的字符串?