2012-05-06 21 views
14

Estoy creando código para un ARM Cortex-M3 (LCP17xx de NXP). He estado usando memoria estática hasta ahora y todo funcionó bien. Intenté agregar compatibilidad con la memoria dinámica, pero una vez que llamé a malloc, el sistema se atascó.Uso de malloc de newlib en un ARM Cortex-M3

Estoy compilando con gcc para el brazo desnudo y usando newlib. Versión: gcc-arm-none-eabi-4_6-2012q1

Para agregar soporte malloc, implementé una función simple _sbrk y modifiqué mi script enlazador para hacer espacio para el montón (he leído muchos tutoriales diferentes sobre esto parte, pero ninguno cubre el problema que encontré después).

Con la ayuda de algunos leds, puedo estar seguro de que el código se ejecuta hasta el punto en que llama a malloc, luego no se enciende. Ni siquiera alcanza mi función _sbrk. Además, se bloqueará en una llamada al sizeof, si incluyo una llamada al malloc más adelante en el código.

Entonces, ¿qué puedo estar haciendo mal al llamar malloc el código se bloquea sin llegar a _sbrk o al volver?

Después de mirar durante un rato el mapa de memoria generado cuando se incluye la llamada malloc y cuando no lo está, sospecho que está relacionado con las estructuras que usa malloc.

Esta es la parte de la secuencia de comandos ld que define la memoria RAM:

.bss : 
{ 
    _start_bss = .; 
    *(.bss) 
    *(COMMON) 
    _ebss = .; 
    . = ALIGN (8); 
    _end = .; 
} >sram 
. = ALIGN(4); 
_end_bss = .; 
. = ALIGN(256); 
_start_heap = .; 
PROVIDE(__cs3_heap_start = _start_heap) 

_end_stack = 0x10008000; 

_end_stack se establece a continuación, en la tabla de vectores de interrupción.

Y ahora una comparación de los diferentes mapas. Sin utilizar malloc en el código:

*(COMMON) 
      0x1000000c    _ebss = . 
      0x10000010    . = ALIGN (0x8) 
*fill*  0x1000000c  0x4 00 
      0x10000010    _end = . 
      0x10000010    . = ALIGN (0x4) 
      0x10000010    _end_bss = . 
      0x10000100    . = ALIGN (0x100) 
      0x10000100    _start_heap = . 

mapa de memoria usando malloc en el código:

*(COMMON) 
COMMON  0x10000848  0x4 ...arm-none-eabi/lib/armv7-m/libc.a(lib_a-reent.o) 
      0x10000848    errno 
      0x1000084c    _ebss = . 
      0x10000850    . = ALIGN (0x8) 
*fill*  0x1000084c  0x4 00 
      0x10000850    _end = . 

.bss.__malloc_max_total_mem 
      0x10000850  0x4 
.bss.__malloc_max_total_mem 
      0x10000850  0x4 ...arm-none-eabi/lib/armv7-m/libc.a(lib_a-mallocr.o) 
      0x10000850    __malloc_max_total_mem 

(...) It goes on (...) 
      0x1000085c    __malloc_current_mallinfo 
      0x10000884    . = ALIGN (0x4) 
      0x10000884    _end_bss = . 
      0x10000900    . = ALIGN (0x100) 
      0x10000900    _start_heap = . 
+0

¿Estás seguro de que estás invocando el código de inicio correctamente, lo que inicializará las estructuras de montón? –

+0

Obviamente estoy haciendo algo mal, el problema es que no sé LO QUE estoy haciendo mal. Agregué información adicional sobre los mapas de memoria, espero que ayude a encontrar el error. –

+0

Un problema muy similar ocurre cuando se usa sprintf. Entonces no es solo un problema Malloc. Tiene que ver con todo el material newlib. Probablemente necesite un cambio en el script de enlace, aunque no puedo entender qué. –

Respuesta

16

