Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 如何使用GCC生成一个最小的BIOS hello world引导扇区,该扇区可以在真实硬件上使用USB棒工作?_Assembly_X86_Qemu_Gnu Assembler_Bare Metal - Fatal编程技术网

Assembly 如何使用GCC生成一个最小的BIOS hello world引导扇区,该扇区可以在真实硬件上使用USB棒工作?

Assembly 如何使用GCC生成一个最小的BIOS hello world引导扇区,该扇区可以在真实硬件上使用USB棒工作?,assembly,x86,qemu,gnu-assembler,bare-metal,Assembly,X86,Qemu,Gnu Assembler,Bare Metal,我已经成功地生成了一个最小的引导扇区,它与QEMU 2.0.0 Ubuntu 14.04一起工作: .code16 .global _start _start: cli mov $msg, %si mov $0x0e, %ah loop: lodsb or %al, %al jz halt int $0x10 jmp loop halt: hlt msg: .asciz "hello world" .org 510

我已经成功地生成了一个最小的引导扇区,它与QEMU 2.0.0 Ubuntu 14.04一起工作:

.code16
.global _start
_start:
    cli
    mov $msg, %si
    mov $0x0e, %ah
loop:
    lodsb
    or %al, %al
    jz halt
    int $0x10
    jmp loop
halt:
    hlt
msg:
    .asciz "hello world"
.org 510
.word 0xaa55
汇编时使用:

as -o main.o main.S
ld --oformat binary -o main.img -Ttext 0x7C00 main.o
本回购协议中提供了以下示例:

在:

它在模拟器屏幕上按预期显示hello world

但如果我尝试刻录到USB:

sudo dd if=main.img of=/dev/sdb
然后将USB插入ThinkPad T400或T430,点击F12,然后选择我观察到的USB:

一些启动消息会很快显示出来 然后屏幕变为空白,顶部只有一个下划线光标 我还用Ubuntu 14.04映像测试了相同的USB,它启动得很好,所以USB正常工作

我应该如何更改此示例,使其在硬件上启动并显示hello world消息

Ubuntu映像和我创建的映像有什么区别

这在哪里有记录


我已将T400上sudo dmidecode的输出上传到:

正如@Jester所述,我必须使用以下命令将DS归零:

请注意,不可能立即将mov传输到ds:我们必须通过ax:

所以问题的根源是QEMU的初始状态和实际硬件的初始状态之间的差异

我现在将以下16位初始化代码添加到我的所有引导加载程序中,以保证更干净的初始状态。迈克尔·佩奇在评论中提到,并非所有这些都是强制性的

 .code16
cli
/* This sets %cs to 0. TODO Is that really needed? */
ljmp $0, $1f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
/* The other segments are not mandatory. TODO source */
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
/*
TODO What to move into BP and SP? https://stackoverflow.com/questions/10598802/which-value-should-be-used-for-sp-for-booting-process
Setting BP does not seem mandatory for BIOS.
*/
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp
我还发现了这个密切相关的问题:

9.10.2 STARTUP.ASM清单
包含一个大型初始化示例。

至少应将DS归零。除设置DS外,还应明确设置堆栈段SS,尤其是在开始使用BIOS例程时。您也有点幸运,因为QEMU和其他模拟器在调用启动代码时对您更友好。当bios调用引导加载程序时,CS段不一定必须为0。段:偏移量将等效于0x0000:0x7c00,但CS可以是其他值,如0x07c0 0x07c0:0x0000。为了避免这种情况,您应该对代码中的标签执行远jmp,并将CS设置为0x0000。在真正的硬件上,这可能是一个问题。@MichaelPetch感谢您提供更多提示!我觉得QEMU没有很好地模仿我的硬件更不走运:-我将更仔细地研究您提到的寄存器段。我以前从来没有很好地理解过它们,因为操作系统对我隐藏了它们。几个月前,我使用了25年前编写的引导加载程序,并将其更新为使用at&t语法,并可使用GNU Assembler在Throwback星期四编译。你可以找到它。它使用CLI在执行远跳转之前关闭中断,然后设置堆栈和ES、DS寄存器。您的代码是英特尔语法,但您应该对我所做的有一个大致的了解。此引导加载程序设计为从软盘上运行此代码用于2.88MB 3.5floppy@RossRidge不幸的是,在真正的硬件中,你不能依赖于0。一些旧的bios特别喜欢使用0x07C0:0000。与0x0000:0x7C00相同的物理内存位置。通过对本地标签执行far jmp,可以确保使用的是已知的CS。当然,它不需要为零,但无论您的代码写入的源代码是什么,都必须由CS匹配。在过去,远jmp到本地标签是确保我们拥有我们期望的CS而不是BIOS可能使用的CS的简单方法。我提供的示例代码执行简单的far jmp方法。提示:要调零寄存器,请使用xor%reg,%reg。这将机器代码的长度从三个字节减少到一个字节,在现代8086兼容机上速度更快。只需使用xor%ax,%ax而不是mov$0,%ax即可。@fuzzxl谢谢!我已经看到了,但它没有进入我的习惯:-固定。BIOS例程不需要设置FS和GS。ES不需要设置,除非特定的BIOS例程需要它作为传入参数的一部分。至于BP,它可以用于任何事情。它不需要初始化,除非您有理由使用它。BIOS调用不使用堆栈帧,也不要求在自己的代码中使用堆栈帧,除非您试图与某种类型的约定兼容。BIOS不在乎。如果BIOS调用需要BP作为参数,文档会说列出该要求,并且只需要在调用之前进行设置。学生:SP是一个不同的故事。BIOS例程和中断需要一个可用的SS:SP。我遇到了完全相同的问题,并通过您的解决方案得到了解决:在引导扇区代码的开头将DS和ES寄存器归零:xor ax、ax和mov DS、ax和mov ES、ax。
@@ -4,2 +4,4 @@ _start:
     cli
+    xor %ax, %ax
+    mov %ax, %ds
     mov $msg, %si
 .code16
cli
/* This sets %cs to 0. TODO Is that really needed? */
ljmp $0, $1f
1:
xor %ax, %ax
/* We must zero %ds for any data access. */
mov %ax, %ds
/* The other segments are not mandatory. TODO source */
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
/*
TODO What to move into BP and SP? https://stackoverflow.com/questions/10598802/which-value-should-be-used-for-sp-for-booting-process
Setting BP does not seem mandatory for BIOS.
*/
mov %ax, %bp
/* Automatically disables interrupts until the end of the next instruction. */
mov %ax, %ss
/* We should set SP because BIOS calls may depend on that. TODO confirm. */
mov %bp, %sp