Stripped down TinyCC fork for StupidOS
On i386 and gcc-4.7 I found that __bound_local_new was miscompiled - look: #ifdef __i386__ /* return the frame pointer of the caller */ #define GET_CALLER_FP(fp)\ {\ unsigned long *fp1;\ __asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\ fp = fp1[0];\ } #endif /* called when entering a function to add all the local regions */ void FASTCALL __bound_local_new(void *p1) { unsigned long addr, size, fp, *p = p1; GET_CALLER_FP(fp); for(;;) { addr = p[0]; if (addr == 0) break; addr += fp; size = p[1]; p += 2; __bound_new_region((void *)addr, size); } } __bound_local_new: .LFB40: .cfi_startproc pushl %esi .cfi_def_cfa_offset 8 .cfi_offset 6, -8 pushl %ebx .cfi_def_cfa_offset 12 .cfi_offset 3, -12 subl $8, %esp // NOTE prologue does not touch %ebp .cfi_def_cfa_offset 20 #APP # 235 "lib/bcheck.c" 1 movl %ebp,%edx // %ebp -> fp1 # 0 "" 2 #NO_APP movl (%edx), %esi // fp1[0] -> fp movl (%eax), %edx movl %eax, %ebx testl %edx, %edx je .L167 .p2align 2,,3 .L173: movl 4(%ebx), %eax addl $8, %ebx movl %eax, 4(%esp) addl %esi, %edx movl %edx, (%esp) call __bound_new_region movl (%ebx), %edx testl %edx, %edx jne .L173 .L167: addl $8, %esp .cfi_def_cfa_offset 12 popl %ebx .cfi_restore 3 .cfi_def_cfa_offset 8 popl %esi .cfi_restore 6 .cfi_def_cfa_offset 4 ret here GET_CALLER_FP() assumed that its using function setups it's stack frame, i.e. first save, then set %ebp to stack frame start, and then it has to do perform two lookups: 1) to get current stack frame through %ebp, and 2) get caller stack frame through (%ebp). And here is the problem: gcc decided not to setup %ebp for __bound_local_new and in such case GET_CALLER_FP actually becomes GET_CALLER_CALLER_FP and oops, wrong regions are registered in bcheck tables... The solution is to stop using hand written assembly and rely on gcc's __builtin_frame_address(1) to get callers frame stack(*). I think for the builtin gcc should generate correct code, independent of whether it decides or not to omit frame pointer in using function - it knows it. (*) judging by gcc history, __builtin_frame_address was there almost from the beginning - at least it is present in 1992 as seen from the following commit: http://gcc.gnu.org/git/?p=gcc.git;a=commit;h=be07f7bdbac76d87d3006c89855491504d5d6202 so we can rely on it being supported by all versions of gcc. In my environment the assembly of __bound_local_new changes as follows: diff --git a/bcheck0.s b/bcheck1.s index 4c02a5f..ef68918 100644 --- a/bcheck0.s +++ b/bcheck1.s @@ -1409,20 +1409,17 @@ __bound_init: __bound_local_new: .LFB40: .cfi_startproc - pushl %esi + pushl %ebp // NOTE prologue saves %ebp ... .cfi_def_cfa_offset 8 - .cfi_offset 6, -8 + .cfi_offset 5, -8 + movl %esp, %ebp // ... and reset it to local stack frame + .cfi_def_cfa_register 5 + pushl %esi pushl %ebx - .cfi_def_cfa_offset 12 - .cfi_offset 3, -12 subl $8, %esp - .cfi_def_cfa_offset 20 -#APP -# 235 "lib/bcheck.c" 1 - movl %ebp,%edx -# 0 "" 2 -#NO_APP - movl (%edx), %esi + .cfi_offset 6, -12 + .cfi_offset 3, -16 + movl 0(%ebp), %esi // stkframe -> stkframe.parent -> fp movl (%eax), %edx movl %eax, %ebx testl %edx, %edx @@ -1440,13 +1437,13 @@ __bound_local_new: jne .L173 .L167: addl $8, %esp - .cfi_def_cfa_offset 12 popl %ebx .cfi_restore 3 - .cfi_def_cfa_offset 8 popl %esi .cfi_restore 6 - .cfi_def_cfa_offset 4 + popl %ebp + .cfi_restore 5 + .cfi_def_cfa 4, 4 ret .cfi_endproc i.e. now it compiles correctly. Though I do not have x86_64 to test, my guess is that __builtin_frame_address(1) should work there too. If not - please revert only x86_64 part of the patch. Thanks. Cc: Michael Matz <matz@suse.de> |
||
---|---|---|
examples | ||
include | ||
lib | ||
tests | ||
tests2 | ||
win32 | ||
.gitignore | ||
arm-gen.c | ||
c67-gen.c | ||
Changelog | ||
coff.h | ||
configure | ||
COPYING | ||
elf.h | ||
i386-asm.c | ||
i386-asm.h | ||
i386-gen.c | ||
i386-tok.h | ||
il-gen.c | ||
il-opcodes.h | ||
libtcc.c | ||
libtcc.h | ||
Makefile | ||
README | ||
stab.def | ||
stab.h | ||
tcc-doc.texi | ||
tcc.c | ||
tcc.h | ||
tccasm.c | ||
tcccoff.c | ||
tccelf.c | ||
tccgen.c | ||
tccpe.c | ||
tccpp.c | ||
tccrun.c | ||
tcctok.h | ||
texi2pod.pl | ||
TODO | ||
VERSION | ||
x86_64-asm.h | ||
x86_64-gen.c |
Tiny C Compiler - C Scripting Everywhere - The Smallest ANSI C compiler ----------------------------------------------------------------------- Features: -------- - SMALL! You can compile and execute C code everywhere, for example on rescue disks. - FAST! tcc generates optimized x86 code. No byte code overhead. Compile, assemble and link about 7 times faster than 'gcc -O0'. - UNLIMITED! Any C dynamic library can be used directly. TCC is heading torward full ISOC99 compliance. TCC can of course compile itself. - SAFE! tcc includes an optional memory and bound checker. Bound checked code can be mixed freely with standard code. - Compile and execute C source directly. No linking or assembly necessary. Full C preprocessor included. - C script supported : just add '#!/usr/local/bin/tcc -run' at the first line of your C source, and execute it directly from the command line. Documentation: ------------- 1) Installation on a i386 Linux host (for Windows read tcc-win32.txt) ./configure make make test make install By default, tcc is installed in /usr/local/bin. ./configure --help shows configuration options. 2) Introduction We assume here that you know ANSI C. Look at the example ex1.c to know what the programs look like. The include file <tcclib.h> can be used if you want a small basic libc include support (especially useful for floppy disks). Of course, you can also use standard headers, although they are slower to compile. You can begin your C script with '#!/usr/local/bin/tcc -run' on the first line and set its execute bits (chmod a+x your_script). Then, you can launch the C code as a shell or perl script :-) The command line arguments are put in 'argc' and 'argv' of the main functions, as in ANSI C. 3) Examples ex1.c: simplest example (hello world). Can also be launched directly as a script: './ex1.c'. ex2.c: more complicated example: find a number with the four operations given a list of numbers (benchmark). ex3.c: compute fibonacci numbers (benchmark). ex4.c: more complicated: X11 program. Very complicated test in fact because standard headers are being used ! As for ex1.c, can also be launched directly as a script: './ex4.c'. ex5.c: 'hello world' with standard glibc headers. tcc.c: TCC can of course compile itself. Used to check the code generator. tcctest.c: auto test for TCC which tests many subtle possible bugs. Used when doing 'make test'. 4) Full Documentation Please read tcc-doc.html to have all the features of TCC. Additional information is available for the Windows port in tcc-win32.txt. License: ------- TCC is distributed under the GNU Lesser General Public License (see COPYING file). Fabrice Bellard.