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")
Related
I found a start up code for arm cortex m cores on internet and using those sources but I have some doubts regarding a function from the sources and here I am pasting the code and the respective linker scripts being used here.
// very simple startup code with definition of handlers for all cortex-m cores
// location of these variables is defined in linker script
extern unsigned __data_load;
extern unsigned __data_start;
extern unsigned __data_end;
extern unsigned __bss_start;
extern unsigned __bss_end;
extern unsigned __heap_start;
extern unsigned __init_array_start;
extern unsigned __init_array_end;
extern unsigned __fini_array_start;
extern unsigned __fini_array_end;
// main application
extern void main_app();
void copy_data() {
unsigned *src = &__data_load;
unsigned *dst = &__data_start;
while (dst < &__data_end) {
*dst++ = *src++;
}
}
void zero_bss() {
unsigned *dst = &__bss_start;
while (dst < &__bss_end) {
*dst++ = 0;
}
}
void fill_heap(unsigned fill=0x55555555) {
unsigned *dst = &__heap_start;
register unsigned *msp_reg;
__asm__("mrs %0, msp\n" : "=r" (msp_reg) );
while (dst < msp_reg) {
*dst++ = fill;
}
}
void call_init_array() {
unsigned *tbl = &__init_array_start;
while (tbl < &__init_array_end) {
((void (*)())*tbl++)();
}
}
void call_fini_array() {
unsigned *tbl = &__fini_array_start;
while (tbl < &__fini_array_end) {
((void (*)())*tbl++)();
}
}
// reset handler
void RESET_handler() {
copy_data();
zero_bss();
fill_heap();
call_init_array();
// run application
main_app();
// call destructors for static instances
call_fini_array();
// stop
while (true);
}
Following is the linker description being used
SECTIONS {
. = ORIGIN(FLASH);
.text : {
KEEP(*(.stack))
KEEP(*(.vectors))
KEEP(*(.vectors*))
KEEP(*(.text))
. = ALIGN(4);
*(.text*)
. = ALIGN(4);
KEEP(*(.rodata))
*(.rodata*)
. = ALIGN(4);
} >FLASH
.init_array ALIGN(4): {
__init_array_start = .;
KEEP(*(.init_array))
__init_array_end = .;
} >FLASH
.fini_array ALIGN(4): {
__fini_array_start = .;
KEEP(*(.fini_array))
__fini_array_end = .;
} >FLASH
}
SECTIONS {
__stacktop = ORIGIN(SRAM) + LENGTH(SRAM);
__data_load = LOADADDR(.data);
. = ORIGIN(SRAM);
.data ALIGN(4) : {
__data_start = .;
*(.data)
*(.data*)
. = ALIGN(4);
__data_end = .;
} >SRAM AT >FLASH
.bss ALIGN(4) (NOLOAD) : {
__bss_start = .;
*(.bss)
*(.bss*)
. = ALIGN(4);
__bss_end = .;
*(.noinit)
*(.noinit*)
} >SRAM
. = ALIGN(4);
__heap_start = .;
}
My question is in the copy_data() function why do we need to assign the address of __data_load to a pointer *src? Is __data_load = LOADADDR(.data); is same as __data_start. What does the copy_data() function doing in the program? Thanks in advance.
The linker script instructs the linker to place the data in flash but link the code as if the data is in ram. In the startup code the data is then copied from the address the data is loaded at (the flash) to the address the data is supposed to be (RAM).
copy_data() copies memory reading from start address __data_load into the adress range starting from __data_start to __data_end
The total size copied is therefore __data_end - __data_start.
Of course you already have the data available at __data_load. The program copies it from FLASH to SRAM where it can be read and written as much as needed.
The problem
We have an issue in embedded code. Storage options are non-volatile but unmodifiable (flash/ROM, etc) or volatile modifiable storage. 'data' is initialized non-zero arbitrary values which can be modified (versus const or rodata). How can this be arranged?
A copy of the data is put in flash or ROM. This data is then copied to RAM where it is both read and written.
My question is in the copy_data() function why do we need to assign the address of __data_load to a pointer *src? Is __data_load = LOADADDR(.data); is same as __data_start. What does the copy_data() function doing in the program?
copy_data() is the solution to the above problem. It takes memory from the flash (load location) and copies it to RAM. A similar dichotomy can exist with virtual addressing. Where you need to arrange a physical address and virtual address contents to be the same before enabling an MMU. Linker documentation often calls the run/RAM location a 'VADDR'.
With an OS or some ROM bootloaders you may load from disk/MMC (NAND flash) to RAM and be able to circumvent copy_data(). It is only needed if your code will run directly from a non-volatile device. It can often be faster and simpler just to copy the entire image from flash to RAM. This depends on resources of course. Read access from RAM is often faster than flash. Again this will depend on your system.
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.
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?
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 ( * )
}
}