From 962b209f30d18d5aaff585a0385cfd4cda4e8f02 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 17 Aug 2021 13:15:50 +0200 Subject: [PATCH] switched to a real linker script --- kinclude/boot.S | 8 +- linker.ld | 264 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 238 insertions(+), 34 deletions(-) diff --git a/kinclude/boot.S b/kinclude/boot.S index 754c435..59d1d63 100644 --- a/kinclude/boot.S +++ b/kinclude/boot.S @@ -33,12 +33,12 @@ _start: .option norelax // init sp and gp la sp, stack_top - la gp, __global_pointer$ + la gp, _gp .option pop // clear kernel bss section mv a0, zero - la a1, __bss_start - la a2, __bss_end + la a1, _bss_start + la a2, _bss_end jal memset // jump to init @@ -97,7 +97,7 @@ trap_vector: .option push .option norelax la sp, stack_top - la gp, __global_pointer$ + la gp, _gp .option pop jal trap_handle diff --git a/linker.ld b/linker.ld index 2248c5d..720ee42 100644 --- a/linker.ld +++ b/linker.ld @@ -1,32 +1,236 @@ -OUTPUT_ARCH("riscv") -ENTRY(_start) +/*======================================================================*/ +/* EMBARK linker script, based on the Default maven linker script */ +/*======================================================================*/ +/* for the original file, see: + https://github.com/pulp-platform/pulp-riscv-gnu-toolchain/blob/49dea1915979fdf91eb2ad4a8873e4cd88a6b811/riscv.ld */ +/* I modified the original file minimally, + +/* This is the default linker script for maven. It is based off of the + mips idt32.ld linker script. I have added many more comments and + tried to clean things up a bit. For more information about standard + MIPS sections see Section 9.5 of "See MIPS Run Linux" by Dominic + Sweetman. For more generic information about the init, fini, ctors, + and dtors sections see the paper titled "ELF From the Programmers + Perspective" by Hongiu Lu. */ + +/*----------------------------------------------------------------------*/ +/* Setup */ +/*----------------------------------------------------------------------*/ + +/* The OUTPUT_ARCH command specifies the machine architecture where the + argument is one of the names used in the BFD library. More + specifically one of the entires in bfd/cpu-mips.c */ + +OUTPUT_ARCH( "riscv" ) + +/* The ENTRY command specifies the entry point (ie. first instruction to + execute). The symbol _start is defined in crt0.S */ + +ENTRY( _start ) + +/* The GROUP command is special since the listed archives will be + searched repeatedly until there are no new undefined references. We + need this since -lc depends on -lgloss and -lgloss depends on -lc. I + thought gcc would automatically include -lgcc when needed, but + idt32.ld includes it explicitly here and I was seeing link errors + without it. */ + +GROUP( -lc -lgloss -lgcc ) + +/*----------------------------------------------------------------------*/ +/* Sections */ +/*----------------------------------------------------------------------*/ +/* This is where we specify how the input sections map to output + sections. The .= commands set the location counter, and the + sections are inserted in increasing address order according to the + location counter. The following statement will take all of the .bar + input sections and reloate them into the .foo output section which + starts at address 0x1000. + + . = 0.x1000; + .foo : { *(.bar) } + + If we wrap an input specification with a KEEP command then it + prevents it from being eliminted during "link-time garbage + collection". I'm not sure what this is, so I just followed what was + done in idt32.ld. + + We can also set a global external symbol to a specific address in the + output binary with this syntax: + + _etext = .; + PROVIDE( etext = . ); + + This will set the global symbol _ftext to the current location. If we + wrap this in a PROVIDE commad, the symbol will only be set if it is + not defined. We do this with symbols which don't begin with an + underscore since technically in ansi C someone might have a function + with the same name (eg. etext). + + If we need to label the beginning of a section we need to make sure + that the linker doesn't insert an orphan section inbetween where we + set the symbol and the actual begining of the section. We can do that + by assigning the location dot to itself. + + . = . + _ftext = .; + .text : + { } + + */ + SECTIONS { - /* start at an address > 12bit to ensure all addresses are loaded using auipc+addi instead of only addi (which is not relocatable)*/ - . = 0xffffff; - .text : - { - *(.text._start) - *(.text) - } - .sdata : - { - __global_pointer$ = . + 0x800; - *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) - *(.sdata .sdata.* .gnu.linkonce.s.*) - } - _edata = .; PROVIDE (edata = .); - . = .; - __bss_start = .; - .sbss : - { - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - } - __bss_end = .; - .stack : - { - *(.stack) - } -} \ No newline at end of file + + /*--------------------------------------------------------------------*/ + /* Code and read-only segment */ + /*--------------------------------------------------------------------*/ + + /* Begining of code and text segment */ + . = 0x00010000; + _ftext = .; + PROVIDE( eprol = . ); + + /* text: Program code section */ + .text : + { + *(.text._start) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + + /* init: Code to execute before main (called by crt0.S) */ + .init : + { + KEEP( *(.init) ) + } + + /* fini: Code to execute after main (called by crt0.S) */ + .fini : + { + KEEP( *(.fini) ) + } + + /* End of code and read-only segment */ + PROVIDE( etext = . ); + _etext = .; + + /*--------------------------------------------------------------------*/ + /* Global constructor/destructor segement */ + /*--------------------------------------------------------------------*/ + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array )) + PROVIDE_HIDDEN (__init_array_end = .); + } + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array )) + PROVIDE_HIDDEN (__fini_array_end = .); + } + + /* rodata: Read-only data */ + .rodata : + { + *(.rdata) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + } + + /*--------------------------------------------------------------------*/ + /* Other misc gcc segments (this was in idt32.ld) */ + /*--------------------------------------------------------------------*/ + /* I am not quite sure about these sections but it seems they are for + C++ exception handling. I think .jcr is for "Java Class + Registration" but it seems to end up in C++ binaries as well. */ + + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : { KEEP( *(.eh_frame) ) } + .gcc_except_table : { *(.gcc_except_table) } + .jcr : { KEEP (*(.jcr)) } + + /*--------------------------------------------------------------------*/ + /* Initialized data segment */ + /*--------------------------------------------------------------------*/ + + /* Start of initialized data segment */ + . = ALIGN(16); + _fdata = .; + + /* data: Writable data */ + .data : + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + } + + /* End of initialized data segment */ + PROVIDE( edata = . ); + _edata = .; + + /* Have _gp point to middle of sdata/sbss to maximize displacement range */ + . = ALIGN(16); + _gp = . + 0x800; + + /* Writable small data segment */ + .sdata : + { + *(.sdata) + *(.sdata.*) + *(.srodata.*) + *(.gnu.linkonce.s.*) + } + + /*--------------------------------------------------------------------*/ + /* Uninitialized data segment */ + /*--------------------------------------------------------------------*/ + + /* Start of uninitialized data segment */ + . = ALIGN(8); + _fbss = .; + _bss_start = .; + + /* Writable uninitialized small data segment */ + .sbss : + { + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + } + + /* bss: Uninitialized writeable data section */ + . = .; + .bss : + { + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + } + _bss_end = .; + + .stack : + { + *(.stack) + } + + /* End of uninitialized data segment (used by syscalls.c for heap) */ + PROVIDE( end = . ); + _end = ALIGN(8); +}