假设我正在编写自己的mbr
部分,并且我想在其中运行一些C代码。为此,我首先需要初始化堆栈,然后调用C代码。我以这样的方式做到了
boot.S
档案:
.code16
.section .bootstrap_stack #initializing stack here
stack_bottom:
.skip 16384
stack_top:
.text
.global _start
_start:
cli
movl $stack_top, %esp
call kmain
loop:
jmp loop
在我的C代码中,我有函数kmain
。
我的linker.ld
文件如下所示:
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i8086)
ENTRY(_start)
SECTIONS
{
. = 0x7C00;
.text : { *(.text) }
.sig : AT(0x7DFE)
{
SHORT(0xaa55);
}
}
所以问题是内存部分.bootstrap_stack
放在哪里?我不会告诉链接器脚本有关它的任何信息。但是,如果我这样做,那么输出文件的大小超过512字节,我不能将其用作mbr
。为什么在此C堆栈正常工作后?
答案 0 :(得分:2)
如果你使用ld的-M
选项以便它生成一个地图文件,你会看到它将地址0分配给.bootstrap_stack
:
Name Origin Length Attributes
*default* 0x0000000000000000 0xffffffffffffffff
Linker script and memory map
0x0000000000007c00 . = 0x7c00
.text 0x0000000000007c00 0x9
*(.text)
.text 0x0000000000007c00 0x9 t95.o
0x0000000000007c00 _start
.sig 0x0000000000007c09 0x2 load address 0x0000000000007dfe
0x0000000000007c09 0x2 SHORT 0xaa55
LOAD t95.o
OUTPUT(a.out binary)
.data 0x0000000000007c0b 0x0 load address 0x0000000000007e00
.data 0x0000000000007c0b 0x0 t95.o
.bss 0x0000000000007c0b 0x0 load address 0x0000000000007e00
.bss 0x0000000000007c0b 0x0 t95.o
.bootstrap_stack
0x0000000000000000 0x4000
.bootstrap_stack
0x0000000000000000 0x4000 t95.o
您可以通过反汇编生成的二进制文件来验证这一点:
$ objdump -b binary -m i8086 --adjust-vma=0x7c00 -D a.out
...
7c00: fa cli
7c01: 66 bc 00 40 00 00 mov $0x4000,%esp
7c07: eb fe jmp 0x7c07
...
7dfd: 00 55 aa add %dl,-0x56(%di)
我建议您使用固定常数加载SP(而不是ESP),而不是使用实际出现在生成输出中的部分。您还需要同时加载SS,因为堆栈的实际地址是SS:SP,即它位于SS * 16 + SP
。例如:
_start:
xor %ax, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov $0x7c00, %sp # stack grows downwards from start of boot loader