Hi,

I have noticed that the Tiny C Compiler does not not align the stack to 16
bytes on i386 Linux. Unfortunately over the years the ABI defined by gcc
has gradually drifted from 4 bytes to 16 bytes. To reproduce see
https://sourceforge.net/p/fbc/bugs/659/ (that page is the equivalent issue
in freebasic). TCC suffers from the same issue.

I ran into the issue in tcc myself when I attempted to call back from tcc
generated code into the Mozilla Spidermonkey JavaScript VM via js-ctypes
callbacks. I was able to hack around it in my project with a bit of inline
assembly
https://github.com/cosinusoidally/mishmashvm/commit/8746e482256af04589bdfcda14d955713f2e3651
but in the general case this is not a complete fix as I may eventually end
up calling some affected system library from tcc generated code. I've been
luckly so far, but there's a good chance I'll eventually hit this issue
again.

I did have a stab at implementing something like mstackrealign in tcc, but
the code I wrote was subtly buggy (breaks several tests and produces some
buggy binaries). Included below in case it is any use as the basis of a
real fix:

diff --git a/i386-gen.c b/i386-gen.c
index 8c245ad..8a33135 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -402,14 +402,41 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic,
CType *ret, int *ret_align, int
 #endif
 }

+int gfunc_call_realign(){
+    //      50                      push   %eax
+    o(0x50);
+    //      89 e0                   mov    %esp,%eax
+    o(0x89); o(0xe0);
+    //      83 c0 04                add    $0x4,%eax
+    o(0x83); o(0xc0); o(0x04);
+    //      81 e4 f0 ff ff ff       and    $0xfffffff0,%esp
+    o(0x81); o(0xe4); o(0xf0); o(0xff); o(0xff); o(0xff);
+    //      90                      nop
+    int foo1=ind;
+    o(0x90);
+    o(0x90);
+    o(0x90);
+    //      50                      push   %eax
+    o(0x50);
+    //      8b 40 fc                mov    -0x4(%eax),%eax
+    o(0x8b); o(0x40); o(0xfc);
+
+    return foo1;
+}
+
 /* Generate function call. The function address is pushed first, then
    all the parameters in call order. This functions pops all the
    parameters and the function address. */
 ST_FUNC void gfunc_call(int nb_args)
 {
-    int size, align, r, args_size, i, func_call;
+    int size, align, r, args_size, i, func_call,foo1;
+    int pre=0;
     Sym *func_sym;
-
+    if(nb_args==0){
+        foo1=gfunc_call_realign();
+       pre=1;
+    }
+
 #ifdef CONFIG_TCC_BCHECK
     if (tcc_state->do_bounds_check)
         gbound_args(nb_args);
@@ -432,6 +459,12 @@ ST_FUNC void gfunc_call(int nb_args)
             } else
 #endif
             {
+               // insert stack realign
+               if(pre==0){
+                   foo1=gfunc_call_realign();
+                  pre=1;
+                }
+
                 oad(0xec81, size); /* sub $xxx, %esp */
                 /* generate structure store */
                 r = get_reg(RC_INT);
@@ -443,6 +476,17 @@ ST_FUNC void gfunc_call(int nb_args)
             args_size += size;
         } else if (is_float(vtop->type.t)) {
             gv(RC_FLOAT); /* only one float register */
+
+           // insert stack realign
+           if(pre==0){
+               foo1=gfunc_call_realign();
+              pre=1;
+            }
+            if(pre==0){
+                foo1=gfunc_call_realign();
+               pre=1;
+            }
+
             if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
                 size = 4;
             else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
@@ -461,6 +505,13 @@ ST_FUNC void gfunc_call(int nb_args)
             /* simple type (currently always same size) */
             /* XXX: implicit cast ? */
             r = gv(RC_INT);
+
+           // insert stack realign
+           if(pre==0){
+               foo1=gfunc_call_realign();
+              pre=1;
+            }
+
             if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
                 size = 8;
                 o(0x50 + vtop->r2); /* push r */
@@ -505,6 +556,13 @@ ST_FUNC void gfunc_call(int nb_args)
     if (args_size && func_call != FUNC_STDCALL && func_call != FUNC_FASTCALLW)
         gadd_sp(args_size);
     vtop--;
+
+    //      5c                      pop    %esp
+    o(0x5c);
+    int blah=(4-(((args_size+4) & 15)>> 2))&3;
+    for(int bar=0;bar<blah;bar++){
+        cur_text_section->data[foo1+bar] = 0x50;
+    }
 }

 #ifdef TCC_TARGET_PE

Thanks

Liam Wilson
_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to