0

好的,所以我一直在尝试在程序集/C 中制作两步引导加载程序,但我无法让 JMP 工作。起初我认为读取失败,但是,经过以下测试,我排除了这一点:

__asm__ __volatile__(
    "xorw %ax, %ax;"
    "movw %ax, %ds;"
    "movw %ax, %es;"
    "movb $0x02, %ah;"
    "movb $0x01, %al;"
    "movw $0x7E00, %bx;"
    "movw $0x0003, %cx;"
    "xorb %dh, %dh;"
    "int $0x13;"
    "movb 0x7E00, %al;"
    "movb $0x0e, %ah;"
    "int $0x10;"
    //"jmp 0x7E00"
);

这按预期打印了“f”(扇区的第一个字节是 0x66,这是“f”的 ASCII 代码),证明读取成功并且jmp是问题所在。这是我的代码:

__asm__(".code16\n");
__asm__(".code16gcc\n");
__asm__("jmpl $0x0000, $main\n");
void main(){
    __asm__ __volatile__(
        "xorw %ax, %ax;"
        "movw %ax, %ds;"
        "movw %ax, %es;"
        "movb $0x02, %ah;"
        "movb $0x01, %al;"
        "movw $0x7E00, %bx;"
        "movw $0x0003, %cx;"
        "xorb %dh, %dh;"
        "int $0x13;"
        "jmp $0x200;"
    );
}

运行时,我的程序只是挂起,这意味着程序可能跳转到内存中的错误位置。顺便说一句,我显然是在 VMWare 播放器下以实模式运行的。我正在使用以下命令编译它:

gcc -c -0s -march=i686 -ffreestanding -Wall -Werror boot.c -o boot.o
ld -static -Ttest.ld -nostdlib --nmagic -o boot.elf boot.o --no-check-sections
objcopy -0 binary boot.elf boot.bin

这是test.ld

ENTRY(main);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        *(.test);
    }
    .sig : AT(0x7DFE)
    {
        SHORT(0xAA55);
    }
}

注意:我已经确认这不是内联 asm 的问题——我也尝试过纯汇编实现,结果相同——我使用 C 的唯一原因是因为我打算扩展它一点,我更舒服使用 C 循环和函数...

编辑:我在这里上传了我的软盘驱动器的前三个扇区

编辑2:我无法使用任何建议让我的引导加载程序工作,并且根据@RossRidge 的建议,我编写了同一程序的汇编版本和一个简单的汇编程序来回显输入。可悲的是,这些也不起作用..

引导加载程序:

org 0x7c00
xor ax, ax
mov ds, ax
mov es, ax
mov ah, 0x02
mov al, 0x01
mov bx, 0x7E00
mov cx, 0x0003
xor dh, dh
int 0x13
jmp 0x7E00

第 3 区计划:

xor ax, ax
int 0x16
mov ah, 0xe
int 0x10

它们都用: 编译,nasm Linux/boot.S -o Linux/asm.bin并且行为与它们的 C 对应物相同..

4

2 回答 2

3

我很确定您的汇编程序正在生成错误的跳转偏移量,它可能0x7e00将当前文本部分中的相对解释为相对,但是0x7c00链接器脚本映射了它,因此您的跳转可能会0x7c00+0x7e00=0xfa00改为。作为一个丑陋的解决方法,您可以尝试jmp 0x200替代或使用间接跳转将其隐藏在您的工具中,例如mov $0x7e00, %ax; jmp *%ax. 或者jmp .text+0x200也可以工作。

另请注意,在 32 位 C 编译器中编写 16 位 asm 会生成错误代码,加载扇区的第一个字节为 0x66 也暗示了这一点,这是操作数大小覆盖前缀。由于编译器假定为 32 位模式,它将生成带有前缀的 16 位代码,在 16 位模式下运行时将切换回 32 位。一般来说,为了这样的目的滥用内联 asm 不是一个好主意,你应该使用一个单独的 asm 文件,并确保你告诉你的汇编程序代码是为 16 位实模式设计的。

PS:学习使用调试器。


更新:以下代码在使用 和 组装时可以正常nasm boot.asm -o boot.bin工作:qemubochs

org 0x7c00
xor ax, ax
mov ds, ax
mov es, ax
mov ah, 0x02
mov al, 0x01
mov bx, 0x7E00
mov cx, 0x0003
xor dh, dh
int 0x13
jmp 0x7E00

times 510-($-$$) db 0
dw 0xaa55
; second sector
times 512 db 0
; Program in sector 3:
xor ax, ax
int 0x16
mov ah, 0xe
int 0x10
jmp $
times 1536-($-$$) db 0

您可以在此处下载图片(限时优惠;))。

于 2015-05-23T21:23:05.677 回答
0

我写了很多引导加载程序。

需要有两 (2) 个单独的可执行文件,

1) the boot loader
2) the main code

所以加载的代码(主程序)可以在不对引导加载程序做任何事情的情况下更新。

引导加载程序完成后需要跳转到已知位置。

主程序需要在已知位置放置一个跳转指令,跳转到 librt 库中的一个函数。(通常是 start())

start() 将设置 I/O、堆等并调用 main()

引导加载程序的链接器命令文件和主程序的链接器命令文件都必须就已知位置的地址达成一致

已知位置通常是两个链接器命令文件的唯一部分中的唯一内容。

引导加载程序必须足够智能,以便将主程序的所有部分放置在内存中的正确区域。

主程序最好是 motorola S1(或类似)格式,而不是原始的 .elf 或 .coff 格式;否则引导加载程序会很快变得非常大。

于 2015-05-24T22:31:35.390 回答