StratifyLabs / StratifyOS

A Powerful embedded RTOS for ARM Cortex M microcontrollers
https://stratifylabs.co
Other
116 stars 23 forks source link

Implement -fstack-check #173

Closed tyler-gilbert closed 3 years ago

tyler-gilbert commented 6 years ago

stack-check will generate instructions to ping memory on an interval. The default for GCC is every 4096 bytes. The macro STACK_CHECK_PROBE_INTERVAL_EXP needs to be changed to match the stack guard size of StratifyOS.

This means GCC would need to be re-built and re-distributed.

tyler-gilbert commented 5 years ago

Here is the basic program used to create the out assembly information

#include <sapi/sys.hpp>

int add_to_stack(){
    char buffer[8192];
    File f;
    buffer[8191] = 0; //does a write way down on the stack -- may jump over the stack guard
    f.open("/home/data.txt");
    f.write(buffer, 4096);
    return f.close();
}

int main(int argc, char * argv[]){
    add_to_stack();
    return 0;
}

Here are all of the compiler options. -fstack-check is the primary one to be interested in for this.

arm-none-eabi-g++  -DSOS_GIT_HASH=\"9667fec\" -D__StratifyOS__ -D__v7em_f5sh -I/Applications/StratifyLabs-SDK/Tools/gcc/arm-none-eabi/../lib/gcc/arm-none-eabi/6.3.1/include -I/Applications/StratifyLabs-SDK/Tools/gcc/arm-none-eabi/../lib/gcc/arm-none-eabi/6.3.1/include-fixed -I/Applications/StratifyLabs-SDK/Tools/gcc/arm-none-eabi/include -I/Applications/StratifyLabs-SDK/Tools/gcc/arm-none-eabi/include/c++/6.3.1 -I/Applications/StratifyLabs-SDK/Tools/gcc/arm-none-eabi/include/c++/6.3.1/arm-none-eabi  -Wall -mthumb -D__StratifyOS__ -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-unwind-tables -fno-use-cxa-atexit   -mlong-calls -march=armv7e-m -mfloat-abi=hard -mfpu=fpv4-sp-d16 -U__SOFTFP__ -D__FPU_PRESENT=1 -DARM_MATH_CM4=1 -Os -fstack-check -o CMakeFiles/HelloWorld_v7em_f5sh.elf.dir/src/main.cpp.obj -c /Users/tgil/git/StratifyApps/HelloWorld/src/main.cpp

Here is the disassembly without -fstack-check enabled (with my comments after //):

de00045c <_Z12add_to_stackv>:
de00045c:   b510        push    {r4, lr}
//compiler allocates space on the stack without trying to see write access is OK
de00045e:   f5ad 5d00   sub.w   sp, sp, #8192   ; 0x2000
de000462:   b08a        sub sp, #40 ; 0x28
de000464:   a805        add r0, sp, #20
de000466:   4b11        ldr r3, [pc, #68]   ; (de0004ac <_Z12add_to_stackv+0x50>)
de000468:   4798        blx r3 //call to first File()

And now the disassembly with -fstack-check enabled (with my comments after //)

de00048c <_Z12add_to_stackv>:
de00048c:   b590        push    {r4, r7, lr}
de00048e:   b08b        sub sp, #44 ; 0x2c
de000490:   f5ad 5389   sub.w   r3, sp, #4384   ; 0x1120
de000494:   af00        add r7, sp, #0
// Here the compiler makes a few writes to the stack below the region used by the function - with the MPU on this will cause a memory fault if it hits the stack guard
de000496:   f843 0c08   str.w   r0, [r3, #-8]
de00049a:   f5ad 5304   sub.w   r3, sp, #8448   ; 0x2100  //writes 4096 + 0x100 where 4096 is page size determined by STACK_CHECK_PROBE_INTERVAL_EXP when compiling GCC
de00049e:   f843 0c28   str.w   r0, [r3, #-40]
de0004a2:   f5ad 5344   sub.w   r3, sp, #12544  ; 0x3100 //writes another page down
de0004a6:   f843 0c28   str.w   r0, [r3, #-40]
// Now the compiler actually allocates data on the stack
de0004aa:   f5ad 5d00   sub.w   sp, sp, #8192   ; 0x2000
de0004ae:   f107 0014   add.w   r0, r7, #20
de0004b2:   4b12        ldr r3, [pc, #72]   ; (de0004fc <_Z12add_to_stackv+0x70>)
de0004b4:   4798        blx r3 //call to File()
de0004b6:   f641 73ff   movw    r3, #8191   ; 0x1fff
de0004ba:   2200        movs    r2, #0

Having a page size of 4096 (STACK_CHECK_PROBE_INTERVAL_EXP=12) is too big for most CortexM applications. If STACK_CHECK_PROBE_INTERVAL_EXP were set to 6 or 7, then the stack writes would happen every 64/128 bytes rather than every 4096. This would allow an MPU stack guard of 128/256 bytes between the stack and heap to throw a memory fault if the code tries to jump over the stack guard.

tyler-gilbert commented 3 years ago

Can't do this without modding GCC.