1

Suppose I'm writing my own mbr section and I want to run some C code where. To do so I need firstly initialize stack and after that call C code. I did that in a way like this

boot.S file:

.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

In my C code I have function kmain.

My linker.ld file looks like this:

OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i8086)
ENTRY(_start)

SECTIONS
{
    . = 0x7C00;
    .text : { *(.text) }
    .sig : AT(0x7DFE)
    {
        SHORT(0xaa55);
    }
}

So the question is where in memory section .bootstrap_stack placed? I dont tell linker script anything about it. But if I do then the size of output file is more than 512 bytes and I can't use it as mbr. Why after this C stack works correctly?

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
PepeHands
  • 1,368
  • 5
  • 20
  • 36

1 Answers1

2

If you use the -M option of ld so that it produces a map file, you'll see that it assigns the address 0 to .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

You can verify this by disassembling generated binary:

$ 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)

Instead of using a section that won't actually appear in your generated output, I'd recommend loading SP (not ESP) with a fixed constant that you know is safe. You also need to load SS at the same time, as the actual address of the stack is SS:SP, that is, it's located at SS * 16 + SP. For example:

_start:
     xor %ax, %ax
     mov %ax, %ds
     mov %ax, %es
     mov %ax, %ss
     mov $0x7c00, %sp  # stack grows downwards from start of boot loader
Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
  • Thanks for amazing answer, that exactly what I wanted and even more. By the way, could you explain, am I write that in my code `stack_bottom:` section is at adress 0 (as `.bootstrap_stack`) and `stack_top` is at adress `0x4000` (as `.bootstrap_stack` + it's size). And is it safe to grow stack starting from `0x7c00`. Won't it contain some useful information at the begginning? – PepeHands Dec 06 '15 at 17:34
  • 1
    @Dima The stack grows toward lower addresses. The first word pushed on the stack will be at 0000:7bfe, the next word at 0000:7bfc. These addresses aren't used by anything. Everything from 0000:0500 to 0000:7bff is free for use however you want. I'm not sure if this is what you're asking but, yes `stack_bottom` is 0 and `stack_top` is 0x4000. – Ross Ridge Dec 06 '15 at 18:58