I'm writing a baremetal kernel, and I have trouble understanding the output of ld
in the case of a NOLOAD
section. I am declaring symbols that only exists with MMU activated, so the VMA and LMA are not the same.
I used to declaring such a section like this:
_foobar_start = .;
.foobar : AT(ADDR(.foobar) - VA_PA_OFFSET)
{
*.o(.foobar.section*)
}
_foobar_end = .;
Now one of my section's content is loaded by the boot loader, so I only want to declare the VMA symbols to be used at runtime, to access the data, so I tried the NOLOAD attribute:
_foobar_start = .;
.foobar (NOLOAD) :
{
. += SIZE_OF_FOOBAR;
}
_foobar_end = .;
I know I don't care about the LMA in this case, but I expected to see something like, where LMA = VMA (see LD manual):
.foobar 0x000000004002c000 0x353c load address 0x000000004002c000
but I get something with a strange LMA that I don't make sense of:
.foobar 0x000000004002c000 0x353c load address 0x0000000001900000
If I force the VMA = LMA in the script using
.foobar (NOLOAD) : AT(_foobar_start)
everything seems fine and I see only
.foobar 0x000000004002c000 0x353c
Even without forcing VMA = LMA, the resulting ELF is ok, but I get some warnings at compile time because of other sections (toto
is another section):
warning: dot moved backwards before `.toto
and I'd like to get read of those.
Is there a reason I don't get LMA = VMA when specifying NOLOAD
?
EDIT: here is full linker file triggering the problem. I added some comments to pin points the issues
OUTPUT_ARCH(CONFIG_LINKER_ARCH)
OUTPUT_FORMAT(CONFIG_LINKER_FORMAT)
_kern_phys_base = OCRAM_BASE_PA + OCRAM_OFFSET;
_kern_offset = KERNEL_VA_PA_OFFSET;
SECTIONS
{
. = _kern_phys_base;
_start_image_addr = .;
. = ALIGN(0x1000);
_early_text_start = .;
.early_text :
{
KEEP(*(.text.boot))
KEEP(*(.text.mmu))
}
. = ALIGN(4);
.early_rodata :
{
*(.rodata.boot*)
*(.rodata.mmu*)
}
_early_text_end = .;
. = ALIGN(0x1000);
_early_data_start = .;
.early_data :
{
*(.data.boot)
}
_early_data_end = .;
. = ALIGN(0x4000);
_early_bss_start = .;
.early_bss :
{
*(.bss.mmu)
*(.bss.boot)
}
. = ALIGN(16);
_early_bss_end = .;
_early_end = .;
/*
* The following part is accessed only once the MMU has been
* activated, so we first need to jump into "high" memory
*/
. += _kern_offset;
. = ALIGN(0x1000);
_text_start = .;
.text : AT(ADDR(.text) - _kern_offset)
{
*(.text .text.*)
}
_text_end = .;
. = ALIGN(0x1000);
_rodata_start = .;
.rodata : AT(ADDR(.rodata) - _kern_offset)
{
*(.rodata*)
}
_rodata_end = .;
. = ALIGN(4);
_arm_extab_start = .;
.ARM.extab : AT(ADDR(.ARM.extab) - _kern_offset)
{
*(.ARM.extab)
}
_arm_extab_end = .;
. = ALIGN(4);
_arm_exidx_start = .;
.ARM.exidx : AT(ADDR(.ARM.exidx) - _kern_offset)
{
*(.ARM.exidx)
}
_arm_exidx_end = .;
. = ALIGN(4);
_kernel_debug_info_start = .;
_kernel_debug_info_end = .;
. = ALIGN(4);
_emergency_code_vstart = .;
_emergency_code_vend = .;
/*
* This is where I use the NOLOAD, with AT this time
* This 'archive' part is not located in OCRAM, but some
* where else in RAM
*/
_archive_point_save = .;
. = DDR_BASE_VA;
. = ALIGN(512);
_archive_start = .;
.archive_data (NOLOAD) : AT(_archive_start)
{
codes.o(.rawdata*)
}
_archive_end = .;
. = _archive_point_save;
/* Back to OCRAM VMA */
. = ALIGN(0x1000);
_data_start = .;
.data : AT(ADDR(.data) - _kern_offset)
{
*(.data*)
}
_data_end = .;
. = ALIGN(32);
_bss_start = .;
.bss : AT(ADDR(.bss) - _kern_offset)
{
*(.bss .bss.*)
}
. = ALIGN(16);
_bss_end = .;
/*
* Second location, also in RAM, just after the '.archive_data' section
* This time I didn't put the AT to show the difference in output
*/
_dyn_archive_point_save = .;
. = _archive_end;
. = ALIGN(0x1000);
_dyn_archive_start = .;
.dyn_archive (NOLOAD) :
{
. += _dyn_archive_space;
}
_dyn_archive_end = .;
. = _dyn_archive_point_save;
/* Back to OCRAM VMA */
. = ALIGN(0x1000);
_kernel_stack_guard = .;
. += 0x1000;
.stack (NOLOAD) :
{
_kernel_stack_end = .;
/* 2 pages of 4 kB */
. += 0x2000;
_kernel_stack_start = .;
}
_kernel_image_end = .;
}
And here is the output of objdump -x
:
build/kernel/kernel.elf: file format elf32-littlearm
build/kernel/kernel.elf
architecture: arm, flags 0x00000102:
EXEC_P, D_PAGED
start address 0x00910000
Program Header:
0x70000001 off 0x0003072c vaddr 0x4003072c paddr 0x0093072c align 2**2
filesz 0x000000a0 memsz 0x000000a0 flags r--
LOAD off 0x00010000 vaddr 0x00910000 paddr 0x00910000 align 2**16
filesz 0x00002828 memsz 0x00008000 flags rwx
LOAD off 0x00018000 vaddr 0x40018000 paddr 0x00918000 align 2**16
filesz 0x000199e0 memsz 0x0001fa28 flags rwx
LOAD off 0x00038000 vaddr 0x41028000 paddr 0x01928000 align 2**16
filesz 0x00000000 memsz 0x00100000 flags rw-
LOAD off 0x00039000 vaddr 0x40039000 paddr 0x40039000 align 2**16
filesz 0x00000000 memsz 0x00002000 flags rw-
LOAD off 0x00040000 vaddr 0x41000000 paddr 0x41000000 align 2**16
filesz 0x00000000 memsz 0x00028000 flags rw-
private flags = 5000200: [Version5 EABI] [soft-float ABI]
Sections:
Idx Name Size VMA LMA File off Algn
0 .early_text 000015c0 00910000 00910000 00010000 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .early_rodata 00000030 009115c0 009115c0 000115c0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .early_data 00000828 00912000 00912000 00012000 2**3
CONTENTS, ALLOC, LOAD, DATA
3 .early_bss 00004000 00914000 00914000 00012828 2**14
ALLOC
4 .text 000142d8 40018000 00918000 00018000 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
5 .rodata 000036c0 4002d000 0092d000 0002d000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .ARM.extab 0000006c 400306c0 009306c0 000306c0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .ARM.exidx 000000a0 4003072c 0093072c 0003072c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .archive_data 00028000 41000000 41000000 00040000 2**0
ALLOC
9 .data 000009e0 40031000 00931000 00031000 2**3
CONTENTS, ALLOC, LOAD, DATA
10 .bss 00006048 400319e0 009319e0 000319e0 2**3
ALLOC
11 .dyn_archive 00100000 41028000 01928000 00038000 2**0
ALLOC
12 .stack 00002000 40039000 40039000 00039000 2**0
ALLOC
13 .comment 0000002d 00000000 00000000 000319e0 2**0
CONTENTS, READONLY
14 .ARM.attributes 00000037 00000000 00000000 00031a0d 2**0
CONTENTS, READONLY
SYMBOL TABLE:
no symbols
As you can see: .archive_data
and .stack
correctly get VMA = LMA but .dyn_archive
doesn't. If I remove the AT
of .archive_data
, I get the same behavior than .dyn_archive
with the address 0x1900000
It seems my last comment is valid, as confirmed (at least to the extend of our interpretation of the manual) on the binutils ML
The warning where triggered by the "LMA goes backwards" scenario, and correctly updating LMA each time .
is updated by hand is the correct way to go.
User contributions licensed under CC BY-SA 3.0