Created
December 13, 2021 11:08
-
-
Save ketsuban/6bb9b243d3eceebc7e1c7e8ef2d40256 to your computer and use it in GitHub Desktop.
Linker script for a Rust executable crate targeting the GBA
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ENTRY(__start) | |
/* | |
* The GBA has two sections of work RAM: internal and external. Internal work | |
* RAM is essentially instantaneous to access and sits on a 32-bit bus, so it's | |
* suitable for ARM code. External work RAM has a delay of two clock cycles and | |
* sits on a 16-bit bus. | |
*/ | |
MEMORY { | |
rom (rx) : ORIGIN = 0x08000000, LENGTH = 32M | |
ewram (rwx) : ORIGIN = 0x02000000, LENGTH = 256K | |
iwram (rwx) : ORIGIN = 0x03000000, LENGTH = 32K | |
} | |
/* | |
* This is an implementation detail of my interrupt handler. | |
*/ | |
PROVIDE(INTERRUPT_HANDLERS = 0); | |
SECTIONS { | |
/* | |
* This section contains the ROM header so it's imperative that it go right | |
* at the beginning of the ROM. | |
*/ | |
.text.start : { | |
*(.text.__start) | |
. = ALIGN(4); | |
} >rom = 0xFF | |
.text : { | |
/* | |
* It's useful to be able to include text and data in either of the two | |
* blocks of work RAM. devkitARM, being a thoroughly C-based toolchain, | |
* does this with filename: `*.iwram.c` is compiled as ARM code and | |
* placed in internal work RAM, `*.ewram.c` is compiled as Thumb code | |
* and placed in external work RAM, `*.arm.c` is compiled as ARM code | |
* and placed in ROM, and everything else is compiled as Thumb code and | |
* placed in ROM. | |
* | |
* That won't fly in Rust, since filenames are tied up with modules, so | |
* I use the input section name - `.text.iwram*` and `.data.iwram*` are | |
* placed in internal work RAM, `.text.ewram*` and `.data.ewram*` are | |
* placed in external work RAM, everything else is placed in ROM. | |
* Unfortunately, that means I have to use this mess of glob syntax to | |
* ensure that the `.text` output section doesn't consume precisely the | |
* input sections I want it to not consume, rather than the much neater | |
* `*(.text*)`. | |
* | |
* I'm sorry. | |
*/ | |
*(.text .text.[^ie]* .text.[ie][^w]* .text.[ie]w[^r]* .text.[ie]wr[^a]* .text.[ie]wra[^m]*) | |
. = ALIGN(4); | |
} >rom = 0xFF | |
.rodata : { | |
*(.rodata*) | |
. = ALIGN(4); | |
} >rom = 0xFF | |
.text.iwram : { | |
*(.text.iwram*) | |
. = ALIGN(4); | |
} >iwram AT>rom = 0xFF | |
.data.iwram : { | |
*(.data.iwram*) | |
. = ALIGN(4); | |
} >iwram AT>rom = 0xFF | |
.text.ewram : { | |
*(.text.ewram*) | |
. = ALIGN(4); | |
} >ewram AT>rom = 0xFF | |
.data.ewram : { | |
*(.data.ewram*) | |
. = ALIGN(4); | |
} >ewram AT>rom = 0xFF | |
.data : { | |
*(.data*) | |
. = ALIGN(4); | |
} >ewram AT>rom = 0xFF | |
.bss (NOLOAD) : { | |
*(.bss*) | |
. = ALIGN(4); | |
} >iwram | |
/DISCARD/ : { | |
/* | |
* Rust has a bit of a habit of including ARM exception sections for | |
* some reason even though I'm aborting on panic, and they cause symbol | |
* lookup failures at link time if included, so I cut them off at the | |
* pass and make sure they're thrown away just in case. | |
*/ | |
*(.ARM.exidx.*) | |
} | |
} | |
/* | |
* Since the work RAM sections are contiguous in the final ROM, I only need one | |
* copy loop for each one. | |
*/ | |
__ewram_lma = LOADADDR(.text.ewram); | |
__ewram_vma = ADDR(.text.ewram); | |
__ewram_len = SIZEOF(.text.ewram) + SIZEOF(.data.ewram) + SIZEOF(.data); | |
__iwram_lma = LOADADDR(.text.iwram); | |
__iwram_vma = ADDR(.text.iwram); | |
__iwram_len = SIZEOF(.text.iwram) + SIZEOF(.data.iwram); | |
/* | |
* Any space in external work RAM not taken up by other things gets used for | |
* the global heap. | |
*/ | |
__heap_start = ORIGIN(ewram) + __ewram_len; | |
__heap_length = LENGTH(ewram) - __heap_start; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment