2

解决了。请参阅下面的解决方案部分。

我有一个问题,我的构建环境正在输出一个大的二进制文件,我希望有人可以帮助我再次移动。

我正在使用 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) );

谢谢您的帮助!

4

1 回答 1

1

看起来您有一些东西以链接描述文件无法捕获的方式插入到 RAM 部分中。您可以objdump在最终的 ELF 上使用或类似方法来检查符号表并检查是否有任何可疑之处,例如,使用此链接器脚本构建一些简单的代码会给出:

$ 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 条目。检查节标题揭示了原因:

$ 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虚拟地址 (VMA),但加载地址仍在闪存 (LMA) 中。另一方面,note 部分也有一个 RAM 加载地址,因此将 ELF 转换为原始二进制文件会导致它在图像中的其他部分之后放置 ~400MB。

从提供的额外细节来看,听起来库函数正在生成自己的 .rodata 部分,这些部分与脚本中的任何内容都不匹配,因此被链接器的启发式分配相当任意。我会尝试添加*(.rodata.*)到 .text 部分来捕捉那些。

于 2015-02-12T11:42:17.590 回答