blob: 59f6e9566c670d99c57cbd2087a23f7cfd691b50 [file] [edit]
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright © 2019 Keith Packard
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
ENTRY(@PREFIX@_start)
/*
* These values should be provided by the application. We'll include
* some phony values here to make things link for testing
*/
MEMORY
{@INIT_MEMORY@
flash (rx!w) :
ORIGIN = DEFINED(@PREFIX@__flash) ? @PREFIX@__flash : @DEFAULT_FLASH_ADDR@,
LENGTH = DEFINED(@PREFIX@__flash_size) ? @PREFIX@__flash_size : @DEFAULT_FLASH_SIZE@
ram (w!rx) :
ORIGIN = DEFINED(@PREFIX@__ram) ? @PREFIX@__ram : @DEFAULT_RAM_ADDR@,
LENGTH = DEFINED(@PREFIX@__ram_size) ? @PREFIX@__ram_size : @DEFAULT_RAM_SIZE@
}
PHDRS
{@INIT_PHDRS@
text PT_LOAD;
ram_init PT_LOAD;
ram PT_LOAD;
@TLS_PHDRS@
}
SECTIONS
{
PROVIDE(@PREFIX@@STACK@ = ORIGIN(ram) + LENGTH(ram));
@INIT_SECTIONS@
.text : {
/* code */
*(.literal.unlikely .text.unlikely .literal.unlikely.* .text.unlikely.*)
*(.literal.startup .text.startup .literal.startup.* .text.startup.*)
*(SORT(.text.sorted.*))
*(.literal .text .literal.* .text.* .opd .opd.* .branch_lt .branch_lt.* @EXTRA_TEXT_SECTIONS@)
*(.gnu.linkonce.t.*)
KEEP (*(.fini .fini.*))
@PREFIX@__text_end = .;
PROVIDE (@PREFIX@__etext = @PREFIX@__text_end);
PROVIDE (@PREFIX@_etext = @PREFIX@__text_end);
PROVIDE (@PREFIX@etext = @PREFIX@__text_end);
/* Need to pre-align so that the symbols come after padding */
. = ALIGN(@DEFAULT_ALIGNMENT@);
/* lists of constructors and destructors */
PROVIDE_HIDDEN ( @PREFIX@__preinit_array_start = . );
PROVIDE_HIDDEN ( @PREFIX@__bothinit_array_start = . );
KEEP (*(.preinit_array))
PROVIDE_HIDDEN ( @PREFIX@__preinit_array_end = . );
PROVIDE_HIDDEN ( @PREFIX@__init_array_start = . );
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array .ctors))
PROVIDE_HIDDEN ( @PREFIX@__init_array_end = . );
PROVIDE_HIDDEN ( @PREFIX@__bothinit_array_end = . );
PROVIDE_HIDDEN ( @PREFIX@__fini_array_start = . );
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array .dtors))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN ( @PREFIX@__fini_array_end = . );
} >flash AT>flash :text
.rodata : {
/* read-only data */
*(.rdata)
*(.rodata .rodata.* @EXTRA_RODATA_SECTIONS@)
*(.gnu.linkonce.r.*)
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >flash AT>flash :text
PROVIDE(@PREFIX@_pid_base = ADDR(.rodata));
.data.rel.ro : {
/* data that needs relocating */
*(.data.rel.ro .data.rel.ro.*)
} >flash AT>flash :text
/*
* Procedure linkage table. This ends up
* with an array of structs containing pointers
* to the function descriptors and iplt references
* that need to contain them after startup.
*/
@BFD_START@
.plt : {
*(.rela.iplt)
*(.rela.*)
} >flash AT>flash :text
PROVIDE( @PREFIX@__plt_start = ADDR(.plt) );
PROVIDE( @PREFIX@__plt_size = SIZEOF(.plt) );
@BFD_END@
/*
* Needs to be in its own segment with the PLT entries first
* so that the linker will compute the offsets to those
* entries correctly.
*/
.got : {
*(.got.plt)
*(.got)
} >flash AT>flash :text
.toc : {
*(.toc .toc.*)
/*
* These get written at startup, so this isn't correct,
* but they must be reachable from tocbase so we can't
* stick them in :ram
*/
*(.iplt .iplt.*)
} >flash AT>flash :text
/* additional sections when compiling with C++ exception support */
@CPP_START@
.except_ordered : {
*(.gcc_except_table *.gcc_except_table.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >flash AT>flash :text
.eh_frame_hdr : {
PROVIDE_HIDDEN ( @PREFIX@__eh_frame_hdr_start = . );
*(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*)
PROVIDE_HIDDEN ( @PREFIX@__eh_frame_hdr_end = . );
} >flash AT>flash :text
.eh_frame : {
PROVIDE_HIDDEN ( @PREFIX@__eh_frame_start = . );
KEEP (*(.eh_frame .eh_frame.*))
PROVIDE_HIDDEN ( @PREFIX@__eh_frame_end = . );
} >flash AT>flash :text
.except_unordered : {
. = ALIGN(@DEFAULT_ALIGNMENT@);
PROVIDE(@PREFIX@__exidx_start = .);
*(.ARM.exidx*)
PROVIDE(@PREFIX@__exidx_end = .);
} >flash AT>flash :text
@CPP_END@
/*
* Data values which are preserved across reset
*/
.preserve (NOLOAD) : {
PROVIDE(@PREFIX@__preserve_start__ = .);
KEEP(*(SORT_BY_NAME(.preserve.*)))
KEEP(*(.preserve))
PROVIDE(@PREFIX@__preserve_end__ = .);
} >ram AT>ram :ram
.data : @BFD_START@ ALIGN_WITH_INPUT @BFD_END@ {
*(.data .data.* @EXTRA_DATA_SECTIONS@)
*(.gnu.linkonce.d.*)
/* Need to pre-align so that the symbols come after padding */
. = ALIGN(@DEFAULT_ALIGNMENT@);
PROVIDE( @PREFIX@__global_pointer$ = . + 0x800 );
PROVIDE( @PREFIX@_gp = . + 0x8000);
*(.sdata .sdata.* .sdata2.* @EXTRA_SDATA_SECTIONS@)
*(.gnu.linkonce.s.*)
/*
* Make sure there is space for PowerPC thread-local
* stack-check value which lives before the thread
* local storage block. We can't include this in
* .tdata because the linker would then allocate TLS
* offsets for it; in reality, it lives at a known
* fixed offset outside of the usual TLS range
*/
PROVIDE( @PREFIX@__stack_chk_start = .);
KEEP (*(.stack_chk .stack_chk.*))
PROVIDE( @PREFIX@__stack_chk_end = .);
} >ram AT>flash :ram_init
PROVIDE(@PREFIX@__data_start = ADDR(.data));
PROVIDE(@PREFIX@__data_source = LOADADDR(.data));
PROVIDE(@PREFIX@__x86_gdt_ro = DEFINED(@PREFIX@__x86_gdt) ? @PREFIX@__x86_gdt - @PREFIX@__data_start + @PREFIX@__data_source : 0);
/* Thread local initialized data. This gets
* space allocated as it is expected to be placed
* in ram to be used as a template for TLS data blocks
* allocated at runtime. We're slightly abusing that
* by placing the data in flash where it will be copied
* into the allocate ram addresses by the existing
* data initialization code in crt0.
* BFD includes .tbss alignment when computing .tdata
* alignment, but for ld.lld we have to explicitly pad
* as it only guarantees usage as a TLS template works
* rather than supporting this use case.
*/
.tdata : @LLD_START@ ALIGN(@PREFIX@__tls_align) @LLD_END@ @BFD_START@ ALIGN_WITH_INPUT @BFD_END@ {
*(.tdata .tdata.* .gnu.linkonce.td.*)
PROVIDE(@PREFIX@__data_end = .);
PROVIDE(@PREFIX@__tdata_end = .);
} >ram AT>flash :@TLS_INIT_SEG@ :ram_init
PROVIDE( @PREFIX@__stack_chk_size = @PREFIX@__stack_chk_end - @PREFIX@__stack_chk_start );
PROVIDE( @PREFIX@__tdata_start = ADDR(.tdata) - @PREFIX@__stack_chk_size );
PROVIDE( @PREFIX@__tdata_source = LOADADDR(.tdata) - @PREFIX@__stack_chk_size );
PROVIDE( @PREFIX@__tdata_source_end = LOADADDR(.tdata) + SIZEOF(.tdata) );
PROVIDE( @PREFIX@__data_source_end = @PREFIX@__tdata_source_end );
PROVIDE( @PREFIX@__tdata_size = SIZEOF(.tdata) + @PREFIX@__stack_chk_size );
PROVIDE( @PREFIX@__edata = @PREFIX@__data_end );
PROVIDE( @PREFIX@_edata = @PREFIX@__data_end );
PROVIDE( @PREFIX@edata = @PREFIX@__data_end );
PROVIDE( @PREFIX@__data_size = @PREFIX@__data_end - @PREFIX@__data_start );
PROVIDE( @PREFIX@__data_source_size = @PREFIX@__data_source_end - @PREFIX@__data_source );
.tbss (NOLOAD) : {
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon)
PROVIDE( @PREFIX@__tls_end = . );
PROVIDE( @PREFIX@__tbss_end = . );
} >ram AT>ram :tls :ram
PROVIDE( @PREFIX@__tls_first = SIZEOF(.tdata) ? ADDR(.tdata) : ADDR(.tbss) );
PROVIDE( @PREFIX@__tls_base = @PREFIX@__tls_first - @PREFIX@__stack_chk_size );
PROVIDE( @PREFIX@__bss_start = ADDR(.tbss));
PROVIDE( @PREFIX@__tbss_start = ADDR(.tbss));
PROVIDE( @PREFIX@__tbss_offset = ADDR(.tbss) - @PREFIX@__tls_first );
PROVIDE( @PREFIX@__tbss_size = SIZEOF(.tbss) );
PROVIDE( @PREFIX@__tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) );
PROVIDE( @PREFIX@__tls_size = (@PREFIX@__tls_tail_extra_size ? ALIGN(@PREFIX@__tls_end, @PREFIX@__tls_align) + @PREFIX@__tls_tail_extra_size : @PREFIX@__tls_end) - @PREFIX@__tls_base );
PROVIDE( @PREFIX@__tls_size_align = (@PREFIX@__tls_size + @PREFIX@__tls_align - 1) & ~(@PREFIX@__tls_align - 1));
PROVIDE( @PREFIX@__arm32_tls_tcb_offset = MAX(8, @PREFIX@__tls_align) );
PROVIDE( @PREFIX@__arm64_tls_tcb_offset = MAX(16, @PREFIX@__tls_align) );
PROVIDE( @PREFIX@__or1k_tls_tcb_offset = MAX(16, @PREFIX@__tls_align) );
PROVIDE( @PREFIX@__sh32_tls_tcb_offset = MAX(8, @PREFIX@__tls_align) );
PROVIDE( @PREFIX@__x86_tls_tcb = ALIGN(@PREFIX@__tls_end, @PREFIX@__tls_align) );
PROVIDE( @PREFIX@__x86_tls_tcb_offset = @PREFIX@__x86_tls_tcb - @PREFIX@__tls_base );
/*
* Unlike ld.lld, ld.bfd does not advance the location counter for
* .tbss, but we actually need memory allocated for .tbss as we use
* it for the initial TLS storage.
* Create special section here just to make room.
*/
@BFD_START@
.tbss_space (NOLOAD) : {
. = ADDR(.tbss);
. = . + SIZEOF(.tbss);
} >ram AT>ram :ram
@BFD_END@
.bss (NOLOAD) : {
/*
* For the x86-32 and x86-64, we must further allocate extra
* space for the thread control block -- at a minimum, the
* TCB needs to contain a pointer to itself
* (https://akkadia.org/drepper/tls.pdf). Unlike the
* PowerPC case, the x86 TCB appears after the thread local
* variables.
* On the x86, the precise procedure to set the TCB pointer
* depends on the operating system. The system library
* should implement a __set_tcb() function to set this
* pointer (similar to OpenBSD's, https://man.openbsd.org/
*__get_tcb.2). __set_tcb() will be called by _set_tls().
*/
. = ALIGN(@PREFIX@__tls_align);
PROVIDE( @PREFIX@__tls_tail_extra_start = . );
KEEP (*(.tls_tail_extra .tls_tail_extra.*))
PROVIDE( @PREFIX@__tls_tail_extra_end = . );
PROVIDE( @PREFIX@__non_tls_bss_start = . );
*(.sbss* @EXTRA_SBSS_SECTIONS@)
*(.gnu.linkonce.sb.*)
*(.bss .bss.* @EXTRA_BSS_SECTIONS@)
*(.gnu.linkonce.b.*)
*(COMMON)
/* Align the heap */
. = ALIGN(@DEFAULT_ALIGNMENT@);
@PREFIX@__bss_end = .;
} >ram AT>ram :ram
PROVIDE( @PREFIX@__tls_tail_extra_size = @PREFIX@__tls_tail_extra_end - @PREFIX@__tls_tail_extra_start );
PROVIDE( @PREFIX@__end = @PREFIX@__bss_end );
@PREFIX@_end = @PREFIX@__bss_end;
PROVIDE( @PREFIX@end = @PREFIX@__bss_end );
PROVIDE( @PREFIX@__bss_size = @PREFIX@__bss_end - @PREFIX@__bss_start );
/* Make the rest of memory available for heap storage */
PROVIDE (@PREFIX@__heap_start = @PREFIX@__end);
PROVIDE (@PREFIX@__heap_end = @PREFIX@@STACK@ - (DEFINED(@PREFIX@@STACK@_size) ? @PREFIX@@STACK@_size : @DEFAULT_STACK_SIZE@));
PROVIDE (@PREFIX@__heap_size = @PREFIX@__heap_end - @PREFIX@__heap_start);
/* Allow a minimum heap size to be specified */
.heap (NOLOAD) : {
. += (DEFINED(@PREFIX@__heap_size_min) ? @PREFIX@__heap_size_min : 0);
} >ram :ram
/* Define a stack region to make sure it fits in memory */
.stack (NOLOAD) : {
. += (DEFINED(@PREFIX@@STACK@_size) ? @PREFIX@@STACK@_size : @DEFAULT_STACK_SIZE@);
} >ram :ram
/* Throw away C++ exception handling information */
@C_START@
/DISCARD/ : {
*(.note .note.*)
*(.eh_frame .eh_frame.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
*(.ARM.exidx*)
}
@C_END@
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1. */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions. */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2. */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2. */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions. */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3. */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF 5. */
.debug_addr 0 : { *(.debug_addr) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_names 0 : { *(.debug_names) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.debug_sup 0 : { *(.debug_sup) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
}
/*
* Check that sections that are copied from flash to RAM have matching
* padding, so that a single memcpy() of __data_size copies the correct bytes.
*/
ASSERT( @PREFIX@__data_size == @PREFIX@__data_source_size,
"ERROR: .data/.tdata flash size does not match RAM size");