/* Filename: ch32v003.ld * Author: Jake Goodwin Email: jakegoodwin@gorge.works * Date: 2025-02-28 * Description: A linker file for the WCH uC `ch32v003` that links with * the newlib C library for functionality. */ /* * I've added tons of comments so that when I come back to this file in a * couple of months I remember what I was doing. */ /*Sets the Entry point address in header of final ELF file. */ ENTRY( InterruptVector ) /*The CH32V003 has 16KiB of "Code Flash" it actually has more I think.*/ /*The CH32V003 has 2048Bytes of SRAM*/ MEMORY { /*Attributes:*/ /*R -- Read-Only Sections*/ /*W -- Read and Write Sections*/ /*X -- Sections contain executable code*/ /*A -- Allocated sections */ /*I or L -- Initialized sections */ /*! -- Invert the Meaning of any attribute */ /*Syntax:*/ /* (attr) : ORIGIN=, LENGTH = */ /*The Flash is usally listed as it's origin being at zero in linker scripts * that you can find. The refernce manual shows it starting at 0x0800 0000 * but this is actually an alias that could also point to system memory of * the area for the boot flash. */ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K BOOT1 (rx) : ORIGIN = 0x1FFFF000, LENGTH = 1920 /*System flash/boot*/ VENDR (rx) : ORIGIN = 0x1FFFF7C0, LENGTH = 128 /*Vendor Bytes*/ OPTIB (rx) : ORIGIN = 0x1FFFF800, LENGTH = 64 /*Option Bytes*/ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K } /* Sections command is used to create differnt output sections in the final elf * executable */ SECTIONS { .init : { _sinit = .; . = ALIGN(4); KEEP(*(SORT_NONE(.init))) . = ALIGN(4); _einit = .; } >FLASH AT>FLASH .text : { . = ALIGN(4); *(.text) *(.text.*) *(.rodata) *(.rodata*) *(.gnu.linkonce.t.*) . = ALIGN(4); } >FLASH AT>FLASH .fini : { KEEP(*(SORT_NONE(.fini))) . = ALIGN(4); } >FLASH AT>FLASH PROVIDE( _etext = . ); PROVIDE( _eitcm = . ); .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } >FLASH AT>FLASH .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) PROVIDE_HIDDEN (__init_array_end = .); } >FLASH AT>FLASH .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) PROVIDE_HIDDEN (__fini_array_end = .); } >FLASH AT>FLASH .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) KEEP (*crtbegin?.o(.ctors)) /* We don't want to include the .ctor section from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >FLASH AT>FLASH .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*crtbegin?.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >FLASH AT>FLASH .dalign : { . = ALIGN(4); PROVIDE(_data_vma = .); } >RAM AT>FLASH .dlalign : { . = ALIGN(4); PROVIDE(_data_lma = .); } >FLASH AT>FLASH .data : { . = ALIGN(4); __global_pointer$ = . + 0x3fc; /* This gets set in the startup code. This allows -mrelax'd code to be smaller by acting as a sort of quick reference in the gp register. */ *(.gnu.linkonce.r.*) *(.data .data.*) *(.gnu.linkonce.d.*) . = ALIGN(8); *(.sdata .sdata.*) *(.sdata2*) *(.gnu.linkonce.s.*) . = ALIGN(8); *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) . = ALIGN(4); PROVIDE( _edata = .); } >RAM AT>FLASH .bss : { . = ALIGN(4); PROVIDE( _sbss = .); *(.sbss*) *(.gnu.linkonce.sb.*) *(.bss*) *(.gnu.linkonce.b.*) *(COMMON*) . = ALIGN(4); PROVIDE( _ebss = .); } >RAM AT>FLASH PROVIDE( _end = _ebss); PROVIDE( end = . ); PROVIDE( _eusrstack = ORIGIN(RAM) + LENGTH(RAM)); /DISCARD/ : { *(.note .note.*) *(.eh_frame .eh_frame.*) *(.comment .comment.*) *(.ARM.extab* .gnu.linkonce.armextab.*) *(.ARM.exidx*) } }