Now, I make a new OS which is written in C++.
I want to place the main function at the first location in the image, but I could not.
If I do not use class, the main is first .
If I use class, the class is located at the first location of the image.
Disassembly of section .text:
00010200 <_ZN4test4initEv>:
_ZN4test4initEv():
/home/xaliver/WorkSpace/kOdin/kernel32/./test.hpp:11
public:
void init(void);
};
void test::init(void)
{
10200: 55 push %ebp
10201: 89 e5 mov %esp,%ebp
/home/xaliver/WorkSpace/kOdin/kernel32/./test.hpp:12
m = 10;
10203: 8b 45 08 mov 0x8(%ebp),%eax
10206: c7 00 0a 00 00 00 movl $0xa,(%eax)
/home/xaliver/WorkSpace/kOdin/kernel32/./test.hpp:14
return;
1020c: 90 nop
/home/xaliver/WorkSpace/kOdin/kernel32/./test.hpp:15
}
1020d: 5d pop %ebp
1020e: c3 ret
0001020f <main>:
main():
/home/xaliver/WorkSpace/kOdin/kernel32/./main.cpp:10
bool kPrintString(int iX, int iY, const char* pcString);
bool kInitializeKernel64Area(void);
bool kIsMemoryEnough(void);
void main(void)
{
1020f: 55 push %ebp
10210: 89 e5 mov %esp,%ebp
10212: 83 e4 f0 and $0xfffffff0,%esp
I use this linker script. 0x10200 is the first location
/* Default linker script, for normal executables */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/home/xaliver/BuildTools/cross/x86_64-pc-linux/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;
/* DS Start */
/* Part moved to the front by section relocation */
.text 0x10200 :
{
main.o(.text)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em */
*(.gnu.warning)
} =0x90909090
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
/* Align start of data at the sector size */
. = ALIGN (512); /* Next .data will be located at aligned address by 512 byte */
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
. = .;
__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 don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
/* DS End */
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
.rel.fini : { *(.rel.fini) }
.rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
.rel.data.rel.ro : { *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) }
.rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
.rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
.rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
.rel.ctors : { *(.rel.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rel.got : { *(.rel.got) }
.rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
.rel.ifunc : { *(.rel.ifunc) }
.rel.plt :
{
*(.rel.plt)
PROVIDE_HIDDEN (__rel_iplt_start = .);
*(.rel.iplt)
PROVIDE_HIDDEN (__rel_iplt_end = .);
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array ))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array ))
PROVIDE_HIDDEN (__fini_array_end = .);
}
//_edata = .; PROVIDE (edata = .);
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.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))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.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.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
//. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* 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) }
/* 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 Extension. */
.debug_macro 0 : { *(.debug_macro) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
How can I set the main at the first location?
Related
I'm working on the Upsilon Project (https://github.com/UpsilonNumworks/Upsilon) and I have some trouble to implement sram data retention after reset (using nrst pin).
I want to preserve the data on the staticStorageArea, so I did this:
extern "C" {
extern char _bss_records_section_start;
}
static volatile uint32_t * staticStorageArea[sizeof(Storage)/sizeof(uint32_t)] __attribute__((section(".noinit"))) ;
And there is my linker script:
MEMORY {
INTERNAL_FLASH (rx) : ORIGIN = 0x00200000, LENGTH = 64K
SRAM (rw) : ORIGIN = 0x20000000, LENGTH = 256K - 0xfa20
NOINIT (rwx) : ORIGIN = 0x20000000 + 256K - 0xfa20, LENGTH = 0xfa20
EXTERNAL_FLASH (rx) : ORIGIN = 0x90000000, LENGTH = 8M
}
STACK_SIZE = 32K;
FIRST_EXTERNAL_FLASH_SECTOR_SIZE = 4K;
SECTIONS {
.isr_vector_table ORIGIN(INTERNAL_FLASH) : {
KEEP(*(.isr_vector_table))
} >INTERNAL_FLASH
.header : {
KEEP(*(.header))
} >INTERNAL_FLASH
.text.internal_to_external : {
...
} >INTERNAL_FLASH
...
} >INTERNAL_FLASH
.rodata.internal : {
...
} >INTERNAL_FLASH
.exam_mode_buffer ORIGIN(EXTERNAL_FLASH) : {
...
} >EXTERNAL_FLASH
/* External flash memory */
.text.external : {
. = ALIGN(4);
*(.text)
*(.text.*)
} >EXTERNAL_FLASH
.rodata.external : {
*(.rodata)
*(.rodata.*)
} >EXTERNAL_FLASH
.init_array : {
...
} >INTERNAL_FLASH
.data : {
...
} >SRAM AT> INTERNAL_FLASH
.bss : {
...
} >SRAM
.heap : {
...
} >SRAM
.stack : {
...
} >SRAM
.noinit (NOLOAD) : ALIGN(4) {
_bss_records_section_start = .;
KEEP(*(.noinit))
KEEP(*(.noinit*))
_bss_records_section_end = .;
} >NOINIT
/DISCARD/ : {
...
}
}
NOCROSSREFS_TO(.text.external .text.internal);
NOCROSSREFS_TO(.rodata.external .text.internal);
NOCROSSREFS_TO(.text.external .rodata.internal);
NOCROSSREFS_TO(.rodata.external .rodata.internal);
NOCROSSREFS_TO(.text.external .isr_vector_table);
NOCROSSREFS_TO(.rodata.external .isr_vector_table);
NOCROSSREFS_TO(.text.external .header);
NOCROSSREFS_TO(.rodata.external .header);
NOCROSSREFS_TO(.exam_mode_buffer .text.internal);
NOCROSSREFS_TO(.exam_mode_buffer .rodata.internal);
NOCROSSREFS_TO(.exam_mode_buffer .isr_vector_table);
NOCROSSREFS_TO(.exam_mode_buffer .header);
I noticed that after every reset the data in the .noinit section is like corrupted, and I do not understand why... maybe I didn't understand correctly what nrst does in fact ? (on the website it's wrote that the power is "virtually disconnected")
I have written a startup and liker script for my C++ application, running on STM32F407VG.
The problem is i have an array of structure, where the structure field str is always zero despite the initialization. The other field in the struct are correctly initialized. I can-t understand what I'm doing wrong, I guess some part of initialization in the startup script is missing.
The array is declared like the following:
struct elem{
uint32_t str;
uint32_t value;
uint32_t value2;
};
const struct elem array[]{
{(uint32_t)(*(uint32_t*)"CM1"), 1, 1},
{(uint32_t)(*(uint32_t*)"CM2"), 2, 2},
{(uint32_t)(*(uint32_t*)"CM3"), 3, 3}
};
relevant section of startup script:
inline void static_init()
{
for (void (**p)() = __preinit_array_start; p < __preinit_array_end; ++p)
(*p)();
for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
(*p)();
}
void reset_handler(void)
{
unsigned long *source;
unsigned long *destination;
// Copying data from Flash to RAM
source = &_data_flash;
for (destination = &_data_begin; destination < &_data_end;)
{
*(destination++) = *(source++);
}
// default zero to undefined variables
for (destination = &_bss_begin; destination < &_bss_end;)
{
*(destination++) = 0;
}
static_init();
#ifndef __NO_SYSTEM_INIT
SystemInit();
#endif
// starting main program
main();
}
and the linker script:
/* Entry Point */
ENTRY(reset_handler)
_estack = 0x20010000; /* end of 128K RAM */
/* Specify the memory areas */
/*
0x08000000 until 0x08010000 is reserved for BOOTLOADER! (64k)
*/
MEMORY
{
EEPROM (rwx) : ORIGIN = 0x08010000, LENGTH = 64K /*fake EEPROM!*/
FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 896K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM2 (rw) : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
__intvec_start__ = .;
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
_text = .;
*(.text) /* .text sections (code) */
_text2 = .;
*(.text*) /* .text* sections (code) */
_rodata = .;
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
_init_data = .;
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} > FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* used by the startup to initialize data */
_data_flash = _sidata;
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_data_begin = .;
*(.data)
*(.data*)
. = ALIGN(4);
_data_end = .;
} >RAM AT> FLASH
.bss (NOLOAD) :
{
. = ALIGN(4);
_bss_begin = .;
__bss_start__ = _bss_begin;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_bss_end = .;
__bss_end__ = _bss_end;
} > RAM
stack_size = 1024;
__stack_end__ = ORIGIN(RAM)+LENGTH(RAM);
__stack_start__ = __stack_end__ - stack_size;
heap_size = 0;
__heap_end__ = __stack_start__;
__heap_start__ = __heap_end__ - heap_size;
. = __stack_start__;
._stack :
{
PROVIDE ( end = . );
. = . + stack_size;
. = . + heap_size;
. = ALIGN(4);
} > RAM
_siccmram = LOADADDR(.ram2);
.ram2 (NOLOAD) :
{
. = ALIGN(4);
*(.ram2);
*(.ram2*);
. = ALIGN(4);
} > RAM2 AT> FLASH
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
This should work and have no UB.
However, it's endian dependent.
#include <iostream>
#include <cstdint>
#include <cstring>
using namespace std;
struct elem {
uint32_t str;
uint32_t value;
uint32_t value2;
};
uint32_t makeint(const char str[4])
{
uint32_t val;
memcpy( &val, str, 4 );
return val;
}
const elem arr[] = {
{makeint("CM1"), 1, 1},
{makeint("CM2"), 2, 2},
{makeint("CM3"), 3, 3}
};
int main()
{
for (auto& e : arr)
cout << e.str << endl;
cout << "\ndone\n";
}
See it here
You might use multicharacter literal: see (6.) of character_literal.
Notice single quotes:
const struct elem array[]{
{'CM1', 1, 1},
{'CM2', 2, 2},
{'CM3', 3, 3}
};
You can see how gcc evaluate multicharacter literal:
https://gcc.gnu.org/onlinedocs/cpp/Implementation-defined-behavior.html#Implementation-defined-behavior
The compiler evaluates a multi-character character constant a character at a time, shifting the previous value left by the number of bits per target character, and then or-ing in the bit-pattern of the new character truncated to the width of a target character. The final bit-pattern is given type int, and is therefore signed, regardless of whether single characters are signed or not. If there are more characters in the constant than would fit in the target int the compiler issues a warning, and the excess leading characters are ignored.
I have a linker script like this:
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0xFFFF800000000000 ;
.startup_text : { processor.o(.text) }
.text : { *(EXCLUDE_FILE (processor.o) .text) }
.data : { *(.data) }
.rodata : { *(.rodata) }
linker_first_free_page = ALIGN(4096);
}
A piece of code loads the executable generated by this script, printing these infos:
size of executable (pages) 3
first free page 0xffff800000003000
And the executable itself prints:
&(linker_first_free_page) 0xffff800000003000
So everything works good so far. Now my executable needs a .bss section. Note that I don't have a loader capable of loading elf files, so I need a flat binary that can be just read and used, with all sections inside.
First attempt
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0xFFFF800000000000 ;
.startup_text : { processor.o(.text) }
.text : { *(EXCLUDE_FILE (processor.o) .text) }
.data : { *(.data) }
.rodata : { *(.rodata) }
.bss : { *(.bss) }
linker_first_free_page = ALIGN(4096);
}
That is, simply adding a .bss section. This is the output:
size of executable (pages) 3
first free page 0xffff800000003000
&(linker_first_free_page) 0xffff800000004000
That is, the linker variable is correctly updated, but the section is not allocated (I guess this is pretty normal for a .bss section).
Second attempt
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0xFFFF800000000000 ;
.startup_text : { processor.o(.text) }
.text : { *(EXCLUDE_FILE (processor.o) .text) }
.data : { *(.data) *(.bss) }
.rodata : { *(.rodata) }
linker_first_free_page = ALIGN(4096);
}
That is, putting .bss section inside the .data one. This is the output:
size of executable (pages) 4
first free page 0xffff800000004000
&(linker_first_free_page) 0xffff800000003000
That is, the .bss is allocated, but the linker variable is not updated (and I can't understand why...)
Short question
So, given all above, how can I embed the .bss section in a flat binary, so that it can be loaded in memory like a "standard" file and used directly, without a specific loader?
I'm trying to debug a program on LH75401 device with ARM7TDMI core using GDB. When I invoke "load" command, GDB loads only ".text" output section. How do I make it so that it loads not only the ".text" section but some other sections too? I tried to use PHDRS command in the linker script to make some sections loadable but it did not help. Here is my linker script:
USR_STACK_SIZE = 0x100;
IRQ_STACK_SIZE = 0x100;
MEMORY
{
EXTROM(wx) : ORIGIN = 0x44000000, LENGTH = 0x100000
EXTRAM(wx) : ORIGIN = 0x48000000, LENGTH = 0x100000
INTRAM(wx) : ORIGIN = 0x60000000, LENGTH = 0x4000
TCMRAM(wx) : ORIGIN = 0x80000000, LENGTH = 0x4000
}
PHDRS
{
EXTROM PT_LOAD;
EXTRAM PT_LOAD;
INTRAM PT_LOAD;
TCMRAM PT_LOAD;
}
ENTRY(rst_handler)
SECTIONS
{
.vect :
{
*(.vect)
}
> TCMRAM AT
> TCMRAM
: TCMRAM
.text :
{
*(.text)
*(.rodata)
}
> EXTROM AT
> EXTROM
: EXTROM
.data :
{
*(.data)
}
> EXTRAM AT
> EXTRAM
: EXTRAM
.bss :
{
*(.bss)
}
> EXTRAM AT
> EXTRAM
: EXTRAM
.usr_stack :
{
. += USR_STACK_SIZE;
. = ALIGN(8);
}
> EXTRAM AT
> EXTRAM
: EXTRAM
.irq_stack :
{
. += IRQ_STACK_SIZE;
. = ALIGN(8);
}
> EXTRAM AT
> EXTRAM
: EXTRAM
}
Fortunately I solved this problem. It was necessary to add a special section attribute in the source file. The attribute is "a", meaning that the section is allocatable. That's all.
Does anyone have a linker script specifically for the Stellaris LM3S8962 board or could explain how to create one? I am using the codesourcery g++ lite toolchain and can successfully create the elf file for the hosted environment using this linker script:
Hosted Linker Script
This does not work with the unhosted libraries. All the examples on I have found only work for C and not C++ and there seems to be some magic involved regarding the cs3 startup code. Any help appreciated.
Thanks,
Mike
These are the extra sections in a C++ linker script (from STM32):
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
The somewhere in your startup, you need to call:
bl __libc_init_array
If you use http://www.google.com/codesearch, you should be able to find something device specific.
Here is what I've ended up with:
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
GROUP(crti.o crtn.o crtbegin.o crtend.o)
ENTRY(Reset_Handler) /* entry Point */
MEMORY { /* memory map of LM3S811 */
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
}
/* The size of the stack used by the application. NOTE: you need to adjust */
STACK_SIZE = 24K;
/* The size of the heap used by the application. NOTE: you need to adjust */
HEAP_SIZE = 0K;
SECTIONS {
. = 0x0;
.isr_vector : { /* the vector table goes FIRST into ROM */
KEEP(*(.isr_vector)) /* vector table */
. = ALIGN(4);
} >ROM
.text : { /* code and constants */
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
} >ROM
__exidx_start = .;
.ARM.exidx : {
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >ROM
__exidx_end = .;
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >ROM
.init_array : {
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >ROM
.fini_array : {
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >ROM
_etext = .; /* global symbols at end of code */
.vtable : { /* the vector table goes FIRST into RAM */
KEEP(*(.vtable)) /* vector table */
. = ALIGN(4);
} >RAM
.data : AT (_etext) {
__data_load = LOADADDR (.data);
__data_start = .;
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(7);
__data_end__ = .;
_edata = __data_end__;
} >RAM
.bss : {
__bss_start__ = . ;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = .;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE ( __end__ = _ebss );
.heap : {
__heap_start__ = . ;
. = . + HEAP_SIZE;
. = ALIGN(8);
__heap_end__ = . ;
} >RAM
.stack : {
__stack_start__ = . ;
. = . + STACK_SIZE;
. = ALIGN(8);
__c_stack_top__ = . ;
__stack_end__ = . ;
} >RAM
/* Remove information from the standard libraries */
/DISCARD/ : {
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
}