Closed tyler-gilbert closed 3 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.
Can't do this without modding GCC.
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.