GCC Linker, bss section symbols equal zero length - c

As a point of trying to understand the basics, I wrote [or extracted I guess] the following c code and linker script. The resulting binary works and the led blinks without issue. However, while debuging, I found that the bss_start and bss_end symbols both hold a value of 0x20000000. The bss zero fuction is basically skipped. When doing an objdump, I can see
20000000 g O .bss 00000004 timer_delayCount
So the section is 4 bytes long and located at 0x20000000 correclty. And at least bss_start is pointed to the correct memory address. However, bss_end should be pointed at 0x20000004 [I think], not 0x20000000.
I would like to now whey the bss_end symbol is not incremeting after the *(.bss), which I think contains four bytes, is placed.
The micro controller is stm32f103rb, a cortex-m3 chip. I am compling with ARM GNU GCC
My main.c file:
#define _stackInit 0x20005000U
volatile unsigned int * const RCC_APB2ENR = (unsigned int *)0x40021018;
volatile unsigned int * const GPIOA_CRL = (unsigned int *)0x40010800;
volatile unsigned int * const GPIOA_BSR = (unsigned int *)0x40010810;
volatile unsigned int * const GPIOA_BRR = (unsigned int *)0x40010814;
volatile unsigned int * const STK_CTRL = (unsigned int *)0xE000E010;
volatile unsigned int * const STK_LOAD = (unsigned int *)0xE000E014;
volatile unsigned int * const STK_VAL = (unsigned int *)0xE000E018;
volatile unsigned int timer_delayCount;
int main() {
// enable GIOA clock and set PB5 to output
*RCC_APB2ENR |= (unsigned int)0x00000004;
*GPIOA_CRL = (unsigned int)0x44244444;
// COnfigure Systick Timer for 1 millisecond interrupts
*STK_VAL = 0x00;
*STK_LOAD = 7999U; //tick every 1 ms
*STK_CTRL = 0x07;
while (1){
int c, d;
timer_delayCount = 500u;
while(timer_delayCount != 0u);
*GPIOA_BSR = 0x20;
timer_delayCount = 500u;
while(timer_delayCount != 0u);
*GPIOA_BRR = 0x20;
}
}
// Begin and End addresses for the .bss section. Symbols defined in linker script
extern unsigned int __bss_start__;
extern unsigned int __bss_end__;
void __attribute__ ((section(".after_vectors"))) Reset_Handler (void)
{
// Initialize bss section by iterating and clearing word by word.
// It is assumed that the pointers are word aligned.
unsigned int *p = &__bss_start__;
while (p < &__bss_end__) {
*p++ = 0;
}
main();
}
void SysTick_Handler() {
// Decrement to coutner to zero.
if (timer_delayCount != 0u)
{
--timer_delayCount;
}
}
void __attribute__ ((section(".after_vectors"))) Default_Handler(void)
{
while(1);
}
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) NMI_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) HardFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) MemManage_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) BusFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) UsageFault_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) SVC_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) DebugMon_Handler(void);
void __attribute__ ((section(".after_vectors"),weak, alias ("Default_Handler"))) PendSV_Handler(void);
typedef void(* const pHandler)(void);
// The vector table.
// The linker script to place at correct location in memory.
__attribute__ ((section(".isr_vector"),used)) pHandler __isr_vectors[] =
{
//core exceptions
(pHandler)_stackInit, // Inital Stack Pointer
Reset_Handler, // reset handler
NMI_Handler, // NMI handler
HardFault_Handler, // hard fault handler
MemManage_Handler, // MPU fault handler
BusFault_Handler, // bus fault handler
UsageFault_Handler, // usage fault handler
0x00, // reserved
0x00, // reserved
0x00, // reserved
0x00, // reserved
SVC_Handler, // SVCall handler
DebugMon_Handler, // debug monitor handler
0x00, // reserved
PendSV_Handler, // PendSV handler
SysTick_Handler, // systick handler
};
My linker file:
ENTRY(Reset_Handler)
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K
}
SECTIONS
{
.text : {
*(.isr_vector)
*(.after_vectors)
*(.text)
} > FLASH
.bss : {
__bss_start__ = .; /* symbol for c code to initialize bss section */
*(.bss)
__bss_end__ = .; /* symbol for c code to initialize bss section */
} > RAM
}
Compiler commands:
/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb -g blinky-interrupt.c -o blinky-interrupt.o
/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/arm-none-eabi-ld -T blinky-interrupt.ld blinky-interrupt.o -o blinky-interrupt.elf

That's because an unitialized variable goes into COMMON instead of .bss. Had you initialized it with 0, then it'd go into .bss.
Look at the linker map file (if you don't have it, let the linker generate it with -Map), you should see something like this
.bss 0x0000000020000000 0x4 load address 0x00000000080000e0
0x0000000020000000 . = ALIGN (0x4)
0x0000000020000000 __bss_start__ = .
*(.bss)
0x0000000020000000 . = ALIGN (0x4)
0x0000000020000000 __bss_end__ = .
COMMON 0x0000000020000000 0x4 ./src/app/main.o
0x0000000020000000 timer_delayCount
When COMMON is not specified in the linker script, the linker puts it somewhere else, probably dumps it at the end.
A more complete linker script has the following .bss section
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} >RAM
Then the COMMON section would go between __bss_start__ and __bss_end__.
FYI, *(.bss*) is there to cover the -fdata-sections option, when each variable gets its own segment, so that the linker can drop unreferenced ones.

Related

Refering in code to section placed in RAM, cause linker error [Lc036]

STM8, IAR compiler.
Im trying to place changable interrupt vector table(IVT) in RAM(ram_ivt_section or RAM_IVT), stating from 0x00 address.
Prereq: Hardware entry point(base_ivt_section or IVT_TO_RAM block) already replaced and redirects to this RAM addresses.
So, i have next code:
Header.h ===========================================
#define MCU_INTERRUPT_VECTORS_COUNT (32)
typedef void (__interrupt *interrupt_handler_t)(void);
typedef struct {
int8_t value;
int8_t unused_byte;
interrupt_handler_t handler;
}interrupt_vector_t;
extern interrupt_vector_t ram_ivt[MCU_INTERRUPT_VECTORS_COUNT];
Source.c ===========================================
#include "header.h"
extern void __iar_program_start(void);
extern void __iar_unhandled_exception(void);
__interrupt void CallUnhandledException(void) { __iar_unhandled_exception(); }
__interrupt void CallResetHandler(void) { __iar_program_start(); }
interrupt_vector_t ram_ivt[MCU_INTERRUPT_VECTORS_COUNT] #".ram_ivt_sector" = {
{0x82, 0x00, CallResetHandler},
{0x82, 0x00, CallUnhandledException},
{0x82, 0x00, CallUnhandledException},
... repeats 32 times.
Main.c ===========================================
#include "header.h"
int main( void ) {
__enable_interrupt();
__trap();
}
It works fine. On trap, programm falls to unhandled exception.
But, when im trying to modify or read table
Main.c ===========================================
#include "header.h"
int main( void ) {
volatile void* a = &ram_ivt[1].handler;
// Or
ram_ivt[1].handler = 0;
__enable_interrupt();
__trap();
}
Project stops build on linker stage with error:
Error[Lc036]: no block or place matches the pattern "rw data section .ram_ivt_sector in ram_ivt.o symbols: [ram_ivt]"
Linker file:
/////////////////////////////////////////////////////////////////
define symbol __RAM_IVT__ = 0x000000;
// Memory regions
define memory with size = 16M;
define region TinyData = [from 0x00 to 0xFF];
define region NearData = [from 0x0000 to 0x0FFF];
define region NearFuncCode = [from 0x8000 to 0x9000];
define block CSTACK with size = _CSTACK_SIZE {};
define block HEAP with size = _HEAP_SIZE {};
define block IVT_TO_RAM with size = 0x80, alignment = 1 { ro section .base_ivt_section };
define block RAM_IVT with size = 0x80, alignment = 1 { rw section .ram_ivt_section };
define block INTVEC with size = 0x80, alignment = 1 { ro section .intvec };
// Initialization
initialize by copy { rw section .iar.dynexit,
rw section .near.bss,
rw section .near.data,
rw section .near_func.textrw,
rw section .tiny.bss,
rw section .tiny.data,
ro section .tiny.rodata };
initialize by copy with packing = none { section __DLIB_PERTHREAD };
do not initialize { rw section .near.noinit,
rw section .tiny.noinit,
rw section .vregs };
// Keep
keep { rw section .ram_ivt_section };
// Placement
place at address mem: __RAM_IVT__ { block RAM_IVT };
place in TinyData { rw section .vregs,
rw section .tiny.bss,
rw section .tiny.data,
rw section .tiny.noinit,
rw section .tiny.rodata };
place in NearData { block HEAP,
rw section __DLIB_PERTHREAD,
rw section .iar.dynexit,
rw section .near.bss,
rw section .near.data,
rw section .near.noinit,
rw section .near_func.textrw };
place at end of NearData { block CSTACK };
place at start of NearFuncCode { block IVT_TO_RAM };
place in NearFuncCode { block INTVEC,
ro section __DLIB_PERTHREAD_init,
ro section .iar.init_table,
ro section .init_array,
ro section .near.data_init,
ro section .near.rodata,
ro section .near_func.text,
ro section .near_func.textrw_init,
ro section .tiny.data_init,
ro section .tiny.rodata_init };
That was a syntax error in
interrupt_vector_t ram_ivt[MCU_INTERRUPT_VECTORS_COUNT] #".ram_ivt_sector"
ram_ivt_sector must be ram_ivt_section
Thanks #KoynovStas.

Baremetal Nucleo-F446RE Turn LED on

I am trying to turn on the Internal LED on my Nucleo-F446RE, but it the LED is always off.
The plan is to set clock for GPIOA on, then set GPIOA_5 to output and then set it to high. Here are the files (C file, Linkerscript, Bashscript for compilation and Flashing).
Blink.c:
// Create references to symbols defined in the linker script
extern unsigned int _data_start;
extern unsigned int _data_end;
extern unsigned int _data_load;
extern unsigned int _bss_start;
extern unsigned int _bss_end;
void startup(); // Function prototype (forward declaration) for startup function
int main(); // Function prototype for main function
// Below we create an array of pointers which would form our vector table
// We use __attribute__ ((section(".vectors"))) to tell the compiler that we want the
// array to be placed in a memory section that we call ".vectors"
unsigned int * vectors[2] __attribute__ ((section(".vectors"))) =
{
(unsigned int *) 0x20020000, // Address of top of stack. 20kB = 1024 x 20 = 20480 bytes = 0x5000
(unsigned int *) startup // Address of the reset handler which is also our startup function
};
// The startup function, address was provided in the vector table
void startup()
{
volatile unsigned int *src, *dest;
// Copy data section values from load time memory address (LMA) to their address in SRAM
for (src = &_data_load, dest = &_data_start; dest < &_data_end; src++, dest++)
*dest = *src;
// Initialize all uninitialized variables (bss section) to 0
for (dest = &_bss_start; dest < &_bss_end; dest++)
*dest = 0;
// Calling the main function
main();
while(1); // Normally main() should never return, but just incase we loop infinitely
}
// LED2 on PA5
#define GPIOA 0x40020000
#define RCC 0x40023800
#define GPIOA_MODER *((volatile char*) GPIOA + 0x0)
#define GPIOA_BSRR *((volatile char*) GPIOA + 0x18)
#define RCC_AHB1ENR *((volatile char*) RCC + 0x30)
int main(){
RCC_AHB1ENR |= (1 << 0);
for(int i = 0; i < 10; i++){ // wait for a few cycles
asm("nop");
}
GPIOA_MODER |= (1 << 10); // set PA5 to output
GPIOA_MODER &= ~(1 << 11);
GPIOA_BSRR = (1 << 5); // set pin high
while(1){}
}
linker.ld:
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.text : /* Define output file TEXT section */
{
*(.vectors) /* Vector table */
*(.text) /* Program code */
. = ALIGN(4); /* Make sure data that follows are aligned to 4 byte boundary */
*(.rodata) /* Read only, section set asside for constants */
} >rom
.data : /* Define output file DATA section */
{
_data_start = .; /* Get the memory address (VMA) for start of section .data */
*(.data) /* Initialized static and global variable values */
. = ALIGN(4);
_data_end = .; /* Get the memory address (VMA) for end of section .data */
} >ram AT >rom /* After AT we specify the load-time location */
_data_load = LOADADDR(.data); /* Get the load memory address (LMA) for section .data */
.bss : /* Define output file BSS section */
{
_bss_start = .; /* Get memory address of start of bss section */
*(.bss) /* Uninitialized static and global variables */
*(COMMON) /* Uninitialized variables are placed in COMMON section for object files */
. = ALIGN(4);
_bss_end = .; /* Get memory address of end of bss section */
} >ram
}
compile_flash.sh:
arm-none-eabi-gcc -O0 -Wall -c -g -mcpu=cortex-m4 -mthumb blink.c -o blink.o
arm-none-eabi-ld -o blink.elf -T linker.ld blink.o
arm-none-eabi-objcopy blink.elf blink.bin -O binary
arm-none-eabi-nm --numeric-sort blink.elf
st-flash --reset write blink.bin 0x08000000
Sorry for the long code, but I think there should be nothing hidden when you want to help me :)
The problem is that the code is setting the 10th and 11th bit but the datatype is char*.
Changing the Datatype to void* works.

