mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
172 lines
6.3 KiB
Plaintext
172 lines
6.3 KiB
Plaintext
/* Linker script
|
|
* The role of this script is to take all the object files built by the compiler
|
|
* and produce a single binary suitable for execution.
|
|
* Without an explicit linker script, the linker will produce a binary file that
|
|
* would not match some of our requirements (for example, we want the code to be
|
|
* written at a specific address (in Flash ROM) and the data at another. */
|
|
|
|
/* Let's instruct the linker about our memory layout.
|
|
* This will let us use shortcuts such as ">FLASH" to ask for a given section
|
|
* to be stored in Flash. */
|
|
MEMORY {
|
|
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
|
|
SRAM (rw) : ORIGIN = 0x20000000, LENGTH = 96K
|
|
/*
|
|
// We're splitting the SRAM in two: general purpose, then framebuffer
|
|
SRAM_HEAP (rwx) : ORIGIN = 0x20000000, LENGTH = 83K
|
|
SRAM_FB (rw) : ORIGIN = 0x20014C00, LENGTH = 9K
|
|
// We're putting the stack after the framebuffer. This way, if the stack was
|
|
/ to overflow, this would be visible!
|
|
SRAM_STACK (rw) : ORIGIN = 0x20017000, LENGTH = 4K
|
|
*/
|
|
}
|
|
|
|
FRAMEBUFFER_SIZE = 19200;
|
|
STACK_SIZE = 4K;
|
|
|
|
SECTIONS {
|
|
|
|
/* The ISR vector table (explained below) contains pointer to functions that
|
|
* we may want to override depending on the binary we want to produce.
|
|
* The C implementation uses _NameServiceRoutine symbols. If those symbols are
|
|
* defined elsewhere, want to use that version. If they aren't defined, we
|
|
* want to provide a default value. We'll define here the default value that
|
|
* we want to be "absolute zero" (outside of any section).
|
|
* provide here a default implementation (namely, calling crt0's _start on
|
|
* reset, and an infinite loop on HardFault). */
|
|
|
|
PROVIDE(_NMIServiceRoutine = 0);
|
|
PROVIDE(_MemManageServiceRoutine = 0);
|
|
PROVIDE(_BusFaultServiceRoutine = 0);
|
|
PROVIDE(_UsageFaultServiceRoutine = 0);
|
|
PROVIDE(_SVCallServiceRoutine = 0);
|
|
PROVIDE(_DebugMonitorServiceRoutine = 0);
|
|
PROVIDE(_PendSVServiceRoutine = 0);
|
|
PROVIDE(_SysTickServiceRoutine = 0);
|
|
PROVIDE(_WWDGServiceRoutine = 0);
|
|
PROVIDE(_PVDServiceRoutine = 0);
|
|
PROVIDE(_TampStampServiceRoutine = 0);
|
|
PROVIDE(_RtcWakeupServiceRoutine = 0);
|
|
PROVIDE(_FlashServiceRoutine = 0);
|
|
PROVIDE(_RCCServiceRoutine = 0);
|
|
PROVIDE(_EXTI0ServiceRoutine = 0);
|
|
PROVIDE(_EXTI1ServiceRoutine = 0);
|
|
PROVIDE(_EXTI2ServiceRoutine = 0);
|
|
PROVIDE(_EXTI3ServiceRoutine = 0);
|
|
PROVIDE(_EXTI4ServiceRoutine = 0);
|
|
PROVIDE(_DMA1Stream0ServiceRoutine = 0);
|
|
PROVIDE(_DMA1Stream1ServiceRoutine = 0);
|
|
PROVIDE(_DMA1Stream2ServiceRoutine = 0);
|
|
PROVIDE(_DMA1Stream3ServiceRoutine = 0);
|
|
PROVIDE(_DMA1Stream4ServiceRoutine = 0);
|
|
PROVIDE(_DMA1Stream5ServiceRoutine = 0);
|
|
PROVIDE(_DMA1Stream6ServiceRoutine = 0);
|
|
|
|
.isr_vector_table ORIGIN(FLASH) : {
|
|
/* When booting, the STM32F42xx fetches the content of address 0x0, and
|
|
* extracts from it various key infos: the initial value of the PC register
|
|
* (program counter), the initial value of the stack pointer, and various
|
|
* entry points for interrupt service routines. This data is called the
|
|
* ISR vector table.
|
|
*
|
|
* Note that address 0x0 is always an alias. It points to the beginning of
|
|
* Flash, SRAM, or integrated bootloader depending on the boot mode chosen.
|
|
* (This mode is chosen by setting BOOTn pins on the chip).
|
|
*
|
|
* We're generating the ISR vector table in C, because it's very convenient:
|
|
* using function pointers, we can easily point to the service routine for
|
|
* each interrupt.
|
|
* See ST/RM0090/p70 for more infos. */
|
|
|
|
|
|
*(.isr_vector_table)
|
|
} >FLASH
|
|
|
|
|
|
.text : {
|
|
. = ALIGN(4);
|
|
|
|
/* We have to finish defining the ISR vectors that might not have been defined
|
|
* previously. We are PROVIDing here the non-zero vectors. In other words, the
|
|
* one where we want to point to actual code.
|
|
* We're doing it here because we want those symbols to live in the .text
|
|
* section. We're simply setting the Reset vector to crt0's _start, and the
|
|
* HardFault one to crt0's _halt. */
|
|
|
|
PROVIDE(_ResetServiceRoutine = _start);
|
|
PROVIDE(_HardFaultServiceRoutine = abort);
|
|
|
|
/* C++ code calls __cxa_pure_virtual when a pure-virtual method is called.
|
|
* This is an error case, so we just redirect it to abort. */
|
|
PROVIDE(__cxa_pure_virtual = abort);
|
|
|
|
*(.text)
|
|
*(.text.*)
|
|
} >FLASH
|
|
|
|
.rodata : {
|
|
. = ALIGN(4);
|
|
*(.rodata)
|
|
*(.rodata.*)
|
|
} >FLASH
|
|
|
|
.data : {
|
|
/* The data section is written to Flash but linked as if it were in RAM.
|
|
*
|
|
* This is required because its initial value matters (so it has to be in
|
|
* persistant memory in the first place), but it is a R/W area of memory
|
|
* so it will have to live in RAM upon execution (in linker lingo, that
|
|
* translate to the data section having a LMA in Flash and a VMA in RAM).
|
|
*
|
|
* This means we'll have to copy it from Flash to RAM on initialization.
|
|
* To do this, we'll need to know the source location of the data section
|
|
* (in Flash), the target location (in RAM), and the size of the section.
|
|
* That's why we're defining three symbols that we'll use in the initial-
|
|
* -ization routine. */
|
|
. = ALIGN(4);
|
|
_data_section_start_flash = LOADADDR(.data);
|
|
_data_section_start_ram = .;
|
|
*(.data)
|
|
*(.data.*)
|
|
_data_section_end_ram = .;
|
|
} >SRAM AT> FLASH
|
|
|
|
.bss : {
|
|
/* The bss section contains data for all uninitialized variables
|
|
* So like the .data section, it will go in RAM, but unline the data section
|
|
* we don't care at all about an initial value.
|
|
*
|
|
* Before execution, crt0 will erase that section of memory though, so we'll
|
|
* need pointers to the beginning and end of this section. */
|
|
. = ALIGN(4);
|
|
_bss_section_start_ram = .;
|
|
*(.bss)
|
|
*(.bss.*)
|
|
/* The compiler may choose to allocate uninitialized global variables as
|
|
* COMMON blocks. This can be disabled with -fno-common if needed. */
|
|
*(COMMON)
|
|
_bss_section_end_ram = .;
|
|
} >SRAM
|
|
|
|
.heap : {
|
|
_heap_start = .;
|
|
/* Note: We don't increment "." here, we set it. */
|
|
. = (ORIGIN(SRAM) + LENGTH(SRAM) - FRAMEBUFFER_SIZE - STACK_SIZE);
|
|
_heap_end = .;
|
|
} >SRAM
|
|
|
|
.framebuffer : {
|
|
_framebuffer_start = .;
|
|
. += FRAMEBUFFER_SIZE;
|
|
_framebuffer_end = .;
|
|
} > SRAM
|
|
|
|
.stack : {
|
|
. = ALIGN(8);
|
|
_stack_end = .;
|
|
. += (STACK_SIZE - 8);
|
|
. = ALIGN(8);
|
|
_stack_start = .;
|
|
} >SRAM
|
|
}
|