【问题标题】:stack initialization in mbrmbr 中的堆栈初始化
【发布时间】:2015-12-06 12:17:45
【问题描述】:

假设我正在编写自己的 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 栈正常工作之后?

【问题讨论】:

    标签: assembly x86 mbr


    【解决方案1】:

    如果您使用 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
    

    【讨论】:

    • 感谢您的精彩回答,这正是我想要的,甚至更多。顺便说一句,你能解释一下吗,我在我的代码中写道stack_bottom: 部分位于地址0(如.bootstrap_stack)和stack_top 位于地址0x4000(如.bootstrap_stack + 它的大小)。从0x7c00 开始增长堆栈是否安全。一开始不会包含一些有用的信息吗?
    • @Dima 堆栈向低地址增长。压入堆栈的第一个单词将在 0000:7bfe,下一个单词在 0000:7bfc。这些地址不被任何东西使用。从 0000:0500 到 0000:7bff 的所有内容都可以根据需要免费使用。我不确定这是否是您要问的,但是,stack_bottom 是 0,stack_top 是 0x4000。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 2017-09-24
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    相关资源
    最近更新 更多