Note that there are some explanatory texts on larger screens.

plurals
  1. POlinkscript - different link address and load address
    text
    copied!<p>I'm wring a toy OS for my raspberry pi and trying to setup the MMU. I want to split the virtual memory between 3G:1G, so I think my code should be linked at 0xC0008000, while loaded to 0x8000 on execution. (The 0x8000 is the address the current bootloaders expect to find the kernel - since they are built for linux).</p> <p>I think everything is setup fine by poking around with objdump, but it doesn't work. After some debugging with qemu, I think the bootloader doesn't find my code at all.</p> <p>I believe the problem is with my linkscript, since the kernel starts fine if I move the starting code into its own section that's both linked and loaded at 0x8000.</p> <p>I've extracted out the script and the minimal code. As following,</p> <pre><code>$ cat kernel.ld ENTRY(_start) SECTIONS { /* must == KERNLINK */ . = 0xC0008000; .text : AT(0x8000) { *(.text) } .bss : { *(.bss) } .data : { *(.data) } .rodata : { *(.rodata) } } </code></pre> <p>-</p> <pre><code>$ cat source/entry.S #include "mem.h" .globl _start _start = V2P(entry) .globl entry entry: loop$: b loop$ </code></pre> <p>(The "b loop$" won't work since it's generated as "b·c0008000" instead of using a relative branch. But never mind that part, the problem is it never reaches entry).</p> <pre><code>$ cat source/mem.h #define KERNLOAD 0x8000 #define KERNBASE 0xC0000000 #define KERNLINK (KERNBASE+KERNLOAD) #define V2P(va) ((va) - KERNBASE) </code></pre> <p>Those are the only three source files. There should be nothing interesting in the Makefile, but the output from make is,</p> <pre><code>$ make arm-none-eabi-gcc -g -Wall -c -o build/entry.o source/entry.S arm-none-eabi-ld --no-undefined -T kernel.ld build/entry.o -Map kernel.map -o build/output.elf arm-none-eabi-objcopy build/output.elf -O binary kernel.img </code></pre> <p>And objdump,</p> <pre><code>$ arm-none-eabi-objdump -h build/output.elf build/output.elf: file format elf32-littlearm Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000004 c0008000 00008000 00008000 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .ARM.attributes 00000014 00000000 00000000 00008004 2**0 CONTENTS, READONLY 2 .debug_line 0000003c 00000000 00000000 00008018 2**0 CONTENTS, READONLY, DEBUGGING 3 .debug_info 00000054 00000000 00000000 00008054 2**0 CONTENTS, READONLY, DEBUGGING 4 .debug_abbrev 00000014 00000000 00000000 000080a8 2**0 CONTENTS, READONLY, DEBUGGING 5 .debug_aranges 00000020 00000000 00000000 000080c0 2**3 CONTENTS, READONLY, DEBUGGING </code></pre> <p>I start to believe I overlooked some obvious yet precious details.</p> <p>==== update ====</p> <p>As noted in my own answer below, the confusion is caused by debugging in qemu. The breakpoints are set by virtual addresses. "b entry" doesn't work, because gdb is thinking about virtual address while MMU hasn't been enabled and we're running by physical address.</p> <p>So before MMU is enabled, we have to use "b *0x8000". This sets a breakpoint that's correctly hit. GDB seems still confused though, since it doesn't show any debugging info (no source code, like <code>0x00008004 in ?? ()</code>). That's not a big issue since I have the listing produced by "objdump -D".</p> <p>After MMU is enabled and we branch to main, gdb works perfectly. The crux is to jump to a virtual address, using an absolute branch. <code>b/bl</code> would issue relative jumps. So I use <code>ldr pc =main</code>. <code>bx</code> works too.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload