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 objdump
or 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:
$ arm-none-eabi-objdump -t a.out
a.out: file format elf32-littlearm
SYMBOL TABLE:
20000000 l d .note.gnu.build-id 00000000 .note.gnu.build-id
08000000 l d .text 00000000 .text
20000000 l d .data 00000000 .data
20000004 l d .bss 00000000 .bss
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 l df *ABS* 00000000 test.c
00000000 l df *ABS* 00000000 sum.c
00000000 l df *ABS* 00000000
20000000 g O .data 00000004 j
080000c0 g .text 00000000 _sidata
20000004 g .bss 00000000 _sbss
08000038 g F .text 0000003c sum
20000000 g .data 00000000 _sdata
080000bc g O .text 00000004 k
20000008 g .bss 00000000 _ebss
20000004 g O .bss 00000004 i
08000000 g F .text 00000038 main
08000074 g F .text 00000048 sum2
20005000 g *ABS* 00000000 _estack
20000004 g .data 00000000 _edata
20000008 g .bss 00000000 _end
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:
$ arm-none-eabi-objdump -h a.out
a.out: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .note.gnu.build-id 00000024 20000000 20000000 00030000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 00000074 08000000 08000000 00010000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .data 00000004 20000000 08000074 00020000 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00000004 20000004 08000078 00020004 2**2
ALLOC
4 .comment 00000036 00000000 00000000 00030024 2**0
CONTENTS, READONLY
5 .ARM.attributes 00000033 00000000 00000000 0003005a 2**0
CONTENTS, READONLY
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.