mbr 中的堆栈初始化
stack initialization in mbr
假设我正在编写自己的 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 堆栈正常工作之后?
如果你使用 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 [=11=]x4000,%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 [=12=]x7c00, %sp # stack grows downwards from start of boot loader
假设我正在编写自己的 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 堆栈正常工作之后?
如果你使用 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 [=11=]x4000,%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 [=12=]x7c00, %sp # stack grows downwards from start of boot loader