GDB missing line numbers

I'm debugging an embedded system with the stm32f746vg microcontroller where some speed critical sections of code are loaded in data RAM instead of flash. The rest of the non-critical code is loaded in flash, and the linker puts all of the .text sections in flash by default.
I do this relocation with nasty little function prototypes like this:
int main(void) __attribute__((section(".data")));
This forces main() to be loaded at address 0x2000 0000, which is what I want. Unfortunately, GDB expects main() to be loaded at address 0x0080 0000, where the rest of the program code is. As a result, GDB does not know where the line numbers for main() are. Is there any way to tell GDB "main() is actually at this address" ?
I DO have the newest version of arm-none-eabi-gdb and arm-none-eabi-gcc.
I am running arm-none-eabi-gcc with the -g option.
When I comment out the prototype for main that contains the __attribute__ directive, GDB has no problem finding line numbers.
Below is my linker script:
/* Entry Point */
ENTRY(Reset_Handler)
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
/**
* for the time being, we are going to buffer the image in sram1. sram1 is
* entirely dedicated to buffering images.
* DTCM_RAM will be used for user variables
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
DTCM_SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
/* RAM1 (xrw) : ORIGIN = 0x20010000, LENGTH = 240K*/
RAM1 (xrw) : ORIGIN = 0x20010000, LENGTH = 245760
RAM2 (xrw) : ORIGIN = 0x2004c000, LENGTH = 16K
ITCM_SRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 16K
}
/* Define output sections */
SECTIONS
{
/* Vectors need to be loaded at the start of flash. */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.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)
/*KEEP (*(.init))*/
/*KEEP (*(.fini))*/
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
_exit = .;
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
/* used by the startup to initialize data */
_sidata = .;
/* Initialized data sections goes into RAM, load LMA copy after code */
.data ORIGIN(DTCM_SRAM) :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} AT > FLASH
__const_data_length__ = SIZEOF(.data);
/* Uninitialized data section */
. = ALIGN(4);
.bss . :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >DTCM_SRAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >DTCM_SRAM
/* ram1 section, vars must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".ram1"))); */
/* No initialization is offered for this section.*/
.ram1 ORIGIN(RAM1) :
{
*(.ram1)
} >RAM1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
}
These are my gcc flags
CFLAGS = -gstabs -Wall -std=gnu99 -ffunction-sections -Wno-unused-variable
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mlong-calls
CFLAGS += -I. -ggdb
CFLAGS += -DHSE_VALUE=$(HSE_VALUE)
CFLAGS += -DUSE_STDPERIPH_DRIVER
You acheive this by placing main() in special code section of your choosing, call it .fast_exec
int main(void) __attribute__((section(".fast_exec")));
Then, in the linker script, place this new section to execute from RAM. It will be copied from FLASH at start-up:
.fast_exec : {
*(.fast_exec)
} > DTCM_SRAM AT> FLASH
You can verify the effect of this, by checking the map file.
Refer to: https://stackoverflow.com/a/15142268/1096140

ARM bare metal binary linking

