Hi!
I have my kernel loaded by GRUB. Its virtual address is 0xc0000000, and it gets loaded at 2MB. I've written my own linker script to achieve this (see below), and it seemed to work quite well.
However, after I introduced a new section (.init, intended to be discarded after kernel initialisation), I noticed that the physical addresses (LMA) of the sections behind the .bss differ from their virtual address (VMA), which of course causes severe problems when the kernel is booted.
Has anybody any idea about this?
Here is my linker script:
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH("i386")
ENTRY(_start)
MEMORY
{
physical : ORIGIN = 0x00200000, LENGTH = 4M
virtual : ORIGIN = 0xc0000000, LENGTH = 4M
}
PHDRS
{
text PT_LOAD ;
init PT_LOAD ;
}
SECTIONS
{
. = 0xc0000000;
PROVIDE(stext = .);
PROVIDE(_stext = .);
.text :
{ *(.text)
*(.rel.text) }
>virtual AT>physical : text
PROVIDE(etext = .);
PROVIDE(_etext = .);
PROVIDE(sdata = .);
PROVIDE(_sdata = .);
.data :
{ *(.data)
*(.sdata)
*(.rodata) }
>virtual AT>physical : text
PROVIDE(edata = .);
PROVIDE(_edata = .);
PROVIDE(sbss = .);
PROVIDE(_sbss = .);
.bss :
{ *(.bss)
*(.sbss)
*(COMMON) }
>virtual AT>physical : text
PROVIDE(ebss = .);
PROVIDE(_ebss = .);
PROVIDE(end = .);
PROVIDE(_end = .);
PROVIDE(sinit = .);
PROVIDE(_sinit = .);
.init :
{ *(.init.text)
*(.init.data)
*(.init.bss)
*(.rel.init.text) }
>virtual AT>physical : init
PROVIDE(einit = .);
PROVIDE(_einit = .);
/DISCARD/ : { *(.note) *(.comment) }
}
Output of objdump -h kernel:
kernel: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00001c50 c0000000 00200000 00001000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000a40 c0001c60 00201c60 00002c60 2**5
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000008 c00026a0 002026a0 000036a0 2**2
ALLOC
3 .init 000010e0 c00026c0 00202698 000036c0 2**5 // 26c0 != 2698
CONTENTS, ALLOC, LOAD, CODE
M. Schütz