【发布时间】:2012-09-20 22:41:32
【问题描述】:
我正在练习使用程序集(在 AT&T 语法和 gnu/gas 中)编写引导程序。小程序组装链接,然后复制到虚拟磁盘的第一个扇区。 BIOS 会将其加载到0000:7c00,问题就来了。 call hello 将在运行期间从 call 0010 转换为 call 7c10。但是movw $message, %as 不会被重新定位。 ax 仍然是 0026,而不是 7c26。结果是我无法在屏幕上制作Hello World。相反,0000:0026 处的一些随机数据将显示在屏幕上。
如何在引导过程中使其正确?我应该使用某些指令更改 asm 源代码吗?还是我应该更改我的链接脚本?
谢谢!
.text
.global _start
.code16
_start:
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
call hello
jmp .
.org 0x10
hello:
movw $message, %ax
movw %ax, %bp
movw $13, %cx
movw $0x1301, %ax
movw $0x000c, %bx
movb $0, %dl
int $0x10
ret
message:
.ascii "Hello, World!"
.org 0x01fe
.byte 0x55
.byte 0xaa
我使用以下汇编和链接脚本
as -o boot.o boot.s
//generate object code
ld -Ttext 0x0 -e _start -s -o boot.out boot.o
//relocate .text to 0x0
//entry is _start
objcopy -O binary -j .text boot.out boot
//copy .text section to boot
vboxmanage convertfromraw boot boot.vdi --format VDI
//create vdi for virtual box
【问题讨论】:
-
在代码的最开始使用一个组织。选择你想要的 0 或 0x7c00。如有必要,在链接时使用相同的值。适当修改代码,以便在代码访问其数据和调用函数之前,段和偏移量具有适当的值。
-
另外,只使用 NASM 会容易得多。你不需要 ld 或 objcopy 。它可以直接将代码汇编成二进制文件(
-f bin选项)。 -
另外,添加 ss/sp 初始化,所以你肯定不会在没有堆栈的情况下运行
-
引导扇区加载代码设置这些值。根据规范,所有段寄存器都被清除,sp 设置为 7c00 并跳转到 7c00。但是,我不会假设每个 BIOS 实现或任何其他东西(如 RPL 引导加载程序)或遵循该规范的任何东西。用已知值加载 ss 和 sp 并没有太多的指令,对吧?为什么不这样做?
-
@Serge 是的,当然。我不应该在引导期间假设任何事情。明确指定任何内容可以控制一切。非常感谢!
标签: assembly ld bootstrapping att