/* Linker script for the fxcg50 platform. */ OUTPUT_FORMAT("elf32-sh", "elf32-sh", "elf32-sh") OUTPUT_ARCH(sh4) ENTRY(_initialize) /* ** Linker script for user executables. */ MEMORY { /* virtual memory, read-write segment */ userram (WX) : o = 0x00000000, l = 1M } SECTIONS { /* Code */ .text : { *(.text); *(.text.*); _bctors = . ; *(.ctors .ctors.*) _ectors = . ; _bdtors = . ; *(.dtors .dtors.*) _edtors = . ; } > userram /* vhex's interrupt handler blocks (.vhex.blocks) Although vhex's blocks end up in VBR space, they are relocated at startup by the library/drivers, so we store them here for now */ .vhex.blocks : { KEEP(*(.vhex.blocks)); } > userram /* Exposed driver interfaces (.vhex.drivers) The driver information is required to start and configure the driver, even if the symbols are not referenced */ .vhex.drivers : { _vhex_drivers_start = . ; KEEP(*(SORT_BY_NAME(.vhex.drivers.*))); _vhex_drivers_end = . ; } > userram /* Exposed module interfaces (.vhex.modules) */ .vhex.modules : { _vhex_modules_start = . ; KEEP(*(SORT_BY_NAME(.vhex.modules.*))); _vhex_modules_end = . ; } > userram /* Read-only sections */ .rodata : { /* Read-Only data */ *(.rodata); *(.rodata.*); } > userram /* The GOT section is a bit exotic. When I generate the PIE executable, all global variables are stored is the *(.got) section and the __GLOBAL_OFFSET_TABLE__ object is generated and inserted in the *(.got.plt) section. But, neither of *(.plt*) or *(rela*) section are generated to help me out for the "relocation" of each address stored in the GOT. The result is that the content of the GOT is always absolute addresses, which makes the machine crash. So, the idea to bypass this limitation (probably due to the custom GCC which not provide critical information for the relocation) is to isolate the GOT in a standalone section and, after the loading of the image, walk thought the relocalised table and manually patch each address. Moreover, the __GLOBAL_OFFSET_TABLE__ is used like a table, so, the section ".got.plt" SHOULD be before the .got section. */ .got.plt : { *(.got.plt) *(.igot.plt) *(.igot) } .got : { *(.got) } /* readable / writable data */ .data ALIGN(4) : { /* Data sections */ *(.data); *(.data.*); *(COMMON); } .bss ALIGN(4) : { /* bss section included to avoid missaligned segment */ *(.bss); *(.bss.*); /* dynamic BSS information (move me ?) */ *(.dynbss) /* Video RAM symbols The video RAM contains a full pixel sized frame for the screen. Its size is 396x224 and each pixel depth is 16its, so (3996 * 224) * 2 = 177408 */ _vhex_vram = ALIGN(4); /* create the VRAM gap */ . = _vhex_vram + 177408; } > userram /* Vhex VBR management geometry Due to the SH3/SH4 VBR system, we have some restrictions: The handlers should reside at VBR relative position, in P1 or P2 protected space (0x8* or 0xA*). For our case, the bootloader will relocalise the kernel at the P1 area using the Casio's UTLB information. So, we don't have to wories about this here. There are 3 vectors offset called by the processor : VBR + 0x100, 0x400 and 0x600. The first offset is involved when an exception occur, the second when a memory (TLB) error is detected and the last when an interruptions is detected. All exception and memory interuption will be handled "normaly" : a simple handler will be involved which will try to resolve/fix the problem, if nothing can be fixed, a panic screen will be displayed. However, regarding interuptions, we will use a power-full and complexe technique to compact as most as possible the VBR size. To explain the technique we need to know that each interruption start at offset VBR + 0x600 and each interrupt source is "gapped" by 0x20 ( for exemple the 0x400 is for TMU0, 0x420 is for TMU1 and 0x440 is for TMU2) Moreover, we have some "hole" in the "interrup map". So, the idea is to write all interrupt handler in "blocks" of 32 bytes, and, for those that 32 bytes is to short, can use hole of the interrupt map. */ .vhex.vbr : ALIGN(4) { _vhex_vbr = . - 0x100; *(.vhex.exch.pretext) ; *(.vhex.exch) . = _vhex_vbr + 0x400; *(.vhex.tlbh.pretext) ; *(.vhex.tlbh) ; . = _vhex_vbr + 0x600; *(.vhex.inth.pretext) ; *(.vhex.inth) ; /* interrupt block entry */ __vhex_interrupth_start = ALIGN(4); /* static ram start (for kmalloc) */ PROVIDE(___sram_start = ALIGN(4) + 4096); } > userram /* unwanted section */ /DISCARD/ : { *(.rela.debug*) *(.gnu.*) *(.debug_info) *(.debug_abbrev) *(.debug_loc) *(.debug_aranges) *(.debug_ranges) *(.debug_line) *(.debug_str) *(.debug_*) *(.jcr) *(.eh_frame_hdr) *(.eh_frame) *(.comment) *(.interp) } }