1

I am working on a Silabs ARm Cortex M3 (EFM32PG12)

I want to declare a linker section XXX between heap and stack, put a variable there and see later on (hardware fault topic) if this variable gets dirty.

  .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 !")

now in my code, I declared variable like this

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

but the map file shows quite strange, seems that XXX region is still before 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)

How to declare this region correctly so I can see at crash if HEAP just corrupted my STACK?

I did everything I could:

  • I wrote a wrapper for malloc/free, this is working as expected
  • I compiled with -fstack-protector-all, seems that everything is ok here
  • I tried to wrote a HARD FAULT handler like this, but the content of CFSR is quite irrelevant

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.

Another issue I remarked is that malloc() never returns NULL like I have unlimited HEAP so that's why I suspect stack overflow.

Thank you in advance,

artless noise
  • 21,212
  • 6
  • 68
  • 105
yo3hcv
  • 1,531
  • 2
  • 17
  • 27
  • https://stackoverflow.com/questions/43035285/heap-overflow-detection-prevention-in-embedded-systems `malloc() never returns NULL like I have unlimited HEAP` From the top - what standard library are you using? What implementation of `malloc()` are you using? Does it call `sbrk()`? Are you asking XY question - you ask about some region - don't you intent to ask specifically how to detect HEAP/stack overflow/underflow on your platform? – KamilCuk Jun 21 '21 at 09:53
  • As to how to detect that - add a `static` heap pool to your `sbrk()` to check for overallocation, check stack size in `sbrk()` for overflow, see https://mcuoneclipse.com/2019/09/28/stack-canaries-with-gcc-checking-for-stack-overflow-at-runtime/, and compile with `-finstrument-functions` and check if stack overflowed/is close to overflow in `__cyg_profile_func_*` functions. – KamilCuk Jun 21 '21 at 09:57

0 Answers0