diff --git a/Makefile b/Makefile index 3b65d7ffc..ca4ebf857 100644 --- a/Makefile +++ b/Makefile @@ -113,6 +113,10 @@ endif @echo "CC $@" @$(CC) $(SFLAGS) $(CFLAGS) -c $< -o $@ +%.o: %.s + @echo "AS $@" + @$(CC) $(SFLAGS) -c $< -o $@ + %.o: %.cpp @echo "CXX $@" @$(CXX) $(SFLAGS) $(CXXFLAGS) -c $< -o $@ diff --git a/liba/Makefile b/liba/Makefile index 32d9116d9..dcb9bcc9b 100644 --- a/liba/Makefile +++ b/liba/Makefile @@ -3,6 +3,8 @@ SFLAGS += -Iliba/include liba/src/external/sqlite/mem5.o: CFLAGS += -w objs += $(addprefix liba/src/, \ + armv7m/setjmp.o \ + armv7m/longjmp.o \ assert.o \ bzero.o \ ctype.o \ diff --git a/liba/include/setjmp.h b/liba/include/setjmp.h index 70ec67b93..f2b992448 100644 --- a/liba/include/setjmp.h +++ b/liba/include/setjmp.h @@ -1,4 +1,17 @@ #ifndef LIBA_SETJMP_H #define LIBA_SETJMP_H +/* We are preseving registers: + * - sp & lr -> 2x4 bytes + * - General purpose registers: r4-r9, r10 = sl, r11 = fp -> 8x4 bytes + * - Floating point registers: s16-s31 -> 8x8 bytes + * - VFP status register: fpscr ->1x4 bytes + * The buffer size has to include room for setjmp implementation: 4x4 bytes. + * (See C Library ABI for the ARM architecture documentation) + * The minimum buffer size is then (2+8+16+1+4)xsizeof(int64_t). */ + +typedef int jmp_buf[31]; +void longjmp(jmp_buf env, int val); +int setjmp(jmp_buf env); + #endif diff --git a/liba/src/armv7m/longjmp.s b/liba/src/armv7m/longjmp.s new file mode 100644 index 000000000..d1d387e14 --- /dev/null +++ b/liba/src/armv7m/longjmp.s @@ -0,0 +1,24 @@ +.syntax unified + +.section .text +.align 2 +.thumb +.global longjmp +longjmp: + /* Restore all the regsiters to get back in the original state (whenever the + matching setjmp was called. */ + // General purpose registers + ldmia r0!, { r4-r11, ip, lr } + // Floating point registers + vldmia r0!, { s16-s31 } + // Special case for VFP status register + ldr r0, [r0, #4] + vmsr fpscr, r0 + mov sp, ip + /* Put the return value in the integer result register, but return 1 if it is + in fact zero. */ + movs r0, r1 + it eq + moveq r0, #1 + bx lr +.type longjmp, function diff --git a/liba/src/armv7m/setjmp.s b/liba/src/armv7m/setjmp.s new file mode 100644 index 000000000..501f16af1 --- /dev/null +++ b/liba/src/armv7m/setjmp.s @@ -0,0 +1,20 @@ +.syntax unified + +.section .text +.align 2 +.thumb +.global setjmp +setjmp: + /* Save all the registers into the jump buffer */ + mov ip, sp + // storing r4-r9, r10=sl, r11=fp, ip=sp, lr + stmia r0!, { r4-r11, ip, lr} + // storing floating point registers + vstmia r0!, {s16-s31} + // Special storing: fpscr + vmrs r1, fpscr + str r1, [r0, #4] + /* And then return 0 */ + mov a1, #0 + bx lr +.type setjmp, function