SOLVED. SEE THE SOLUTION SECTION BELOW.
I've got a problem where my build environment is outputting a large binary file, and I'm hoping that someone can help get me moving again.
I'm using an STM32F105 processor, Eclipse, FreeRTOS, and CodeSourcery compiler to try to get some AHRS evaluation code running on this device. I have much of the code running, but I ran into a problem when implementing the section of the eval code which uses malloc to allocate memory. I had to add some code for _sbrk to get it to compile, and now my binary went from 35K to almost 400MB. I think that this is a linker problem, as the .out file (before objcopy) is about the same size. Even the .s files output from the objdump look pretty comparable.
Here are some (hopefully) relevant bits and pieces:
MEMORY
{
RAM (RWX) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 128K
}
_estack = ORIGIN(RAM)+LENGTH(RAM);
SECTIONS
{
.text ORIGIN(FLASH):
{
*(.isr_vector)
*(.text)
*(.text.*)
*(.rodata)
_sidata = .;
}
.data ORIGIN(RAM):
AT (_sidata)
{
_sdata = . ;
*(.data)
_edata = . ;
}
.bss (_edata) (NOLOAD):
{
_sbss = .;
*(.bss)
*(.bss.*)
*(COMMON)
_ebss = . ;
. = ALIGN(4);
_end = .;
}
}
/* end of allocated ram _end */
PROVIDE( _HEAP_START = _end );
/* end of the heap -> align 4 byte */
PROVIDE ( _HEAP_END = ALIGN(ORIGIN(RAM) + LENGTH(RAM) - 4 ,4) );
The makefile:
BOOT = boot
RTOS = FreeRTOSSource
FREERTOS = $(RTOS)/port.c $(RTOS)/tasks.c $(RTOS)/croutine.c $(RTOS)/heap_2.c $(RTOS)/list.c $(RTOS)/queue.c
APP_SOURCE = app_source/sysmon.c app_source/hscan.c app_source/gps.c app_source/mems.c app_source/gpio.c app_source/mainstates.c app_source/leds.c app_source/database.c
INEMO_LIB = inemo/mems/LSM303DLH.c inemo/mems/L3GD20.c
OBJS = main.o \
$(BOOT)/core_cm3.o \
$(BOOT)/system_stm32f10x.o \
$(BOOT)/stm32f10x_rcc.o \
$(BOOT)/stm32f10x_gpio.o \
$(BOOT)/stm32f10x_can.o \
$(BOOT)/stm32f10x_iwdg.o \
$(BOOT)/stm32f10x_i2c.o \
$(BOOT)/startup.o \
$(BOOT)/mx_gpio.o \
$(FREERTOS:%.c=%.o) \
$(INEMO_LIB:%.c=%.o) \
$(APP_SOURCE:%.c=%.o)
CFLAGS = -O0 -gdwarf-2 -mcpu=cortex-m3 -mthumb -fno-common -I$(BOOT) -std=gnu99 -c -mfloat-abi=soft -Wall -g
LFLAGS = -mthumb -mcpu=cortex-m3 -Tscripts/stm32f103.ld -nostartfiles -lgcc -lm -lc -mfloat-abi=soft -Wall -g -O0
CPFLAGS = -O binary
TARGET = arm-none-eabi
#TARGET = arm-elf
CC = $(TARGET)-gcc
LD = $(TARGET)-gcc
CP = $(TARGET)-objcopy
OD = $(TARGET)-objdump
all: version $(OBJS) link
$(BOOT)/startup.o:
$(CC) $(CFLAGS) $(BOOT)/startup_stm32f10x_cl.s -lm -lc -lnosys -o $@
%.o: %.c
$(CC) $(CFLAGS) $< -o $@
version:
$(CC) --version
link: $(OBJS)
$(LD) -o main.out $(OBJS) $(LFLAGS)
$(CP) $(CPFLAGS) main.out main.bin
$(OD) -D -h main.out > main.S
clean:
rm -rf $(OBJS) main.bin main.out main.S
The addition of this code plus a call to malloc causes the binary to grow to almost 400MB:
#include <sys/types.h>
extern unsigned int _HEAP_START;
caddr_t * _sbrk(int incr) {
static unsigned char *heap = NULL;
unsigned char *prev_heap;
if (heap == NULL) {
heap = (unsigned char *)_HEAP_START;
}
prev_heap = heap;
heap += incr;
return (caddr_t) prev_heap;
}
Any thoughts on how to get moving again? Thanks for any help you can provide!
THE SOLUTION
With the comments of Notlikethat, I saw that another section of code was getting created in the build process, but the linker script didn't have a section with the same name. The linker decided to put this section in RAM, when it should have put it in FLASH. Since it spanned RAM and FLASH, the bin file filled the area between them, causing the large binary. Adding the following line to the linker script (in the FLASH section), allowed the code to build again at a normal size.
*(.rodata.str1.4)
The new complete linker script looks like this:
MEMORY
{
RAM (RWX) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (RX) : ORIGIN = 0x08000000, LENGTH = 128K
}
_estack = ORIGIN(RAM)+LENGTH(RAM);
SECTIONS
{
.text ORIGIN(FLASH):
{
*(.isr_vector)
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.str1.4)
_sidata = .;
}
.data ORIGIN(RAM):
AT (_sidata)
{
_sdata = . ;
*(.data)
_edata = . ;
}
.bss (_edata) (NOLOAD):
{
_sbss = .;
*(.bss)
*(.bss.*)
*(COMMON)
_ebss = . ;
. = ALIGN(4);
_end = .;
}
}
/* end of allocated ram _end */
PROVIDE( _HEAP_START = _end );
/* end of the heap -> align 4 byte */
PROVIDE ( _HEAP_END = ALIGN(ORIGIN(RAM) + LENGTH(RAM) - 4 ,4) );
Thanks for the help!
It looks like you have something inserting itself into a RAM section in a way the linker script doesn't catch. You can use
objdumpor similar on the final ELF to inspect the symbol table and check for anything suspicious, e.g. building some trivial code with this linker script gives:In this case, there are a few symbols with RAM addresses, but what causes this final binary to blow up to ~400MB in this case is the .note.gnu.build-id entry. Checking the section headers reveals why:
The .data and .bss sections have RAM virtual addresses (VMA), but load addresses still in flash (LMA). The note section on the other hand has a RAM load address as well, so converting the ELF to a raw binary causes it to placed ~400MB after the other sections in the image.
From the extra details provided, it sounds like library functions are generating their own .rodata sections which don't match anything in the script, thus get allocated fairly arbitrarily by the linker's heuristics. I'd try adding
*(.rodata.*)to the .text section to catch those.