/* -*- ld-script -*-
 *
 * Linker script for MAX80 firmware
 */

#include "sys.h"

OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv",
              "elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)

MEMORY
{
	SRAM	: org = SRAM_ADDR,  len = SRAM_SIZE
	DRAM	: org = SDRAM_ADDR, len = SDRAM_SIZE
}

SECTIONS
{
	/*
	 * Sections we do not need. This program cannot exit, so
	 * fini/destructors are never needed. Exception handling
	 * is not supported.
	 */
	 /DISCARD/	: {
		*(.note.GNU-stack)
		*(.gnu_debuglink)
		*(.gnu.lto_*)
		*(.discard)
		*(.discard.*)
		*(.dtors.*)
		*(.dtors)
		*(.fini_array)
		*(.fini_array.*)
		*(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*)
		*(.eh_frame) *(.eh_frame.*)
		*(.gcc_except_table .gcc_except_table.*)
		*(.gnu_extab*)
		*(.exception_ranges*)
		*crtbegin.o(*)
	}

	PROVIDE (__executable_start = _PC_RESET);

	.init.reset _PC_RESET : ALIGN(4) {
		PROVIDE (___reset = .);
		KEEP (*(SORT_NONE(.init.reset)))
	} >SRAM

	.init.irq _PC_IRQ : ALIGN(4) {
		PROVIDE (___irq = .);
		KEEP (*(SORT_NONE(.init.irq)))
	}

	/*
	 * Put the short data sections in the zero page.
	 * This means .bss and .sbss aren't contiguous, but
	 * all memory is intialized during FPGA load anyway.
	 */
	.sdata : ALIGN(4) {
		__SDATA_BEGIN__ = .;
		*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4)
		*(.srodata.cst2) *(.srodata .srodata.*)
		*(.sdata .sdata.* .gnu.linkonce.s.*)
	}
	.sbss : ALIGN(4) {
		*(.dynsbss)
		*(.sbss .sbss.* .gnu.linkonce.sb.*)
		*(.scommon)
	}

	HIDDEN($assert_zero_page = ASSERT((. <= 2048), "zero page overflow"));

	__global_pointer$ = 0;

	.text : ALIGN(4) {
		PROVIDE(___text = .);
		KEEP (*(SORT_NONE(.init)))
	        *(.text.unlikely .text.*_unlikely .text.unlikely.*)
		*(.text.exit .text.exit.*)
		*(.text.startup .text.startup.*)
		*(.text.hot .text.hot.*)
		*(SORT(.text.sorted.*))
		*(.text .stub .text.* .gnu.linkonce.t.*)
		/* .gnu.warning sections are handled specially by elf.em.  */
		*(.gnu.warning)
	}

	PROVIDE (__etext = .);
	PROVIDE (_etext = .);
	. = ALIGN(4);
	.rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
	.rodata1        : { *(.rodata1) }
	.sdata2         : {
		*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
	}
	.sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }

	/* Thread Local Storage sections  */
	.tdata          : {
		PROVIDE_HIDDEN (__tdata_start = .);
		*(.tdata .tdata.* .gnu.linkonce.td.*)
	}
	.tbss       : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
	.preinit_array    : {
		PROVIDE_HIDDEN (__preinit_array_start = .);
		KEEP (*(.preinit_array))
		PROVIDE_HIDDEN (__preinit_array_end = .);
	}
	.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 = .);
	}

	/* Are these necessary/supportable? */
	  .jcr          : { KEEP (*(.jcr)) }
	.data.rel.ro	: {
			*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
	}

.data           : {
		__DATA_BEGIN__ = .;
		*(.data .data.* .gnu.linkonce.d.*)
		SORT(CONSTRUCTORS)
	}
	.data1          : { *(.data1) }
	_edata = .;
	. = ALIGN(16);
	__bss_start = .;
	.bss            : {
		*(.dynbss)
		*(.bss .bss.* .gnu.linkonce.b.*)
		*(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we do not
      pad the .data section.  */
		. = ALIGN(16);
	}
	. = SEGMENT_START("ldata-segment", .);
	. = ALIGN(16);
	__BSS_END__ = .;
	_end = .;

	.stack STACK_BOTTOM : {
		KEEP (*(.stack))
	}
}