I have an ARM board with ROM at 0x80000000 and RAM at 0x20000000. Board starts execution of raw binary code at 0x80000000.
I managed to get a simple ARM assembler program running on it, but I have to use C instead of ASM. I know I will need to use some kind of linker script, and then manually copy .data section to RAM and clear .bss, setup stack etc. but I haven't found a reliable solution how to do this yet, especially the linker script (it's very messy in my opinion).
Also, I can't get the linker to output a raw binary instead of ELF, but it's not a big deal as I can use objcopy later.
Thanks in advance.
This example is for STM32F051 MCU:
Very simple application as "blinky" (without delays):
// define used registers
#define RCC_AHB1 *(volatile unsigned int *)(0x40021014)
#define GPIOC_MODER *(volatile unsigned int *)(0x48000800)
#define GPIOC_BSRR *(volatile unsigned int *)(0x48000818)
// main program
void mainApp() {
RCC_AHB1 = 1 << 19; // enable clock for GPIOC
GPIOC_MODER = 1 << (9 * 2); // set output on GPIOC.P9
while (1) {
GPIOC_BSRR = 1 << 9; // set output on GPIOC.P9
GPIOC_BSRR = 1 << (9 + 16); // clear output on GPIOC.P9
}
}
// variables for testing memory initialisation
int x = 10;
int y = 0;
int z;
Here is also very simple startup file written in C (also will work in C++), which start application mainApp and initialise static variables .data initialised from ROM and .bss only set to zero, there are variables initialised to zero and uninitialised variables.
extern void mainApp();
// external variables defined in linker script
// address in FLASH where are stored initial data for .data section
extern unsigned int _data_load;
// defines start and end of .data section in RAM
extern unsigned int _data_start;
extern unsigned int _data_end;
// defines start and end of .bss section in RAM
extern unsigned int _bss_start;
extern unsigned int _bss_end;
void resetHandler() {
unsigned int *src, *dst;
// copy .data area
src = &_data_load;
dst = &_data_start;
while (dst < &_data_end) {
*dst++ = *src++;
}
// clear .bss area
dst = &_bss_start;
while (dst < &_bss_end) {
*dst++ = 0;
}
mainApp();
while(1);
}
// _stacktop is defined in linker script
extern unsigned int _stacktop;
// vector table, will be placed on begin of FLASH memory, is defined in linker script
// only reset vector defined, need add other used vectors (especially NMI)
__attribute__((section(".vectors"), used)) void *isr_vectors[] = {
&_stacktop, // first vector is not vector but initial stack position
(void *)resetHandler, // vector which is called after MCU start
};
And finaly linker script which define location and sizes of memories, sections for vector, program (text), data (.data and .bss) a stacktop
MEMORY {
FLASH(rx) : ORIGIN = 0x08000000, LENGTH = 64K
SRAM(rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}
SECTIONS {
. = ORIGIN(FLASH);
.text : {
*(.vectors)
*(.text)
} >FLASH
. = ORIGIN(SRAM);
.data ALIGN(4) : {
_data_start = .;
*(.data)
. = ALIGN(4);
_data_end = .;
} >SRAM AT >FLASH
.bss ALIGN(4) (NOLOAD) : {
_bss_start = .;
*(.bss)
. = ALIGN(4);
_bss_end = .;
} >SRAM
_stacktop = ORIGIN(SRAM) + LENGTH(SRAM);
_data_load = LOADADDR(.data);
}
Build this with these command (build and link at once):
$ arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -nostartfiles main.c startup.c -T stm32f051x8.ld -o main.elf
In symbol table is possible to see where are stored data:
$ arm-none-eabi-nm -C -l -n -S main.elf
08000000 00000008 T isr_vectors
08000008 00000034 T mainApp
0800003c 0000005c T resetHandler
08000098 A _data_load
20000000 D _data_start
20000000 00000004 D x
20000004 D _data_end
20000004 B _bss_start
20000004 00000004 B y
20000008 B _bss_end
20000008 00000004 B z
20002000 A _stacktop
Also you can look into listing:
arm-none-eabi-objdump -S main.elf
Raw binary:
arm-none-eabi-objcopy -O binary main.elf main.bin
MEMORY
{
bob : ORIGIN = 0x8000, LENGTH = 0x1000
ted : ORIGIN = 0xA000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
__data_rom_start__ = .;
.data : {
__data_start__ = .;
*(.data*)
} > ted AT > bob
__data_end__ = .;
__data_size__ = __data_end__ - __data_start__;
.bss : {
__bss_start__ = .;
*(.bss*)
} > ted
__bss_end__ = .;
__bss_size__ = __bss_end__ - __bss_start__;
}
of course change the addresses as you see fit. clearly the names of the sections mean nothing, you might try rom and ram if it helps you.
If you were to do something like this
MEMORY
{
rom : ORIGIN = 0x80000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
.rodata : { *(.rodata*) } > rom
.data : { *(.data*) } > ram
}
and then objcopy it then you are going to end up with a huge file, even if you only have one instruction of .text and one byte of data. because a binary format has to cover everything as in the memory so it will make a file that is 0x80000000+sizeof(text)-0x20000000. If you had one instruction only in ram and one byte of data then the file would be 0x60000004 bytes or 1.6 gig. leave it as an elf and use objdump -D until you have your linker script worked out THEN make a .bin if you really need one. or make an intel hex or s record and again you can examine it to see if it is all in the same address space before trying a binary.
the first key to your problem is the AT
MEMORY
{
bob : ORIGIN = 0x8000, LENGTH = 0x1000
ted : ORIGIN = 0xA000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > bob
.data : { *(.data*) } > ted AT > bob
.bss : { *(.bss*) } > bob
}
it says I want the .data in the address space ted, but place it in the binary in the bob space. it compiles for the ted address space, but the bits are loaded from bob space. exactly what you want. except you dont know how much .data to copy from rom to ram. you have to be super careful where you place the variables in the more complicated one or it wont work right.

TI LM4F120, GNU ARM GCC eabi and malloc: crash when calling malloc

I am working with the Stellaris Launchpad, GCC arm embedded and I am trying to use malloc. According to this it should not be a problem at all, but it is a problem at compile time: you need an implementation of _sbrk to make it run. So based on this thread I created the following _sbrk implementation:
#include "stdio.h"
extern int _HEAP_START;
extern int _HEAP_END;
extern void *_sbrk(int incr)
{
static unsigned char *heap = NULL;
unsigned char *prev_heap;
if (heap == NULL) {
heap = (unsigned char *)&_HEAP_START;
}
prev_heap = heap;
if ((heap + incr) >= (unsigned char *)&_HEAP_END) {
return 0;
}
heap += incr;
return (void *)prev_heap;
}
I also have the following linkerscript to define a stack, a heap and all the rest (also based on the same thread)
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
SECTIONS
{
.text :
{
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH
.data : AT (ADDR(.text) + SIZEOF(.text))
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM
.bss :
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
. = ALIGN (8);
_end = .;
} > SRAM
}
/* end of allocated ram _end */
PROVIDE( _HEAP_START = _end );
/* end of the heap -> align 8 byte */
PROVIDE ( _HEAP_END = ALIGN(ORIGIN(SRAM) + LENGTH(SRAM) - 8 ,8) );
the last pieces of information: Compiler params:
-g -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_LM4F120H5QR -c -Iinc/ -Ilib/inc -I/usr/arm-none-eabi/include -DTARGET_IS_BLIZZARD_RA1
And the Linker params:
-Tlib/linker_script.ld --entry ResetISR --gc-sections -L lib/ -L /usr/arm-none-eabi/lib -o final.elf obj/main.c.o obj/_sbrk.c.o obj/startup_gcc.c.o obj/switch.S.o -ldriver-cm4f -lc -lm
The main file consists of one malloc call:
#include "stdio.h"
#include "stdlib.h"
int main(){
int *i = malloc(sizeof(int));
}
And it crashes on the malloc call. Breakpoints in the _sbrk do not get hit, so the program crashes before it even reaches _sbrk. What is going on? Why does malloc not, as promised, work on its own? And why does it crash before it reaches its core algorithm (_sbrk)?
Ah, I found the mistake: I used the wrong libraries. For this version of the stellaris launchpad and GCC arm embedded 4.8 you need to use the Thumb libraries, which (on my pc) has the following directories:
/usr/arm-none-eabi/lib/thumb (for libM and libC (and libC++ etc))
/usr/lib/gcc/arm-none-eabi/4.8.3/thumb/ (for libgcc)

Resources