/*
* rvos.ld
* Linker script for outputting to RVOS
*/
#include "platform.h"
/*
* https://sourceware.org/binutils/docs/ld/Miscellaneous-Commands.html
* OUTPUT_ARCH command specifies a particular output machine architecture.
* "riscv" is the name of the architecture for both 64-bit and 32-bit
* RISC-V target. We will further refine this by using -march
* and -mabi when calling gcc.
*/
OUTPUT_ARCH( "riscv" )
/*
* https://sourceware.org/binutils/docs/ld/Entry-Point.html
* ENTRY command is used to set the "entry point", which is the first instruction
* to execute in a program.
* The argument of ENTRY command is a symbol name, here is "_start" which is
* defined in start.S.
*/
ENTRY( _start )
/*
* https://sourceware.org/binutils/docs/ld/MEMORY.html
* The MEMORY command describes the location and size of blocks of memory in
* the target.
* The syntax for MEMORY is:
* MEMORY
* {
* name [(attr)] : ORIGIN = origin, LENGTH = len
* ......
* }
* Each line defines a memory region.
* Each memory region must have a distinct name within the MEMORY command. Here
* we only define one region named as "ram".
* The "attr" string is an optional list of attributes that specify whether to
* use a particular memory region for an input section which is not explicitly
* mapped in the linker script. Here we assign 'w' (writeable), 'x' (executable),
* and 'a' (allocatable). We use '!' to invert 'r' (read-only) and
* 'i' (initialized).
* The "ORIGIN" is used to set the start address of the memory region. Here we
* place it right at the beginning of 0x8000_0000 because this is where the
* QEMU-virt machine will start executing.
* Finally LENGTH = 128M tells the linker that we have 128 megabyte of RAM.
* The linker will double check this to make sure everything can fit.
*/
MEMORY
{
ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = LENGTH_RAM
}
/*
* https://sourceware.org/binutils/docs/ld/SECTIONS.html
* The SECTIONS command tells the linker how to map input sections into output
* sections, and how to place the output sections in memory.
* The format of the SECTIONS command is:
* SECTIONS
* {
* sections-command
* sections-command
* ......
* }
*
* Each sections-command may of be one of the following:
* (1) an ENTRY command
* (2) a symbol assignment
* (3) an output section description
* (4) an overlay description
* We here only demo (2) & (3).
*
* We use PROVIDE command to define symbols.
* https://sourceware.org/binutils/docs/ld/PROVIDE.html
* The PROVIDE keyword may be used to define a symbol.
* The syntax is PROVIDE(symbol = expression).
* Such symbols as "_text_start", "_text_end" ... will be used in mem.S.
* Notice the period '.' tells the linker to set symbol(e.g. _text_start) to
* the CURRENT location ('.' = current memory location). This current memory
* location moves as we add things.
*/
SECTIONS
{
/*
* We are going to layout all text sections in .text output section,
* starting with .text. The asterisk("*") in front of the
* parentheses means to match the .text section of ANY object file.
*/
.text : {
PROVIDE(_text_start = .);
*(.text .text.*)
PROVIDE(_text_end = .);
} >ram
.rodata : {
PROVIDE(_rodata_start = .);
*(.rodata .rodata.*)
PROVIDE(_rodata_end = .);
} >ram
.data : {
/*
* . = ALIGN(4096) tells the linker to align the current memory
* location to 4096 bytes. This will insert padding bytes until
* current location becomes aligned on 4096-byte boundary.
* This is because our paging system's resolution is 4,096 bytes.
*/
. = ALIGN(4096);
PROVIDE(_data_start = .);
/*
* sdata and data are essentially the same thing. We do not need
* to distinguish sdata from data.
*/
*(.sdata .sdata.*)
*(.data .data.*)
PROVIDE(_data_end = .);
} >ram
.bss :{
/*
* https://sourceware.org/binutils/docs/ld/Input-Section-Common.html
* In most cases, common symbols in input files will be placed
* in the ‘.bss’ section in the output file.
*/
PROVIDE(_bss_start = .);
*(.sbss .sbss.*)
*(.bss .bss.*)
*(COMMON)
PROVIDE(_bss_end = .);
} >ram
PROVIDE(_memory_start = ORIGIN(ram));
PROVIDE(_memory_end = ORIGIN(ram) + LENGTH(ram));
PROVIDE(_heap_start = _bss_end);
PROVIDE(_heap_size = _memory_end - _heap_start);
}