Así que, después de algunos 10 horas pasaron la depuración de esto, por fin he hecho el trabajo. El problema estaba en el script del enlazador. Sin embargo, no estaba en la sección de bss que había publicado, sino en la sección de texto y datos. Aquí está el script que funciona.

OUTPUT_FORMAT("elf32-littlearm") 
OUTPUT_ARCH(arm) 
ENTRY(_startup) 

MEMORY 
{ 
    rom (rx) : ORIGIN = 0x00000000, LENGTH = 512K 
    ram (rwx) : ORIGIN = 0x10000000, LENGTH = 32K 
} 

/* Define the top our stack at the end of SRAM */ 
_end_stack = 0x10008000; 

EXTERN(__interrupt_vector_table); 

SECTIONS 
{ 
    .text : 
    { 
     /* Insert the interrupt vector table first */ 
     __interrupt_vector_table = .; 
     *(.interrupt_vector_table) 
     /* Startup assembly */ 
     *(.startup) 
     /* Rest of the code (C) */ 
     *(.text) *(.text.*) *(.glue_7) *(.glue_7t) 
     *(.vfp11_veneer) 
     *(.ARM.extab* .gnu.linkonce.armextab.*) 
     *(.rodata) *(.rodata.*) 
     . = ALIGN(8); 
     _end_text = .; 
     _start_datai = .; 
    } >rom 

    .data : 
    { 
     _start_data = .; 
     *(vtable) 
     *(.data) *(.data.*) 
     . = ALIGN (8); 
     _end_data = .; 
    } >ram AT >rom 

    .data_init : { _end_datai = .; } >rom 

    __exidx_start = .; 
    .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > rom 
    __exidx_end = .; 

    .bss : 
    { 
     _start_bss = .; 
     *(.bss) 
     *(COMMON) 
    } >ram 

    . = ALIGN(4); 
    _end_bss = .; 
    . = ALIGN(256); 

    _start_heap = .; 
    PROVIDE(__cs3_heap_start = _start_heap); 

    /* Linker wants .eh_frame section defined because of gcc 4.4.X bug, 
    * just discard it here. */ 
    /DISCARD/ : { *(.eh_*) } 
} 

_end = .; 
PROVIDE(end = .); 

También tuve que añadir un poco de inicialización de variables a mi código de inicio:

extern unsigned int _start_data; 
extern unsigned int _end_data; 
extern unsigned int _start_datai; 
extern unsigned int _end_datai; 

void init(void) { 

    // (...) Other stuff 

    // Initialize Global Variables 
    uint32_t* data_begin = (uint32_t*) &_start_data; 
    uint32_t* data_end = (uint32_t*) &_end_data; 
    uint32_t* datai_begin = (uint32_t*) &_start_datai; 
    uint32_t* datai_end = (uint32_t*) &_end_datai; 
    while(data_begin < data_end) 
    { 
     *data_begin = *datai_begin; 
     data_begin++; 
     datai_begin++; 
    } 

Estas dos páginas eran bastante útil, aunque todavía me llevó mucho a entender lo que estaba pasando: http://fun-tech.se/stm32/linker/index.php y http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/t/44452.aspx?pi23648=1

Espero que esto pueda serle útil a otra persona que tenga los mismos problemas que yo.

+6

También necesita poner a cero la sección .bss: 'for (uint32_t * p = & _start_bss; p <&_ebss; ++ p) * p = 0;' –

+0

@Marga, gracias por resolver todo esto. ¡Lo estaré usando! – nic

-15

Si está dentro de su presupuesto, considere comprar una licencia para un compilador ARM. Keil e IAR son excelentes compiladores de ARM que se encargarán de la gran mayoría de los problemas de la cadena de herramientas y ambos tienen un soporte decente.

+15

No le diga a alguien que use dinero para dejar de aprender. Los resultados que encontró son excelentes para instruir qué trabajo de campo han hecho Keil y IAR. Al final, ella será una programadora más poderosa ya que ahora entiende lo que hay debajo del capó. – nic