компоновщик gcc, как объявить область между HEAP и STACK, поместить туда переменную для обнаружения переполнения (проблема с жестким сбоем на Cortex M3)?

Я работаю над Silabs ARM Cortex M3 (EFM32PG12).

Я хочу объявить раздел компоновщика XXX между кучей и стеком, поместить туда переменную и посмотреть позже (тема аппаратного сбоя), если эта переменная загрязнится.

  .heap (COPY):
  {
    __HeapBase = .;
    __end__ = .;
    end = __end__;
    _end = __end__;
    KEEP(*(.heap*))
    __HeapLimit = .;
  } > RAM

  .xxx (NOLOAD): /* my DEBUG section */
  {
    . = ALIGN(4);
    __xxx_start__ = .;
    KEEP(*(.xxx*))
    __xxx_end__ = .;
  } > RAM

  /* .stack_dummy section doesn't contains any symbols. It is only
   * used for linker to calculate size of stack sections, and assign
   * values to stack symbols later */
  .stack_dummy (COPY):
  {
    KEEP(*(.stack*))
  } > RAM

  /* Set stack top to end of RAM, and stack limit move down by
   * size of stack_dummy section */
  __StackTop = ORIGIN(RAM) + LENGTH(RAM);
  __StackLimit = __StackTop - SIZEOF(.stack_dummy);
  PROVIDE(__stack = __StackTop);

  /* Check if data + heap + stack exceeds RAM limit */
  ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")

  /* Check if FLASH usage exceeds FLASH size */
  ASSERT( LENGTH(FLASH) >= (__etext + SIZEOF(.data)), "FLASH memory overflowed !")

теперь в моем коде я объявил такую ​​​​переменную

__attribute__((section(".xxx"))) volatile uint32_t dirtyvar = 0x12345678;

но файл карты показывает довольно странно, кажется, что регион XXX все еще находится перед HEAP

 *(COMMON)
 COMMON         0x20000c7c     0x6004 ./src/dbg_malloc.o
                0x20000c7c                dbgMallocData
 COMMON         0x20006c80        0x4 ./src/drv_uart.o
                0x20006c80                frames
 COMMON         0x20006c84        0x4 ./src/error.o
                0x20006c84                __stack_chk_guard
 COMMON         0x20006c88        0x4 c:/siliconlabs/simplicitystudio/v5/developer/toolchains/gnu_arm/7.2_2017q4/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/softfp\libc_nano.a(lib_a-reent.o)
                0x20006c88                errno
                0x20006c8c                . = ALIGN (0x4)
                0x20006c8c                __bss_end__ = .

.heap           0x20006c90     0x2000
                0x20006c90                __HeapBase = .
                0x20006c90                __end__ = .
                0x20006c90                end = __end__
                0x20006c90                _end = __end__
 *(.heap*)
 .heap          0x20006c90     0x2000 ./CMSIS/EFM32PG12B/startup_gcc_efm32pg12b.o
                0x20008c90                __HeapLimit = .

.xxx            0x20006c8c        0x4 load address 0x00009b88
                0x20006c8c                . = ALIGN (0x4)
                0x20006c8c                __xxx_start__ = .
 *(.xxx*)
 .xxx           0x20006c8c        0x4 ./src/error.o
                0x20006c8c                dirtyvar
                0x20006c90                __xxx_end__ = .

.stack_dummy    0x20006c90       0x80
 *(.stack*)
 .stack         0x20006c90       0x80 ./CMSIS/EFM32PG12B/startup_gcc_efm32pg12b.o
                0x20040000                __StackTop = (ORIGIN (RAM) + LENGTH (RAM))
                0x2003ff80                __StackLimit = (__StackTop - SIZEOF (.stack_dummy))
                0x20040000                PROVIDE (__stack, __StackTop)
                0x00000001                ASSERT ((__StackLimit >= __HeapLimit), region RAM overflowed with stack)
                0x00000001                ASSERT ((LENGTH (FLASH) >= (__etext + SIZEOF (.data))), FLASH memory overflowed !)
OUTPUT(5GNR_EFM32.axf elf32-littlearm)

Как правильно объявить этот регион, чтобы я мог видеть при сбое, если HEAP только что повредил мой STACK?

Я сделал все, что мог:

  • Я написал оболочку для malloc/free, она работает как положено.
  • Я компилировал с -fstack-protector-all, вроде тут все ок
  • Я пытался написать такой обработчик HARD FAULT, но содержимое CFSR совершенно не имеет значения.

void debugHardfault(uint32_t *sp)
{
    uint32_t cfsr  = SCB->CFSR;
    uint32_t hfsr  = SCB->HFSR;
    uint32_t mmfar = SCB->MMFAR;
    uint32_t bfar  = SCB->BFAR;

    uint32_t r0  = sp[0];
    uint32_t r1  = sp[1];
    uint32_t r2  = sp[2];
    uint32_t r3  = sp[3];
    uint32_t r12 = sp[4];
    uint32_t lr  = sp[5];
    uint32_t pc  = sp[6];
    uint32_t psr = sp[7];

    printf("HardFault:\n");
    printf("SCB->CFSR   0x%08lx\n", cfsr);

    /*
     * HFSR
     * 0x1b4b09b3
     *
     *
     * 00011011 01001011 00001001 10110011
     *
     */

    printf("SCB->HFSR   0x%08lx\n", hfsr);
    printf("SCB->MMFAR  0x%08lx\n", mmfar);
    printf("SCB->BFAR   0x%08lx\n", bfar);
    printf("\n");

    printf("SP          0x%08lx\n", (uint32_t)sp);
    printf("R0          0x%08lx\n", r0);
    printf("R1          0x%08lx\n", r1);
    printf("R2          0x%08lx\n", r2);
    printf("R3          0x%08lx\n", r3);
    printf("R12         0x%08lx\n", r12);
    printf("LR          0x%08lx\n", lr);
    printf("PC          0x%08lx\n", pc);
    printf("PSR         0x%08lx\n", psr);

    while(1);
}

Notice: This fault gets more often (still random) when I compile with -O3.

Еще одна проблема, которую я заметил, заключается в том, что malloc() никогда не возвращает NULL, как будто у меня неограниченная куча, поэтому я подозреваю переполнение стека.

Заранее спасибо,


person orfruit    schedule 21.06.2021    source источник
comment
stackoverflow.com/questions/43035285 / malloc() never returns NULL like I have unlimited HEAP Сверху — какую стандартную библиотеку вы используете? Какую реализацию malloc() вы используете? Он звонит sbrk()? Вы задаете вопрос XY - вы спрашиваете о каком-то регионе - не намерены ли вы конкретно спросить, как обнаружить переполнение / недополнение HEAP / стека на вашей платформе?   -  person KamilCuk    schedule 21.06.2021
comment
Что касается того, как это обнаружить — добавьте пул кучи static в ваш sbrk() для проверки на перераспределение, проверьте размер стека в sbrk() на предмет переполнения, см. mcuoneclipse.com/2019/09/28/, скомпилируйте с помощью -finstrument-functions и проверьте, не переполнен ли стек /близок к переполнению в __cyg_profile_func_* функциях.   -  person KamilCuk    schedule 21.06.2021