使用 malloc 时创建的 STM32 大型二进制文件
STM32 Large binary created when using malloc
已解决。请参阅下面的解决方案部分。
我遇到一个问题,我的构建环境正在输出一个大的二进制文件,我希望有人能帮助我重新开始。
我正在使用 STM32F105 处理器、Eclipse、FreeRTOS 和 CodeSourcery 编译器尝试在此设备上获取一些 AHRS 评估代码 运行。我有很多代码 运行,但是在执行使用 malloc 分配内存的 eval 代码部分时,我 运行 遇到了问题。我必须为 _sbrk 添加一些代码才能编译,现在我的二进制文件从 35K 增加到将近 400MB。我认为这是一个链接器问题,因为 .out 文件(在 objcopy 之前)的大小大致相同。即使是 objdump 输出的 .s 文件看起来也相当可比。
这里有一些(希望)相关的点点滴滴:
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) );
生成文件:
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
添加此代码加上对 malloc 的调用导致二进制文件增长到近 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;
}
关于如何重新开始运动有什么想法吗?感谢您提供的任何帮助!
解决方案
根据 Notlikethat 的评论,我看到在构建过程中正在创建另一段代码,但链接器脚本没有同名的段。链接器决定将此部分放入 RAM,而本应将其放入 FLASH。由于它跨越 RAM 和 FLASH,bin 文件填满了它们之间的区域,导致二进制文件很大。将以下行添加到链接描述文件(在 FLASH 部分),允许代码以正常大小再次构建。
*(.rodata.str1.4)
新的完整链接描述文件如下所示:
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) );
感谢您的帮助!
看起来你有一些东西以链接描述文件无法捕获的方式将自身插入到 RAM 部分。你可以在最终的 ELF 上使用 objdump
或类似的东西来检查符号 table 并检查是否有任何可疑的东西,例如使用此链接描述文件构建一些简单的代码可以得到:
$ 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
在这种情况下,有一些带有 RAM 地址的符号,但在这种情况下导致最终二进制文件爆炸到 ~400MB 的是 .note.gnu.build-id 条目。检查 headers 部分揭示了原因:
$ 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
.data 和 .bss 部分有 RAM virtual addresses (VMA),但加载地址仍在闪存 (LMA) 中。另一方面,注释部分也有一个 RAM 加载地址,因此将 ELF 转换为原始二进制文件会导致它在图像中的其他部分之后放置 ~400MB。
从提供的额外细节来看,听起来库函数正在生成它们自己的 .rodata 部分,这些部分与脚本中的任何内容都不匹配,因此链接器的试探法相当随意地分配了这些部分。我会尝试将 *(.rodata.*)
添加到 .text 部分以捕获这些内容。
已解决。请参阅下面的解决方案部分。
我遇到一个问题,我的构建环境正在输出一个大的二进制文件,我希望有人能帮助我重新开始。
我正在使用 STM32F105 处理器、Eclipse、FreeRTOS 和 CodeSourcery 编译器尝试在此设备上获取一些 AHRS 评估代码 运行。我有很多代码 运行,但是在执行使用 malloc 分配内存的 eval 代码部分时,我 运行 遇到了问题。我必须为 _sbrk 添加一些代码才能编译,现在我的二进制文件从 35K 增加到将近 400MB。我认为这是一个链接器问题,因为 .out 文件(在 objcopy 之前)的大小大致相同。即使是 objdump 输出的 .s 文件看起来也相当可比。
这里有一些(希望)相关的点点滴滴:
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) );
生成文件:
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
添加此代码加上对 malloc 的调用导致二进制文件增长到近 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;
}
关于如何重新开始运动有什么想法吗?感谢您提供的任何帮助!
解决方案
根据 Notlikethat 的评论,我看到在构建过程中正在创建另一段代码,但链接器脚本没有同名的段。链接器决定将此部分放入 RAM,而本应将其放入 FLASH。由于它跨越 RAM 和 FLASH,bin 文件填满了它们之间的区域,导致二进制文件很大。将以下行添加到链接描述文件(在 FLASH 部分),允许代码以正常大小再次构建。
*(.rodata.str1.4)
新的完整链接描述文件如下所示:
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) );
感谢您的帮助!
看起来你有一些东西以链接描述文件无法捕获的方式将自身插入到 RAM 部分。你可以在最终的 ELF 上使用 objdump
或类似的东西来检查符号 table 并检查是否有任何可疑的东西,例如使用此链接描述文件构建一些简单的代码可以得到:
$ 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
在这种情况下,有一些带有 RAM 地址的符号,但在这种情况下导致最终二进制文件爆炸到 ~400MB 的是 .note.gnu.build-id 条目。检查 headers 部分揭示了原因:
$ 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
.data 和 .bss 部分有 RAM virtual addresses (VMA),但加载地址仍在闪存 (LMA) 中。另一方面,注释部分也有一个 RAM 加载地址,因此将 ELF 转换为原始二进制文件会导致它在图像中的其他部分之后放置 ~400MB。
从提供的额外细节来看,听起来库函数正在生成它们自己的 .rodata 部分,这些部分与脚本中的任何内容都不匹配,因此链接器的试探法相当随意地分配了这些部分。我会尝试将 *(.rodata.*)
添加到 .text 部分以捕获这些内容。