mirror of https://github.com/tinygo-org/tinygo.git
wasmstm32webassemblymicrocontrollerarmavrspiwasiadafruitarduinocircuitplayground-expressgpioi2cllvmmicrobitnrf51nrf52nrf52840samd21tinygo
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
9.4 KiB
286 lines
9.4 KiB
3 years ago
|
/* Linker script for the ESP32-C3
|
||
|
*
|
||
|
* The ESP32-C3 has a rather funky memory layout, more like its Xtensa
|
||
|
* predecessors than like other RISC-V chips:
|
||
|
* - It has 384kB of regular RAM. This RAM can be used both as data RAM and
|
||
|
* instruction RAM, but needs to be accessed via a different address space
|
||
|
* (DRAM/IRAM).
|
||
|
* - It has another 16kB of RAM, that could be used as regular RAM but is
|
||
|
* normally used by the flash cache.
|
||
|
* - It has 8MB of address space for the DROM and IROM, but for some reason
|
||
|
* this address space is shared. So it isn't possible to map all DROM at
|
||
|
* 0x3C000000 and all DRAM at 0x42000000: they would overlap.
|
||
|
* - The MMU works in pages of 64kB, which means the bottom 16 bits of the
|
||
|
* address in flash and the address in DROM/IROM need to match.
|
||
|
* - Memory in DRAM and IRAM is loaded at reset by the ROM bootloader.
|
||
|
* Luckily, this doesn't have significant alignment requirements.
|
||
|
*
|
||
|
* This linker script has been written to carefully work around (or with) these
|
||
|
* limitations:
|
||
|
* - It adds dummy sections so that the bottom 16 bits of the virtual address
|
||
|
* and the physical address (in the generated firmware image) match.
|
||
|
* - It also offsets sections that share an address space using those same
|
||
|
* dummy sections.
|
||
|
* - It sorts the sections by load address, to avoid surprises as esptool.py
|
||
|
* also does it.
|
||
|
* This way, it's possible to create a very small firmware image that still
|
||
|
* conforms to the expectations of esptool.py and the ROM bootloader.
|
||
|
*/
|
||
|
|
||
|
MEMORY
|
||
|
{
|
||
|
/* Note: DRAM and IRAM below are actually in the same 384K address space. */
|
||
|
DRAM (rw) : ORIGIN = 0x3FC80000, LENGTH = 384K /* Internal SRAM 1 (data bus) */
|
||
|
IRAM (x) : ORIGIN = 0x40380000, LENGTH = 384K /* Internal SRAM 1 (instruction bus) */
|
||
|
|
||
|
/* Note: DROM and IROM below are actually in the same 8M address space. */
|
||
|
DROM (r) : ORIGIN = 0x3C000000, LENGTH = 8M /* Data bus (read-only) */
|
||
|
IROM (rx) : ORIGIN = 0x42000000, LENGTH = 8M /* Instruction bus */
|
||
|
}
|
||
|
|
||
|
/* The entry point. It is set in the image flashed to the chip, so must be
|
||
|
* defined.
|
||
|
*/
|
||
|
ENTRY(call_start_cpu0)
|
||
|
|
||
|
SECTIONS
|
||
|
{
|
||
|
/* Dummy section to make sure the .rodata section starts exactly behind the
|
||
|
* image header.
|
||
|
*/
|
||
|
.rodata_dummy (NOLOAD): ALIGN(4)
|
||
|
{
|
||
|
. += 0x18; /* image header at start of flash: esp_image_header_t */
|
||
|
. += 0x8; /* DROM segment header (8 bytes) */
|
||
|
} > DROM
|
||
|
|
||
|
/* Constant global variables, stored in DROM.
|
||
|
*/
|
||
|
.rodata : ALIGN(4)
|
||
|
{
|
||
|
*(.rodata .rodata.*)
|
||
|
. = ALIGN (4);
|
||
|
} >DROM
|
||
|
|
||
|
/* Put the stack at the bottom of DRAM, so that the application will
|
||
|
* crash on stack overflow instead of silently corrupting memory.
|
||
|
* See: http://blog.japaric.io/stack-overflow-protection/
|
||
|
* TODO: this might not actually work because memory protection hasn't been set up.
|
||
|
*/
|
||
|
.stack (NOLOAD) :
|
||
|
{
|
||
|
. = ALIGN(16);
|
||
|
. += _stack_size;
|
||
|
_stack_top = .;
|
||
|
} >DRAM
|
||
|
|
||
|
/* Global variables that are mutable and zero-initialized.
|
||
|
* These must be zeroed at startup (unlike data, which is loaded by the
|
||
|
* bootloader).
|
||
|
*/
|
||
|
.bss (NOLOAD) : ALIGN(4)
|
||
|
{
|
||
|
. = ALIGN (4);
|
||
|
_sbss = ABSOLUTE(.);
|
||
|
*(.sbss)
|
||
|
*(.bss .bss.*)
|
||
|
. = ALIGN (4);
|
||
|
_ebss = ABSOLUTE(.);
|
||
|
} >DRAM
|
||
|
|
||
|
/* Mutable global variables. This data (in the DRAM segment) is initialized
|
||
|
* by the ROM bootloader.
|
||
|
*/
|
||
|
.data : ALIGN(4)
|
||
|
{
|
||
|
. = ALIGN (4);
|
||
|
_sdata = ABSOLUTE(.);
|
||
|
*(.sdata)
|
||
|
*(.data .data.*)
|
||
|
. = ALIGN (4);
|
||
|
_edata = ABSOLUTE(.);
|
||
|
} >DRAM
|
||
|
|
||
|
/* Dummy section to make sure the .init section (in the IRAM segment) is just
|
||
|
* behind the DRAM segment. For IRAM and DRAM, we luckily don't have to
|
||
|
* worry about 64kB pages or image headers as they're loaded in RAM by the
|
||
|
* bootloader (not mapped from flash).
|
||
|
*/
|
||
|
.iram_dummy (NOLOAD): ALIGN(4)
|
||
|
{
|
||
|
. += SIZEOF(.stack);
|
||
|
. += SIZEOF(.bss);
|
||
|
. += SIZEOF(.data);
|
||
|
} > IRAM
|
||
|
|
||
|
/* Initialization code is loaded into IRAM. This memory area is also used by
|
||
|
* the heap, so no RAM is wasted.
|
||
|
*/
|
||
|
.init : ALIGN(4)
|
||
|
{
|
||
|
*(.init)
|
||
|
} >IRAM
|
||
|
|
||
|
/* Dummy section to put the IROM segment exactly behind the IRAM segment.
|
||
|
* This has to follow the app image format exactly.
|
||
|
*/
|
||
|
.text_dummy (NOLOAD): ALIGN(4)
|
||
|
{
|
||
|
/* Note: DRAM and DROM are not always present so the header should only
|
||
|
* be inserted if it actually exists.
|
||
|
*/
|
||
|
. += 0x18; /* esp_image_header_t */
|
||
|
. += SIZEOF(.rodata) + ((SIZEOF(.rodata) != 0) ? 0x8 : 0); /* DROM segment (optional) */
|
||
|
. += SIZEOF(.data) + ((SIZEOF(.data) != 0) ? 0x8 : 0); /* DRAM segment (optional) */
|
||
|
. += SIZEOF(.init) + 0x8; /* IRAM segment */
|
||
|
. += 0x8; /* IROM segment header */
|
||
|
} > IROM
|
||
|
|
||
|
/* IROM segment. This contains all the actual code and is placed right after
|
||
|
* the DROM segment.
|
||
|
*/
|
||
|
.text : ALIGN(4)
|
||
|
{
|
||
|
*(.text .text.*)
|
||
|
} >IROM
|
||
|
|
||
|
/DISCARD/ :
|
||
|
{
|
||
|
*(.eh_frame) /* causes 'no memory region specified' error in lld */
|
||
|
}
|
||
|
|
||
|
/* Check that the boot ROM stack (for the APP CPU) does not overlap with the
|
||
|
* data that is loaded by the boot ROM. This is unlikely to happen in
|
||
|
* practice.
|
||
|
* The magic value comes from here:
|
||
|
* https://github.com/espressif/esp-idf/blob/61299f879e/components/bootloader/subproject/main/ld/esp32c3/bootloader.ld#L191
|
||
|
*/
|
||
|
ASSERT((_edata + SIZEOF(.init)) < 0x3FCDE710, "the .init section overlaps with the stack used by the boot ROM, possibly causing corruption at startup")
|
||
|
}
|
||
|
|
||
|
/* For the garbage collector.
|
||
|
* Note that _heap_start starts after _edata (without caring for the .init
|
||
|
* section), because the .init section isn't necessary anymore after startup and
|
||
|
* can thus be overwritten by the heap.
|
||
|
*/
|
||
|
_globals_start = _sbss;
|
||
|
_globals_end = _edata;
|
||
|
_heap_start = _edata;
|
||
|
_heap_end = ORIGIN(DRAM) + LENGTH(DRAM);
|
||
|
|
||
|
_stack_size = 4K;
|
||
|
|
||
|
/* ROM functions used for setting up the flash mapping.
|
||
|
*/
|
||
|
Cache_Invalidate_ICache_All = 0x400004d8;
|
||
|
Cache_Suspend_ICache = 0x40000524;
|
||
|
Cache_Resume_ICache = 0x40000528;
|
||
|
Cache_MMU_Init = 0x4000055c;
|
||
|
Cache_Dbus_MMU_Set = 0x40000564;
|
||
|
|
||
|
/* From ESP-IDF:
|
||
|
* components/esp_rom/esp32c3/ld/esp32c3.rom.libgcc.ld
|
||
|
* These are called from LLVM during codegen. The original license is Apache
|
||
|
* 2.0.
|
||
|
*/
|
||
|
__absvdi2 = 0x40000764;
|
||
|
__absvsi2 = 0x40000768;
|
||
|
__adddf3 = 0x4000076c;
|
||
|
__addsf3 = 0x40000770;
|
||
|
__addvdi3 = 0x40000774;
|
||
|
__addvsi3 = 0x40000778;
|
||
|
__ashldi3 = 0x4000077c;
|
||
|
__ashrdi3 = 0x40000780;
|
||
|
__bswapdi2 = 0x40000784;
|
||
|
__bswapsi2 = 0x40000788;
|
||
|
__clear_cache = 0x4000078c;
|
||
|
__clrsbdi2 = 0x40000790;
|
||
|
__clrsbsi2 = 0x40000794;
|
||
|
__clzdi2 = 0x40000798;
|
||
|
__clzsi2 = 0x4000079c;
|
||
|
__cmpdi2 = 0x400007a0;
|
||
|
__ctzdi2 = 0x400007a4;
|
||
|
__ctzsi2 = 0x400007a8;
|
||
|
__divdc3 = 0x400007ac;
|
||
|
__divdf3 = 0x400007b0;
|
||
|
__divdi3 = 0x400007b4;
|
||
|
__divsc3 = 0x400007b8;
|
||
|
__divsf3 = 0x400007bc;
|
||
|
__divsi3 = 0x400007c0;
|
||
|
__eqdf2 = 0x400007c4;
|
||
|
__eqsf2 = 0x400007c8;
|
||
|
__extendsfdf2 = 0x400007cc;
|
||
|
__ffsdi2 = 0x400007d0;
|
||
|
__ffssi2 = 0x400007d4;
|
||
|
__fixdfdi = 0x400007d8;
|
||
|
__fixdfsi = 0x400007dc;
|
||
|
__fixsfdi = 0x400007e0;
|
||
|
__fixsfsi = 0x400007e4;
|
||
|
__fixunsdfsi = 0x400007e8;
|
||
|
__fixunssfdi = 0x400007ec;
|
||
|
__fixunssfsi = 0x400007f0;
|
||
|
__floatdidf = 0x400007f4;
|
||
|
__floatdisf = 0x400007f8;
|
||
|
__floatsidf = 0x400007fc;
|
||
|
__floatsisf = 0x40000800;
|
||
|
__floatundidf = 0x40000804;
|
||
|
__floatundisf = 0x40000808;
|
||
|
__floatunsidf = 0x4000080c;
|
||
|
__floatunsisf = 0x40000810;
|
||
|
__gcc_bcmp = 0x40000814;
|
||
|
__gedf2 = 0x40000818;
|
||
|
__gesf2 = 0x4000081c;
|
||
|
__gtdf2 = 0x40000820;
|
||
|
__gtsf2 = 0x40000824;
|
||
|
__ledf2 = 0x40000828;
|
||
|
__lesf2 = 0x4000082c;
|
||
|
__lshrdi3 = 0x40000830;
|
||
|
__ltdf2 = 0x40000834;
|
||
|
__ltsf2 = 0x40000838;
|
||
|
__moddi3 = 0x4000083c;
|
||
|
__modsi3 = 0x40000840;
|
||
|
__muldc3 = 0x40000844;
|
||
|
__muldf3 = 0x40000848;
|
||
|
__muldi3 = 0x4000084c;
|
||
|
__mulsc3 = 0x40000850;
|
||
|
__mulsf3 = 0x40000854;
|
||
|
__mulsi3 = 0x40000858;
|
||
|
__mulvdi3 = 0x4000085c;
|
||
|
__mulvsi3 = 0x40000860;
|
||
|
__nedf2 = 0x40000864;
|
||
|
__negdf2 = 0x40000868;
|
||
|
__negdi2 = 0x4000086c;
|
||
|
__negsf2 = 0x40000870;
|
||
|
__negvdi2 = 0x40000874;
|
||
|
__negvsi2 = 0x40000878;
|
||
|
__nesf2 = 0x4000087c;
|
||
|
__paritysi2 = 0x40000880;
|
||
|
__popcountdi2 = 0x40000884;
|
||
|
__popcountsi2 = 0x40000888;
|
||
|
__powidf2 = 0x4000088c;
|
||
|
__powisf2 = 0x40000890;
|
||
|
__subdf3 = 0x40000894;
|
||
|
__subsf3 = 0x40000898;
|
||
|
__subvdi3 = 0x4000089c;
|
||
|
__subvsi3 = 0x400008a0;
|
||
|
__truncdfsf2 = 0x400008a4;
|
||
|
__ucmpdi2 = 0x400008a8;
|
||
|
__udivdi3 = 0x400008ac;
|
||
|
__udivmoddi4 = 0x400008b0;
|
||
|
__udivsi3 = 0x400008b4;
|
||
|
__udiv_w_sdiv = 0x400008b8;
|
||
|
__umoddi3 = 0x400008bc;
|
||
|
__umodsi3 = 0x400008c0;
|
||
|
__unorddf2 = 0x400008c4;
|
||
|
__unordsf2 = 0x400008c8;
|
||
|
|
||
|
/* From ESP-IDF:
|
||
|
* components/esp_rom/esp32c3/ld/esp32c3.rom.newlib.ld
|
||
|
* These are called during codegen and thus it's a good idea to make them always
|
||
|
* available. ROM functions may also be faster than functions in IROM (that go
|
||
|
* through the flash cache) and are always available in interrupts.
|
||
|
*/
|
||
|
memset = 0x40000354;
|
||
|
memcpy = 0x40000358;
|
||
|
memmove = 0x4000035c;
|