Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rp2_common/pico_standard_link: implement customizable linker script #1547

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/rp2_common/pico_standard_link/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ if (NOT TARGET pico_standard_link)
pico_add_link_depend(${TARGET} ${LDSCRIPT})
endfunction()

function(pico_customize_linker_script TARGET LDSCRIPT_INCLUDE)
set(LDSCRIPT_INPUT ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/memmap.ld.in)
set(LDSCRIPT_GENERATED ${TARGET}.ld)
message("generating linker script at ${LDSCRIPT_GENERATED} from ${LDSCRIPT_INPUT} and ${LDSCRIPT_INCLUDE}")

add_custom_command(TARGET ${TARGET} DEPENDS ${LDSCRIPT_INCLUDE} PRE_BUILD
COMMAND ${CMAKE_C_COMPILER} -E -x c -CC ${CFLAGS} -DLD_INCLUDE=\"${LDSCRIPT_INCLUDE}\" ${LDSCRIPT_INPUT} | sed -e "s@^#.*@/*&*/@" | tr "\\\\" "\\n" > ${LDSCRIPT_GENERATED}
VERBATIM
)
set_target_properties(${TARGET} PROPERTIES PICO_TARGET_LINKER_SCRIPT ${LDSCRIPT_GENERATED})
endfunction()

function(pico_set_binary_type TARGET TYPE)
set_target_properties(${TARGET} PROPERTIES PICO_TARGET_BINARY_TYPE ${TYPE})
endfunction()
Expand Down
272 changes: 272 additions & 0 deletions src/rp2_common/pico_standard_link/memmap.ld.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
/* Based on GCC ARM embedded samples.
Defines the following symbols for use by code:
__exidx_start
__exidx_end
__etext
__data_start__
__preinit_array_start
__preinit_array_end
__init_array_start
__init_array_end
__fini_array_start
__fini_array_end
__data_end__
__bss_start__
__bss_end__
__end__
end
__HeapLimit
__StackLimit
__StackTop
__stack (== StackTop)
*/

/* defaults that can be redefined */
#define MAIN_FLASH_LENGTH 2048k
#define MAIN_RAM_LENGTH 256k
#define MAIN_RAM_ORIGIN 0x20000000
#define MAIN_ROM_REGION FLASH

#define ADDITIONAL_FLASH_REGIONS
#define ADDITIONAL_RAM_REGIONS
#define ADDITIONAL_SECTIONS

#ifdef LD_INCLUDE
#include LD_INCLUDE
#endif

MEMORY
{
FLASH(rx) : ORIGIN = 0x10000000, LENGTH = MAIN_FLASH_LENGTH
ADDITIONAL_FLASH_REGIONS
RAM(rwx) : ORIGIN = MAIN_RAM_ORIGIN, LENGTH = MAIN_RAM_LENGTH
ADDITIONAL_RAM_REGIONS
SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
}

ENTRY(_entry_point)

SECTIONS
{
/* Second stage bootloader is prepended to the image. It must be 256 bytes big
and checksummed. It is usually built by the boot_stage2 target
in the Raspberry Pi Pico SDK
*/

.flash_begin : {
__flash_binary_start = .;
} > FLASH

.boot2 : {
__boot2_start__ = .;
KEEP (*(.boot2))
__boot2_end__ = .;
} > FLASH

ASSERT(__boot2_end__ - __boot2_start__ == 256,
"ERROR: Pico second stage bootloader must be 256 bytes in size")

/* The second stage will always enter the image at the start of .text.
The debugger will use the ELF entry point, which is the _entry_point
symbol if present, otherwise defaults to start of .text.
This can be used to transfer control back to the bootrom on debugger
launches only, to perform proper flash setup.
*/

.vectors : {
__logical_binary_start = .;
KEEP (*(.vectors))
} > MAIN_ROM_REGION

.text : {
KEEP (*(.binary_info_header))
__binary_info_header_end = .;
KEEP (*(.reset))
/* TODO revisit this now memset/memcpy/float in ROM */
/* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
* FLASH ... we will include any thing excluded here in .data below by default */
*(.init)
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
*(.fini)
/* Pull all c'tors into .text */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* Followed by destructors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)

*(.eh_frame*)
. = ALIGN(4);
} > MAIN_ROM_REGION

ADDITIONAL_SECTIONS

.rodata : {
*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
. = ALIGN(4);
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
. = ALIGN(4);
} > MAIN_ROM_REGION

.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > MAIN_ROM_REGION

__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > MAIN_ROM_REGION
__exidx_end = .;

/* Machine inspectable binary information */
. = ALIGN(4);
__binary_info_start = .;
.binary_info :
{
KEEP(*(.binary_info.keep.*))
*(.binary_info.*)
} > MAIN_ROM_REGION
__binary_info_end = .;
. = ALIGN(4);

.ram_vector_table (NOLOAD): {
*(.ram_vector_table)
} > RAM

.uninitialized_data (NOLOAD): {
. = ALIGN(4);
*(.uninitialized_data*)
} > RAM

.data : {
__data_start__ = .;
*(vtable)

*(.time_critical*)

/* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
*(.text*)
. = ALIGN(4);
*(.rodata*)
. = ALIGN(4);

*(.data*)

. = ALIGN(4);
*(.after_data.*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__mutex_array_start = .);
KEEP(*(SORT(.mutex_array.*)))
KEEP(*(.mutex_array))
PROVIDE_HIDDEN (__mutex_array_end = .);

. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(SORT(.preinit_array.*)))
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);

. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);

. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
*(SORT(.fini_array.*))
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);

*(.jcr)
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM AT> MAIN_ROM_REGION
/* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */
__etext = LOADADDR(.data);

/* Start and end symbols must be word-aligned */
.scratch_x : {
__scratch_x_start__ = .;
*(.scratch_x.*)
. = ALIGN(4);
__scratch_x_end__ = .;
} > SCRATCH_X AT > MAIN_ROM_REGION
__scratch_x_source__ = LOADADDR(.scratch_x);

.scratch_y : {
__scratch_y_start__ = .;
*(.scratch_y.*)
. = ALIGN(4);
__scratch_y_end__ = .;
} > SCRATCH_Y AT > MAIN_ROM_REGION
__scratch_y_source__ = LOADADDR(.scratch_y);

.bss : {
. = ALIGN(4);
__bss_start__ = .;
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > RAM

.heap (NOLOAD):
{
__end__ = .;
end = __end__;
KEEP(*(.heap*))
__HeapLimit = .;
} > RAM

/* .stack*_dummy section doesn't contains any symbols. It is only
* used for linker to calculate size of stack sections, and assign
* values to stack symbols later
*
* stack1 section may be empty/missing if platform_launch_core1 is not used */

/* by default we put core 0 stack at the end of scratch Y, so that if core 1
* stack is not used then all of SCRATCH_X is free.
*/
.stack1_dummy (NOLOAD):
{
*(.stack1*)
} > SCRATCH_X
.stack_dummy (NOLOAD):
{
KEEP(*(.stack*))
} > SCRATCH_Y

.flash_end : {
PROVIDE(__flash_binary_end = .);
} > MAIN_ROM_REGION

/* stack limit is poorly named, but historically is maximum heap ptr */
__StackLimit = ORIGIN(RAM) + LENGTH(RAM);
__StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
__StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
__StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
__StackBottom = __StackTop - SIZEOF(.stack_dummy);
PROVIDE(__stack = __StackTop);

/* Check if data + heap + stack exceeds RAM limit */
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")

ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
/* todo assert on extra code */
}