summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2012-06-12 17:51:49 +0200
committerThomas Preud'homme <robotux@celest.fr>2012-06-12 17:51:49 +0200
commit9cb064c2db59fb92a3cee7c0e9fd447aec2083f3 (patch)
tree08e5102b995af057f84d71866100c1542a1b183b
parentd178eb7650ef7356ca4e6d9d64ac242dcff64811 (diff)
Imported Upstream version 0.9.26~git20120612.ad5f375
-rw-r--r--.gitignore11
-rw-r--r--Changelog1
-rw-r--r--Makefile21
-rw-r--r--arm-gen.c384
-rwxr-xr-xconfigure4
-rwxr-xr-xexamples/ex1.c2
-rwxr-xr-xexamples/ex4.c2
-rw-r--r--i386-gen.c6
-rw-r--r--lib/Makefile18
-rw-r--r--lib/bcheck.c8
-rw-r--r--libtcc.c30
-rw-r--r--tcc-doc.texi2
-rw-r--r--tcc.c21
-rw-r--r--tcc.h127
-rw-r--r--tccasm.c2
-rw-r--r--tccelf.c25
-rw-r--r--tccgen.c102
-rw-r--r--tccpe.c11
-rw-r--r--tccpp.c55
-rw-r--r--tccrun.c21
-rw-r--r--tests/Makefile8
-rw-r--r--tests/tcctest.c216
-rw-r--r--win32/build-tcc.bat5
-rw-r--r--win32/tcc-win32.txt2
-rw-r--r--x86_64-gen.c90
25 files changed, 907 insertions, 267 deletions
diff --git a/.gitignore b/.gitignore
index a845ddc..bfcf93a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,11 +30,20 @@ p.c
p2.c
tcctest[1234]
test[1234].out
+tests/tcclib.h
+tests/tcctest.gcc
.gdb_history
tcc.1
tcc.pod
config.h
config.mak
config.texi
-tests
tags
+.DS_Store
+*.swp
+lib/x86_64
+lib/i386
+tcc-doc.info
+conftest*
+tiny_libmaker
+*.dSYM
diff --git a/Changelog b/Changelog
index 14cc9a1..2a19902 100644
--- a/Changelog
+++ b/Changelog
@@ -14,6 +14,7 @@ not released:
- Support indirect functions as externals (Thomas Preud'homme)
- Add support for C99 variable length arrays (Thomas Preud'homme & Joe Soroka)
- Improve support of ARM (Daniel Glöckner)
+- Support ARM hardfloat calling convention (Thomas Preud'homme)
version 0.9.25:
diff --git a/Makefile b/Makefile
index 43d7cfd..3b6acdd 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,7 @@ CFLAGS+=-Wno-pointer-sign -Wno-sign-compare -D_FORTIFY_SOURCE=0
endif
endif
+ifneq ($(TARGETOS),Darwin)
ifeq ($(ARCH),i386)
CFLAGS+=-mpreferred-stack-boundary=2
ifeq ($(GCC_MAJOR),2)
@@ -23,6 +24,7 @@ else
CFLAGS+=-march=i386 -falign-functions=0
endif
endif
+endif
ifdef CONFIG_WIN64
CONFIG_WIN32=yes
@@ -36,11 +38,15 @@ endif
endif
ifeq ($(ARCH),i386)
-NATIVE_DEFINES=-DTCC_TARGET_I386
+NATIVE_DEFINES=-DTCC_TARGET_I386
+NATIVE_DEFINES+=$(if $(wildcard /lib/i386-linux-gnu),-DCONFIG_MULTIARCHDIR=\"i386-linux-gnu\")
+CFLAGS+=-m32
else
ifeq ($(ARCH),x86-64)
NATIVE_DEFINES=-DTCC_TARGET_X86_64
-NATIVE_DEFINES+=$(if $(wildcard /lib64/ld-linux-x86-64.so.2),-DTCC_TARGET_X86_64_CENTOS)
+CFLAGS+=-m64
+NATIVE_DEFINES+=$(if $(wildcard /usr/lib64),-DCONFIG_LDDIR=\"lib64\")
+NATIVE_DEFINES+=$(if $(wildcard /lib/x86_64-linux-gnu),-DCONFIG_MULTIARCHDIR=\"x86_64-linux-gnu\")
endif
endif
@@ -48,7 +54,10 @@ ifeq ($(ARCH),arm)
NATIVE_DEFINES=-DTCC_TARGET_ARM
NATIVE_DEFINES+=-DWITHOUT_LIBTCC
NATIVE_DEFINES+=$(if $(wildcard /lib/ld-linux.so.3),-DTCC_ARM_EABI)
+NATIVE_DEFINES+=$(if $(wildcard /lib/arm-linux-gnueabi),-DCONFIG_MULTIARCHDIR=\"arm-linux-gnueabi\")
NATIVE_DEFINES+=$(if $(shell grep -l "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo),-DTCC_ARM_VFP)
+# To use ARM hardfloat calling convension
+#NATIVE_DEFINES+=-DTCC_ARM_HARDFLOAT
endif
ifdef CONFIG_WIN32
@@ -136,6 +145,10 @@ endif
ifdef CONFIG_UCLIBC
BCHECK_O=
endif
+ifeq ($(TARGETOS),Darwin)
+BCHECK_O=
+PROGS+=tiny_libmaker$(EXESUF)
+endif
ifdef CONFIG_USE_LIBGCC
LIBTCC1=
@@ -153,7 +166,7 @@ all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
# Host Tiny C Compiler
tcc$(EXESUF): tcc.o $(LIBTCC)
- $(CC) -o $@ $^ $(LIBS) $(LDFLAGS) $(LINK_LIBTCC)
+ $(CC) -o $@ $^ $(LIBS) $(CFLAGS) $(LDFLAGS) $(LINK_LIBTCC)
# Cross Tiny C Compilers
%-tcc$(EXESUF):
@@ -190,7 +203,7 @@ LIBTCC_INC = $(filter %.h,$(CORE_FILES)) $(filter-out $(CORE_FILES),$(NATIVE_FIL
else
LIBTCC_OBJ = libtcc.o
LIBTCC_INC = $(NATIVE_FILES)
-$(LIBTCC_OBJ) tcc.o : NATIVE_DEFINES += -DONE_SOURCE
+libtcc.o : NATIVE_DEFINES += -DONE_SOURCE
endif
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
diff --git a/arm-gen.c b/arm-gen.c
index b7e8665..d8e68ae 100644
--- a/arm-gen.c
+++ b/arm-gen.c
@@ -737,16 +737,85 @@ static void gcall_or_jmp(int is_jmp)
}
}
+#ifdef TCC_ARM_HARDFLOAT
+static int is_float_hgen_aggr(CType *type)
+{
+ if ((type->t & VT_BTYPE) == VT_STRUCT) {
+ struct Sym *ref;
+ int btype, nb_fields = 0;
+
+ ref = type->ref;
+ btype = ref->type.t & VT_BTYPE;
+ if (btype == VT_FLOAT || btype == VT_DOUBLE) {
+ for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
+ return !ref && nb_fields <= 4;
+ }
+ }
+ return 0;
+}
+
+struct avail_regs {
+ /* worst case: f(float, double, 3 float struct, double, 3 float struct, double) */
+ signed char avail[3];
+ int first_hole;
+ int last_hole;
+ int first_free_reg;
+};
+
+#define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
+
+/* Assign a register for a CPRC param with correct size and alignment
+ * size and align are in bytes, as returned by type_size */
+int assign_fpreg(struct avail_regs *avregs, int align, int size)
+{
+ int first_reg = 0;
+
+ if (avregs->first_free_reg == -1)
+ return -1;
+ if (align >> 3) { // alignment needed (base type: double)
+ first_reg = avregs->first_free_reg;
+ if (first_reg & 1)
+ avregs->avail[avregs->last_hole++] = first_reg++;
+ } else {
+ if (size == 4 && avregs->first_hole != avregs->last_hole)
+ return avregs->avail[avregs->first_hole++];
+ else
+ first_reg = avregs->first_free_reg;
+ }
+ if (first_reg + size / 4 <= 16) {
+ avregs->first_free_reg = first_reg + size / 4;
+ return first_reg;
+ }
+ avregs->first_free_reg = -1;
+ return -1;
+}
+#endif
+
/* 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. */
void gfunc_call(int nb_args)
{
- int size, align, r, args_size, i;
- Sym *func_sym;
+ int size, align, r, args_size, i, ncrn, ncprn, argno, vfp_argno;
signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
- int todo=0xf, keep, plan2[4]={0,0,0,0};
+ SValue *before_stack = NULL; /* SValue before first on stack argument */
+ SValue *before_vfpreg_hfa = NULL; /* SValue before first in VFP reg hfa argument */
+#ifdef TCC_ARM_HARDFLOAT
+ struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
+ signed char vfp_plan[16];
+ int plan2[4+16];
+ int variadic;
+#else
+ int plan2[4]={0,0,0,0};
+#endif
+ int vfp_todo=0;
+ int todo=0, keep;
+#ifdef TCC_ARM_HARDFLOAT
+ memset(vfp_plan, -1, sizeof(vfp_plan));
+ memset(plan2, 0, sizeof(plan2));
+ variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
+#endif
r = vtop->r & VT_VALMASK;
if (r == VT_CMP || (r & ~1) == VT_JMP)
gv(RC_INT);
@@ -763,42 +832,131 @@ void gfunc_call(int nb_args)
vpushi(0);
vtop->type.t = VT_LLONG;
args_size = 0;
+#endif
+ ncrn = ncprn = argno = vfp_argno = 0;
+ /* Assign argument to registers and stack with alignment.
+ If, considering alignment constraints, enough registers of the correct type
+ (core or VFP) are free for the current argument, assign them to it, else
+ allocate on stack with correct alignment. Whenever a structure is allocated
+ in registers or on stack, it is always put on the stack at this stage. The
+ stack is divided in 3 zones. The zone are, from low addresses to high
+ addresses: structures to be loaded in core registers, structures to be
+ loaded in VFP registers, argument allocated to stack. SValue's representing
+ structures in the first zone are moved just after the SValue pointed by
+ before_vfpreg_hfa. SValue's representing structures in the second zone are
+ moved just after the SValue pointer by before_stack. */
for(i = nb_args + 1 ; i-- ;) {
+ int j, assigned_vfpreg = 0;
size = type_size(&vtop[-i].type, &align);
- if(args_size & (align-1)) {
- vpushi(0);
- vtop->type.t = VT_VOID; /* padding */
- vrott(i+2);
- args_size += 4;
- ++nb_args;
- }
- args_size += (size + 3) & -4;
- }
- vtop--;
-#endif
- args_size = 0;
- for(i = nb_args ; i-- && args_size < 16 ;) {
switch(vtop[-i].type.t & VT_BTYPE) {
case VT_STRUCT:
case VT_FLOAT:
case VT_DOUBLE:
case VT_LDOUBLE:
- size = type_size(&vtop[-i].type, &align);
- size = (size + 3) & -4;
- args_size += size;
+#ifdef TCC_ARM_HARDFLOAT
+ if (!variadic) {
+ int hfa = 0; /* Homogeneous float aggregate */
+
+ if (is_float(vtop[-i].type.t)
+ || (hfa = is_float_hgen_aggr(&vtop[-i].type))) {
+ int end_reg;
+
+ assigned_vfpreg = assign_fpreg(&avregs, align, size);
+ end_reg = assigned_vfpreg + (size - 1) / 4;
+ if (assigned_vfpreg >= 0) {
+ vfp_plan[vfp_argno++]=TREG_F0 + assigned_vfpreg/2;
+ if (hfa) {
+ /* before_stack can only have been set because all core registers
+ are assigned, so no need to care about before_vfpreg_hfa if
+ before_stack is set */
+ if (before_stack) {
+ vrote(&vtop[-i], &vtop[-i] - before_stack);
+ before_stack++;
+ } else if (!before_vfpreg_hfa)
+ before_vfpreg_hfa = &vtop[-i-1];
+ for (j = assigned_vfpreg; j <= end_reg; j++)
+ vfp_todo|=(1<<j);
+ }
+ continue;
+ } else {
+ if (!hfa)
+ vfp_argno++;
+ /* No need to update before_stack as no more hfa can be allocated in
+ VFP regs */
+ if (!before_vfpreg_hfa)
+ before_vfpreg_hfa = &vtop[-i-1];
+ break;
+ }
+ }
+ }
+#endif
+ ncrn = (ncrn + (align-1)/4) & -(align/4);
+ size = (size + 3) & -4;
+ if (ncrn + size/4 <= 4 || (ncrn < 4 && assigned_vfpreg != -1)) {
+ /* Either there is HFA in VFP registers, or there is arguments on stack,
+ it cannot be both. Hence either before_stack already points after
+ the slot where the vtop[-i] SValue is moved, or before_stack will not
+ be used */
+ if (before_vfpreg_hfa) {
+ vrote(&vtop[-i], &vtop[-i] - before_vfpreg_hfa);
+ before_vfpreg_hfa++;
+ }
+ for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
+ todo|=(1<<j);
+ ncrn+=size/4;
+ if (ncrn > 4) {
+ args_size = (ncrn - 4) * 4;
+ if (!before_stack)
+ before_stack = &vtop[-i-1];
+ }
+ }
+ else {
+ ncrn = 4;
+ /* No need to set before_vfpreg_hfa if not set since there will no
+ longer be any structure assigned to core registers */
+ if (!before_stack)
+ before_stack = &vtop[-i-1];
break;
+ }
+ continue;
default:
- plan[nb_args-1-i][0]=args_size/4;
- args_size += 4;
- if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) {
- plan[nb_args-1-i][1]=args_size/4;
- args_size += 4;
+ if (!i) {
+ break;
}
+ if (ncrn < 4) {
+ int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG;
+
+ if (is_long) {
+ ncrn = (ncrn + 1) & -2;
+ if (ncrn == 4) {
+ argno++;
+ break;
+ }
+ }
+ plan[argno++][0]=ncrn++;
+ if (is_long) {
+ plan[argno-1][1]=ncrn++;
+ }
+ continue;
+ }
+ argno++;
}
+#ifdef TCC_ARM_EABI
+ if(args_size & (align-1)) {
+ vpushi(0);
+ vtop->type.t = VT_VOID; /* padding */
+ vrott(i+2);
+ args_size += 4;
+ nb_args++;
+ argno++;
+ }
+#endif
+ args_size += (size + 3) & -4;
}
+ vtop--;
args_size = keep = 0;
for(i = 0;i < nb_args; i++) {
- vnrott(keep+1);
+ vrotb(keep+1);
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
size = type_size(&vtop->type, &align);
/* align to stack align size */
@@ -814,6 +972,12 @@ void gfunc_call(int nb_args)
vtop--;
args_size += size;
} else if (is_float(vtop->type.t)) {
+#ifdef TCC_ARM_HARDFLOAT
+ if (!variadic && --vfp_argno<16 && vfp_plan[vfp_argno]!=-1) {
+ plan2[keep++]=vfp_plan[vfp_argno];
+ continue;
+ }
+#endif
#ifdef TCC_ARM_VFP
r=vfpr(gv(RC_FLOAT))<<12;
size=4;
@@ -848,57 +1012,59 @@ void gfunc_call(int nb_args)
size=4;
if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
lexpand_nr();
- s=RC_INT;
- if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) {
- s=regmask(plan[nb_args-i-1][1]);
- todo&=~(1<<plan[nb_args-i-1][1]);
- }
- if(s==RC_INT) {
- r = gv(s);
+ s=-1;
+ if(--argno<4 && plan[argno][1]!=-1)
+ s=plan[argno][1];
+ argno++;
+ size = 8;
+ if(s==-1) {
+ r = gv(RC_INT);
o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
vtop--;
} else {
+ size=0;
plan2[keep]=s;
keep++;
vswap();
}
- size = 8;
- }
- s=RC_INT;
- if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) {
- s=regmask(plan[nb_args-i-1][0]);
- todo&=~(1<<plan[nb_args-i-1][0]);
}
+ s=-1;
+ if(--argno<4 && plan[argno][0]!=-1)
+ s=plan[argno][0];
#ifdef TCC_ARM_EABI
if(vtop->type.t == VT_VOID) {
- if(s == RC_INT)
+ if(s == -1)
o(0xE24DD004); /* sub sp,sp,#4 */
vtop--;
} else
-#endif
- if(s == RC_INT) {
- r = gv(s);
+#endif
+ if(s == -1) {
+ r = gv(RC_INT);
o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
vtop--;
} else {
+ size=0;
plan2[keep]=s;
keep++;
}
args_size += size;
}
}
- for(i=keep;i--;) {
- gv(plan2[i]);
- vrott(keep);
+ for(i = 0; i < keep; i++) {
+ vrotb(keep);
+ gv(regmask(plan2[i]));
+ /* arg is in s(2d+1): plan2[i]<plan2[i+1] => alignment occured (ex f,d,f) */
+ if (i < keep - 1 && is_float(vtop->type.t) && (plan2[i] <= plan2[i + 1])) {
+ o(0xEEF00A40|(vfpr(plan2[i])<<12)|vfpr(plan2[i]));
+ }
}
save_regs(keep); /* save used temporary registers */
keep++;
- if(args_size) {
- int n;
- n=args_size/4;
- if(n>4)
- n=4;
- todo&=((1<<n)-1);
+ if(ncrn) {
+ int nb_regs=0;
+ if (ncrn>4)
+ ncrn=4;
+ todo&=((1<<ncrn)-1);
if(todo) {
int i;
o(0xE8BD0000|todo);
@@ -907,12 +1073,31 @@ save_regs(keep); /* save used temporary registers */
vpushi(0);
vtop->r=i;
keep++;
+ nb_regs++;
}
}
- args_size-=n*4;
+ args_size-=nb_regs*4;
}
- vnrott(keep);
- func_sym = vtop->type.ref;
+ if(vfp_todo) {
+ int nb_fregs=0;
+
+ for(i=0;i<16;i++)
+ if(vfp_todo&(1<<i)) {
+ o(0xED9D0A00|(i&1)<<22|(i>>1)<<12|nb_fregs);
+ vpushi(0);
+ /* There might be 2 floats in a double VFP reg but that doesn't seem
+ to matter */
+ if (!(i%2))
+ vtop->r=TREG_F0+i/2;
+ keep++;
+ nb_fregs++;
+ }
+ if (nb_fregs) {
+ gadd_sp(nb_fregs*4);
+ args_size-=nb_fregs*4;
+ }
+ }
+ vrotb(keep);
gcall_or_jmp(0);
if (args_size)
gadd_sp(args_size);
@@ -924,7 +1109,11 @@ save_regs(keep); /* save used temporary registers */
++keep;
}
#ifdef TCC_ARM_VFP
+#ifdef TCC_ARM_HARDFLOAT
+ else if(variadic && is_float(vtop->type.ref->type.t)) {
+#else
else if(is_float(vtop->type.ref->type.t)) {
+#endif
if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
o(0xEE000A10); /* fmsr s0,r0 */
} else {
@@ -942,26 +1131,38 @@ save_regs(keep); /* save used temporary registers */
void gfunc_prolog(CType *func_type)
{
Sym *sym,*sym2;
- int n,addr,size,align;
+ int n,nf,size,align, variadic, struct_ret = 0;
+#ifdef TCC_ARM_HARDFLOAT
+ struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
+#endif
sym = func_type->ref;
func_vt = sym->type;
-
- n = 0;
- addr = 0;
+
+ n = nf = 0;
+ variadic = (func_type->ref->c == FUNC_ELLIPSIS);
if((func_vt.t & VT_BTYPE) == VT_STRUCT
&& type_size(&func_vt,&align) > 4)
{
- func_vc = addr;
- addr += 4;
n++;
+ struct_ret = 1;
}
- for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) {
+ for(sym2=sym->next;sym2 && (n<4 || nf<16);sym2=sym2->next) {
size = type_size(&sym2->type, &align);
- n += (size + 3) / 4;
+#ifdef TCC_ARM_HARDFLOAT
+ if (!variadic && (is_float(sym2->type.t)
+ || is_float_hgen_aggr(&sym2->type))) {
+ int tmpnf = assign_fpreg(&avregs, align, size) + 1;
+ nf = (tmpnf > nf) ? tmpnf : nf;
+ } else
+#endif
+ if (n < 4)
+ n += (size + 3) / 4;
}
+ if (struct_ret)
+ func_vc = nf * 4;
o(0xE1A0C00D); /* mov ip,sp */
- if(func_type->ref->c == FUNC_ELLIPSIS)
+ if(variadic)
n=4;
if(n) {
if(n>4)
@@ -971,20 +1172,57 @@ void gfunc_prolog(CType *func_type)
#endif
o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
}
+ if (nf) {
+ if (nf>16)
+ nf=16;
+ nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */
+ o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */
+ }
o(0xE92D5800); /* save fp, ip, lr */
o(0xE28DB00C); /* add fp, sp, #12 */
func_sub_sp_offset = ind;
- o(0xE1A00000); /* nop, leave space for stack adjustment */
- while ((sym = sym->next)) {
- CType *type;
- type = &sym->type;
- size = type_size(type, &align);
- size = (size + 3) & -4;
+ o(0xE1A00000); /* nop, leave space for stack adjustment in epilogue */
+ {
+ int addr, pn = struct_ret, sn = 0; /* pn=core, sn=stack */
+
+#ifdef TCC_ARM_HARDFLOAT
+ avregs = AVAIL_REGS_INITIALIZER;
+#endif
+ while ((sym = sym->next)) {
+ CType *type;
+ type = &sym->type;
+ size = type_size(type, &align);
+ size = (size + 3) >> 2;
+#ifdef TCC_ARM_HARDFLOAT
+ if (!variadic && (is_float(sym->type.t)
+ || is_float_hgen_aggr(&sym->type))) {
+ int fpn = assign_fpreg(&avregs, align, size << 2);
+ if (fpn >= 0) {
+ addr = fpn * 4;
+ } else
+ goto from_stack;
+ } else
+#endif
+ if (pn < 4) {
+#ifdef TCC_ARM_EABI
+ pn = (pn + (align-1)/4) & -(align/4);
+#endif
+ addr = (nf + pn) * 4;
+ pn += size;
+ if (!sn && pn > 4)
+ sn = (pn - 4);
+ } else {
+#ifdef TCC_ARM_HARDFLOAT
+from_stack:
+#endif
#ifdef TCC_ARM_EABI
- addr = (addr + align - 1) & -align;
+ sn = (sn + (align-1)/4) & -(align/4);
#endif
- sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
- addr += size;
+ addr = (n + nf + sn) * 4;
+ sn += size;
+ }
+ sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
+ }
}
last_itod_magic=0;
leaffunc = 1;
@@ -997,6 +1235,8 @@ void gfunc_epilog(void)
uint32_t x;
int diff;
#ifdef TCC_ARM_EABI
+ /* Useless but harmless copy of the float result into main register(s) in case
+ of variadic function in the hardfloat variant */
if(is_float(func_vt.t)) {
if((func_vt.t & VT_BTYPE) == VT_FLOAT)
o(0xEE100A10); /* fmrs r0, s0 */
diff --git a/configure b/configure
index 3d68b1c..f152cf9 100755
--- a/configure
+++ b/configure
@@ -168,7 +168,7 @@ for opt do
;;
--help|-h) show_help="yes"
;;
- *) echo "configure: unrecognized option $opt"; exit 1
+ *) echo "configure: WARNING: unrecognized option $opt"
;;
esac
done
@@ -352,6 +352,7 @@ echo "Doc directory $docdir"
echo "Target root prefix $sysroot"
echo "Source path $source_path"
echo "C compiler $cc"
+echo "Target OS $targetos"
echo "CPU $cpu"
echo "Big Endian $bigendian"
echo "gprof enabled $gprof"
@@ -425,6 +426,7 @@ else
echo "Unsupported CPU"
exit 1
fi
+echo "TARGETOS=$targetos" >> config.mak
if test "$noldl" = "yes" ; then
echo "CONFIG_NOLDL=yes" >> config.mak
fi
diff --git a/examples/ex1.c b/examples/ex1.c
index 87d6019..3d2a3e1 100755
--- a/examples/ex1.c
+++ b/examples/ex1.c
@@ -1,4 +1,4 @@
-#!/usr/bin/env tcc -run
+#!/usr/local/bin/tcc -run
#include <tcclib.h>
int main()
diff --git a/examples/ex4.c b/examples/ex4.c
index 7611910..f92c0da 100755
--- a/examples/ex4.c
+++ b/examples/ex4.c
@@ -1,4 +1,4 @@
-#!/usr/bin/env tcc -run -L/usr/X11R6/lib -lX11
+#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
#include <stdio.h>
#include <X11/Xlib.h>
diff --git a/i386-gen.c b/i386-gen.c
index 686419c..6635559 100644
--- a/i386-gen.c
+++ b/i386-gen.c
@@ -229,8 +229,10 @@ ST_FUNC void load(int r, SValue *sv)
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.ul = fc;
- load(r, &v1);
fr = r;
+ if (!(reg_classes[fr] & RC_INT))
+ fr = get_reg(RC_INT);
+ load(fr, &v1);
}
if ((ft & VT_BTYPE) == VT_FLOAT) {
o(0xd9); /* flds */
@@ -1068,7 +1070,7 @@ ST_FUNC void gen_bounded_ptr_deref(void)
case 12: func = TOK___bound_ptr_indir12; break;
case 16: func = TOK___bound_ptr_indir16; break;
default:
- tcc_error("unhandled size when derefencing bounded pointer");
+ tcc_error("unhandled size when dereferencing bounded pointer");
func = 0;
break;
}
diff --git a/lib/Makefile b/lib/Makefile
index 071c49f..d7d2c3f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -14,11 +14,15 @@ ifndef TARGET
else
ifeq ($(ARCH),i386)
TARGET = i386
- XCC = gcc -O2
+ ifneq ($(TARGETOS),Darwin)
+ XCC = gcc -O2 -m32
+ endif
else
ifeq ($(ARCH),x86-64)
TARGET = x86_64
- XCC = gcc -O2
+ ifneq ($(TARGETOS),Darwin)
+ XCC = gcc -O2 -m64
+ endif
endif
endif
endif
@@ -55,12 +59,18 @@ else
ifeq "$(TARGET)" "i386"
OBJ = $(addprefix $(DIR)/,$(I386_O))
TGT = -DTCC_TARGET_I386
- XCC ?= $(TCC) -B$(TOP)
+ XCC ?= $(TCC) -B$(TOP) -m32 -D_ANSI_SOURCE
+ ifeq ($(TARGETOS),Darwin)
+ XAR = $(DIR)/tiny_libmaker$(EXESUF)
+ endif
else
ifeq "$(TARGET)" "x86_64"
OBJ = $(addprefix $(DIR)/,$(X86_64_O))
TGT = -DTCC_TARGET_X86_64
- XCC ?= $(TCC) -B$(TOP)
+ XCC ?= $(TCC) -B$(TOP) -m64 -D_ANSI_SOURCE
+ ifeq ($(TARGETOS),Darwin)
+ XAR = $(DIR)/tiny_libmaker$(EXESUF)
+ endif
else
$(error libtcc1.a not supported on target '$(TARGET)')
endif
diff --git a/lib/bcheck.c b/lib/bcheck.c
index 9996649..48d7606 100644
--- a/lib/bcheck.c
+++ b/lib/bcheck.c
@@ -216,6 +216,14 @@ BOUND_PTR_INDIR(16)
__asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\
fp = fp1[0];\
}
+#elif defined(__x86_64__)
+/* TCC always creates %rbp frames also on x86_64, so use them. */
+#define GET_CALLER_FP(fp)\
+{\
+ unsigned long *fp1;\
+ __asm__ __volatile__ ("movq %%rbp,%0" :"=g" (fp1));\
+ fp = fp1[0];\
+}
#else
#error put code to extract the calling frame pointer
#endif
diff --git a/libtcc.c b/libtcc.c
index 8f5cd0e..b0a9b1a 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -237,6 +237,8 @@ PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size)
mem_cur_size -= malloc_usable_size(ptr);
#endif
ptr1 = realloc(ptr, size);
+ if (!ptr1 && size)
+ tcc_error("memory full");
#ifdef MEM_DEBUG
/* NOTE: count not correct if alloc error, but not critical */
mem_cur_size += malloc_usable_size(ptr1);
@@ -282,8 +284,6 @@ PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data)
else
nb_alloc = nb * 2;
pp = tcc_realloc(pp, nb_alloc * sizeof(void *));
- if (!pp)
- tcc_error("memory full");
*ptab = pp;
}
pp[nb++] = data;
@@ -377,8 +377,6 @@ ST_FUNC void section_realloc(Section *sec, unsigned long new_size)
while (size < new_size)
size = size * 2;
data = tcc_realloc(sec->data, size);
- if (!data)
- tcc_error("memory full");
memset(data + sec->data_allocated, 0, size - sec->data_allocated);
sec->data = data;
sec->data_allocated = size;
@@ -425,7 +423,7 @@ ST_FUNC Section *find_section(TCCState *s1, const char *name)
/* update sym->c so that it points to an external symbol in section
'section' with value 'value' */
ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
- unsigned long value, unsigned long size,
+ uplong value, unsigned long size,
int can_add_underscore)
{
int sym_type, sym_bind, sh_num, info, other;
@@ -529,7 +527,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section,
}
ST_FUNC void put_extern_sym(Sym *sym, Section *section,
- unsigned long value, unsigned long size)
+ uplong value, unsigned long size)
{
put_extern_sym2(sym, section, value, size, 1);
}
@@ -747,6 +745,12 @@ static int tcc_compile(TCCState *s1)
char_pointer_type.t = VT_BYTE;
mk_pointer(&char_pointer_type);
+#if PTR_SIZE == 4
+ size_type.t = VT_INT;
+#else
+ size_type.t = VT_LLONG;
+#endif
+
func_old_type.t = VT_FUNC;
func_old_type.ref = sym_push(SYM_FIELD, &int_type, FUNC_CDECL, FUNC_OLD);
@@ -980,6 +984,7 @@ LIBTCCAPI TCCState *tcc_new(void)
#endif
/* glibc defines */
+ tcc_define_symbol(s, "__REDIRECT(name, proto, alias)", "name proto __asm__ (#alias)");
tcc_define_symbol(s, "__REDIRECT_NTH(name, proto, alias)", "name proto __asm__ (#alias) __THROW");
#ifndef TCC_TARGET_PE
@@ -1002,6 +1007,7 @@ LIBTCCAPI TCCState *tcc_new(void)
".strtab",
".hashtab", SHF_PRIVATE);
strtab_section = symtab_section->link;
+ s->symtab = symtab_section;
/* private symbol table for dynamic symbols */
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE,
@@ -1488,12 +1494,14 @@ PUB_FUNC const char * tcc_set_linker(TCCState *s, char *option, int multi)
end = NULL;
if (link_option(option, "Bsymbolic", &p)) {
s->symbolic = TRUE;
+ } else if (link_option(option, "nostdlib", &p)) {
+ s->nostdlib = TRUE;
} else if (link_option(option, "fini=", &p)) {
s->fini_symbol = p;
if (s->warn_unsupported)
tcc_warning("ignoring -fini %s", p);
} else if (link_option(option, "image-base=", &p)) {
- s->text_addr = strtoul(p, &end, 16);
+ s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1;
} else if (link_option(option, "init=", &p)) {
s->init_symbol = p;
@@ -1562,10 +1570,12 @@ PUB_FUNC const char * tcc_set_linker(TCCState *s, char *option, int multi)
#endif
} else if (link_option(option, "Ttext=", &p)) {
- s->text_addr = strtoul(p, &end, 16);
+ s->text_addr = strtoull(p, &end, 16);
s->has_text_addr = 1;
-
} else {
+ char *comma_ptr = strchr(option, ',');
+ if (comma_ptr)
+ *comma_ptr = '\0';
return option;
}
@@ -1657,7 +1667,7 @@ PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *file
fprintf(depout, "%s : \\\n", target);
for (i=0; i<s->nb_target_deps; ++i)
- fprintf(depout, "\t%s \\\n", s->target_deps[i]);
+ fprintf(depout, " %s \\\n", s->target_deps[i]);
fprintf(depout, "\n");
fclose(depout);
}
diff --git a/tcc-doc.texi b/tcc-doc.texi
index 2522e48..4d4a029 100644
--- a/tcc-doc.texi
+++ b/tcc-doc.texi
@@ -334,6 +334,8 @@ Generate additional support code to check
memory allocations and array/pointer bounds. @option{-g} is implied. Note
that the generated code is slower and bigger in this case.
+Note: @option{-b} is only available on i386 for the moment.
+
@item -bt N
Display N callers in stack traces. This is useful with @option{-g} or
@option{-b}.
diff --git a/tcc.c b/tcc.c
index 0c51451..5dd5725 100644
--- a/tcc.c
+++ b/tcc.c
@@ -35,6 +35,7 @@ static int do_bench = 0;
static int gen_deps;
static const char *deps_outfile;
static const char *m_option;
+static CString linker_arg;
#define TCC_OPTION_HAS_ARG 0x0001
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
@@ -282,8 +283,9 @@ static int parse_args(TCCState *s, int argc, char **argv)
int was_pthread;
was_pthread = 0; /* is set if commandline contains -pthread key */
+ optind = 0;
+ cstr_new(&linker_arg);
- optind = 1;
while (optind < argc) {
r = argv[optind++];
@@ -442,8 +444,10 @@ static int parse_args(TCCState *s, int argc, char **argv)
s->rdynamic = 1;
break;
case TCC_OPTION_Wl:
- if ((r = (char *) tcc_set_linker(s, (char *)optarg, TRUE)))
- tcc_error("unsupported linker option '%s'", r);
+ if (linker_arg.size)
+ --linker_arg.size, cstr_ccat(&linker_arg, ',');
+ cstr_cat(&linker_arg, optarg);
+ cstr_ccat(&linker_arg, '\0');
break;
case TCC_OPTION_E:
output_type = TCC_OUTPUT_PREPROCESS;
@@ -465,6 +469,8 @@ static int parse_args(TCCState *s, int argc, char **argv)
}
}
}
+ if (NULL != (r1 = tcc_set_linker(s, (char *) linker_arg.data, TRUE)))
+ tcc_error("unsupported linker option '%s'", r1);
/* fixme: these options could be different on your platform */
if (was_pthread && output_type != TCC_OUTPUT_OBJ) {
dynarray_add((void ***)&files, &nb_files, "-lpthread");
@@ -494,7 +500,7 @@ int main(int argc, char **argv)
m_option = NULL;
ret = 0;
- optind = parse_args(s, argc, argv);
+ optind = parse_args(s, argc - 1, argv + 1);
#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386
if (m_option)
@@ -578,7 +584,11 @@ int main(int argc, char **argv)
tcc_print_stats(s, getclock_us() - start_time);
if (s->output_type == TCC_OUTPUT_MEMORY) {
- ret = tcc_run(s, argc - optind, argv + optind);
+#ifdef TCC_IS_NATIVE
+ ret = tcc_run(s, argc - 1 - optind, argv + 1 + optind);
+#else
+ tcc_error_noabort("-run is not available in a cross compiler");
+#endif
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile)
fclose(s->outfile);
@@ -593,6 +603,7 @@ int main(int argc, char **argv)
}
tcc_delete(s);
+ cstr_free(&linker_arg);
tcc_free(outfile);
#ifdef MEM_DEBUG
diff --git a/tcc.h b/tcc.h
index d158829..8bca9ae 100644
--- a/tcc.h
+++ b/tcc.h
@@ -49,11 +49,9 @@
#include <direct.h> /* getcwd */
#define inline __inline
#define inp next_inp
-#ifdef _WIN64
-# define uplong unsigned long long
-#endif
#ifdef LIBTCC_AS_DLL
# define LIBTCCAPI __declspec(dllexport)
+# define PUB_FUNC LIBTCCAPI
#endif
#endif
@@ -67,17 +65,10 @@
#endif /* !CONFIG_TCCBOOT */
-#ifndef uplong
-#define uplong unsigned long
-#endif
-
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
-#include "elf.h"
-#include "stab.h"
-
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -86,6 +77,8 @@
#define SA_SIGINFO 0x00000004u
#endif
+#include "elf.h"
+#include "stab.h"
#include "libtcc.h"
/* parser debug */
@@ -131,8 +124,26 @@
#define TCC_TARGET_COFF
#endif
-#if !defined(CONFIG_TCCBOOT)
-#define CONFIG_TCC_BACKTRACE
+/* only native compiler supports -run */
+#if defined _WIN32 == defined TCC_TARGET_PE
+# if (defined __i386__ || defined _X86_) && defined TCC_TARGET_I386
+# define TCC_IS_NATIVE
+# elif (defined __x86_64__ || defined _AMD64_) && defined TCC_TARGET_X86_64
+# define TCC_IS_NATIVE
+# elif defined __arm__ && defined TCC_TARGET_ARM
+# define TCC_IS_NATIVE
+# endif
+#endif
+
+#if defined TCC_IS_NATIVE && !defined CONFIG_TCCBOOT
+# define CONFIG_TCC_BACKTRACE
+#endif
+
+/* target address type */
+#if defined TCC_TARGET_X86_64 && (!defined __x86_64__ || defined _WIN32)
+# define uplong unsigned long long
+#else
+# define uplong unsigned long
#endif
/* ------------ path configuration ------------ */
@@ -141,17 +152,17 @@
# define CONFIG_SYSROOT ""
#endif
-#ifndef CONFIG_TCC_LDDIR
-# if defined(TCC_TARGET_X86_64_CENTOS)
-# define CONFIG_TCC_LDDIR "/lib64"
-# else
-# define CONFIG_TCC_LDDIR "/lib"
-# endif
+#ifdef CONFIG_MULTIARCHDIR
+# define CONFIG_LDDIR "lib/" CONFIG_MULTIARCHDIR
+#endif
+
+#ifndef CONFIG_LDDIR
+# define CONFIG_LDDIR "lib"
#endif
/* path to find crt1.o, crti.o and crtn.o */
#ifndef CONFIG_TCC_CRTPREFIX
-# define CONFIG_TCC_CRTPREFIX CONFIG_SYSROOT "/usr" CONFIG_TCC_LDDIR
+# define CONFIG_TCC_CRTPREFIX CONFIG_SYSROOT "/usr/" CONFIG_LDDIR
#endif
/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */
@@ -160,6 +171,13 @@
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
# ifdef TCC_TARGET_PE
# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include;{B}/include/winapi"
+# elif defined CONFIG_MULTIARCHDIR
+# define CONFIG_TCC_SYSINCLUDEPATHS \
+ CONFIG_SYSROOT "/usr/local/include" \
+ ":" CONFIG_SYSROOT "/usr/local/include/" CONFIG_MULTIARCHDIR \
+ ":" CONFIG_SYSROOT "/usr/include" \
+ ":" CONFIG_SYSROOT "/usr/include/" CONFIG_MULTIARCHDIR \
+ ":" "{B}/include"
# else
# define CONFIG_TCC_SYSINCLUDEPATHS \
CONFIG_SYSROOT "/usr/local/include" \
@@ -174,9 +192,9 @@
# define CONFIG_TCC_LIBPATHS "{B}/lib"
# else
# define CONFIG_TCC_LIBPATHS \
- CONFIG_SYSROOT "/usr" CONFIG_TCC_LDDIR \
- ":" CONFIG_SYSROOT CONFIG_TCC_LDDIR \
- ":" CONFIG_SYSROOT "/usr/local" CONFIG_TCC_LDDIR
+ CONFIG_SYSROOT "/usr/" CONFIG_LDDIR \
+ ":" CONFIG_SYSROOT "/" CONFIG_LDDIR \
+ ":" CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR
# endif
#endif
@@ -185,20 +203,22 @@
# if defined __FreeBSD__
# define CONFIG_TCC_ELFINTERP "/libexec/ld-elf.so.1"
# elif defined __FreeBSD_kernel__
-# define CONFIG_TCC_ELFINTERP CONFIG_TCC_LDDIR"/ld.so.1"
+# define CONFIG_TCC_ELFINTERP "/lib/ld.so.1"
+# elif defined TCC_ARM_HARDFLOAT
+# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-armhf.so.3"
# elif defined TCC_ARM_EABI
-# define CONFIG_TCC_ELFINTERP CONFIG_TCC_LDDIR"/ld-linux.so.3"
+# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.3"
# elif defined(TCC_TARGET_X86_64)
-# define CONFIG_TCC_ELFINTERP CONFIG_TCC_LDDIR"/ld-linux-x86-64.so.2"
+# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
# elif defined(TCC_UCLIBC)
-# define CONFIG_TCC_ELFINTERP CONFIG_TCC_LDDIR"/ld-uClibc.so.0"
+# define CONFIG_TCC_ELFINTERP "/lib/ld-uClibc.so.0"
# else
-# define CONFIG_TCC_ELFINTERP CONFIG_TCC_LDDIR"/ld-linux.so.2"
+# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
# endif
#endif
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
-#define TCC_LIBGCC CONFIG_SYSROOT CONFIG_TCC_LDDIR "/libgcc_s.so.1"
+#define TCC_LIBGCC CONFIG_SYSROOT "/" CONFIG_LDDIR "/libgcc_s.so.1"
/* -------------------------------------------- */
@@ -313,8 +333,8 @@ typedef struct Section {
int sh_addralign; /* elf section alignment */
int sh_entsize; /* elf entry size */
unsigned long sh_size; /* section size (only used during output) */
- unsigned long sh_addr; /* address at which the section is relocated */
- unsigned long sh_offset; /* file offset */
+ uplong sh_addr; /* address at which the section is relocated */
+ unsigned long sh_offset; /* file offset */
int nb_hashed_syms; /* used to resize the hash table */
struct Section *link; /* link to another section */
struct Section *reloc; /* corresponding section for relocation, if any */
@@ -509,6 +529,9 @@ struct TCCState {
/* exported dynamic symbol section */
Section *dynsym;
+ /* copy of the gobal symtab_section variable */
+ Section *symtab;
+
int nostdinc; /* if true, no standard headers are added */
int nostdlib; /* if true, no standard libraries are added */
int nocommon; /* if true, do not use common symbols for .bss data */
@@ -531,7 +554,7 @@ struct TCCState {
int alacarte_link;
/* address of text section */
- unsigned long text_addr;
+ uplong text_addr;
int has_text_addr;
/* symbols to call at load-time / unload-time */
@@ -871,7 +894,8 @@ enum tcc_token {
#ifndef __GNUC__
#define strtold (long double)strtod
#define strtof (float)strtod
- #define strtoll (long long)strtol
+ #define strtoll _strtoi64
+ #define strtoull _strtoui64
#endif
#else
/* XXX: need to define this to use them in non ISOC99 context */
@@ -944,12 +968,6 @@ ST_DATA int tcc_ext;
/* XXX: get rid of this ASAP */
ST_DATA struct TCCState *tcc_state;
-#ifdef CONFIG_TCC_BACKTRACE
-ST_DATA int rt_num_callers;
-ST_DATA const char **rt_bound_error_msg;
-ST_DATA void *rt_prog_main;
-#endif
-
#define AFF_PRINT_ERROR 0x0001 /* print error if file not found */
#define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */
#define AFF_PREPROCESS 0x0004 /* preprocess file */
@@ -978,12 +996,11 @@ PUB_FUNC void tcc_error(const char *fmt, ...);
PUB_FUNC void tcc_warning(const char *fmt, ...);
/* other utilities */
-ST_INLN void cstr_ccat(CString *cstr, int ch);
-ST_FUNC void cstr_cat(CString *cstr, const char *str);
-ST_FUNC void cstr_wccat(CString *cstr, int ch);
-ST_FUNC void cstr_new(CString *cstr);
-ST_FUNC void cstr_free(CString *cstr);
-ST_FUNC void add_char(CString *cstr, int c);
+PUB_FUNC void cstr_ccat(CString *cstr, int ch);
+PUB_FUNC void cstr_cat(CString *cstr, const char *str);
+PUB_FUNC void cstr_wccat(CString *cstr, int ch);
+PUB_FUNC void cstr_new(CString *cstr);
+PUB_FUNC void cstr_free(CString *cstr);
#define cstr_reset(cstr) cstr_free(cstr)
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
@@ -992,8 +1009,8 @@ ST_FUNC void *section_ptr_add(Section *sec, unsigned long size);
ST_FUNC void section_reserve(Section *sec, unsigned long size);
ST_FUNC Section *find_section(TCCState *s1, const char *name);
-ST_FUNC void put_extern_sym2(Sym *sym, Section *section, unsigned long value, unsigned long size, int can_add_underscore);
-ST_FUNC void put_extern_sym(Sym *sym, Section *section, unsigned long value, unsigned long size);
+ST_FUNC void put_extern_sym2(Sym *sym, Section *section, uplong value, unsigned long size, int can_add_underscore);
+ST_FUNC void put_extern_sym(Sym *sym, Section *section, uplong value, unsigned long size);
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type);
ST_INLN void sym_free(Sym *sym);
@@ -1019,9 +1036,6 @@ PUB_FUNC int tcc_set_flag(TCCState *s, const char *flag_name, int value);
PUB_FUNC void tcc_print_stats(TCCState *s, int64_t total_time);
PUB_FUNC char *tcc_default_target(TCCState *s, const char *default_file);
PUB_FUNC void tcc_gen_makedeps(TCCState *s, const char *target, const char *filename);
-#ifdef CONFIG_TCC_BACKTRACE
-PUB_FUNC void tcc_set_num_callers(int n);
-#endif
/* ------------ tccpp.c ------------ */
@@ -1105,7 +1119,7 @@ ST_DATA Sym *local_stack;
ST_DATA Sym *local_label_stack;
ST_DATA Sym *global_label_stack;
ST_DATA Sym *define_stack;
-ST_DATA CType char_pointer_type, func_old_type, int_type;
+ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
ST_DATA SValue vstack[VSTACK_SIZE], *vtop;
ST_DATA int rsym, anon_sym, ind, loc;
@@ -1126,10 +1140,11 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
ST_FUNC void vset(CType *type, int r, int v);
ST_FUNC void vswap(void);
ST_FUNC void vpush_global_sym(CType *type, int v);
+ST_FUNC void vrote(SValue *e, int n);
ST_FUNC void vrott(int n);
+ST_FUNC void vrotb(int n);
#ifdef TCC_TARGET_ARM
ST_FUNC int get_reg_ex(int rc, int rc2);
-ST_FUNC void vnrott(int n);
ST_FUNC void lexpand_nr(void);
#endif
ST_FUNC void vpushv(SValue *v);
@@ -1328,6 +1343,14 @@ ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol);
#elif !defined TCC_TARGET_PE || !defined _WIN32
ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol);
#endif
+
+#ifdef CONFIG_TCC_BACKTRACE
+ST_DATA int rt_num_callers;
+ST_DATA const char **rt_bound_error_msg;
+ST_DATA void *rt_prog_main;
+PUB_FUNC void tcc_set_num_callers(int n);
+#endif
+
/********************************************************/
/* include the target specific definitions */
@@ -1347,7 +1370,7 @@ ST_FUNC void *resolve_sym(TCCState *s1, const char *symbol);
#endif
#undef TARGET_DEFS_ONLY
-ST_DATA const int reg_classes[NB_REGS];
+ST_DATA const int reg_classes[];
/********************************************************/
#undef ST_DATA
diff --git a/tccasm.c b/tccasm.c
index 527c006..d1d2af1 100644
--- a/tccasm.c
+++ b/tccasm.c
@@ -19,6 +19,7 @@
*/
#include "tcc.h"
+#ifdef CONFIG_TCC_ASM
ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
{
@@ -1115,3 +1116,4 @@ ST_FUNC void asm_global_instr(void)
cstr_free(&astr);
}
+#endif /* CONFIG_TCC_ASM */
diff --git a/tccelf.c b/tccelf.c
index 40c88ab..655860b 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -162,8 +162,8 @@ static void *get_elf_sym_addr(TCCState *s, const char *name, int err)
int sym_index;
ElfW(Sym) *sym;
- sym_index = find_elf_sym(symtab_section, name);
- sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
+ sym_index = find_elf_sym(s->symtab, name);
+ sym = &((ElfW(Sym) *)s->symtab->data)[sym_index];
if (!sym_index || sym->st_shndx == SHN_UNDEF) {
if (err)
tcc_error("%s not defined", name);
@@ -634,6 +634,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
case R_ARM_ABS32:
*(int *)ptr += val;
break;
+ case R_ARM_REL32:
+ *(int *)ptr += val - addr;
case R_ARM_BASE_PREL:
*(int *)ptr += s1->got->sh_addr - addr;
break;
@@ -836,8 +838,6 @@ static void put_got_offset(TCCState *s1, int index, unsigned long val)
while (index >= n)
n *= 2;
tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long));
- if (!tab)
- tcc_error("memory full");
s1->got_offsets = tab;
memset(s1->got_offsets + s1->nb_got_offsets, 0,
(n - s1->nb_got_offsets) * sizeof(unsigned long));
@@ -1153,7 +1153,7 @@ ST_FUNC Section *new_symtab(TCCState *s1,
}
/* put dynamic tag */
-static void put_dt(Section *dynamic, int dt, unsigned long val)
+static void put_dt(Section *dynamic, int dt, uplong val)
{
ElfW(Dyn) *dyn;
dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn)));
@@ -1381,7 +1381,7 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
section_reserve(s1->got, offset + PTR_SIZE);
#ifdef TCC_TARGET_X86_64
/* only works for x86-64 */
- put32(s1->got->data + offset, sym->st_value >> 32);
+ put32(s1->got->data + offset + 4, sym->st_value >> 32);
#endif
put32(s1->got->data + offset, sym->st_value & 0xffffffff);
}
@@ -1421,8 +1421,9 @@ static int elf_output_file(TCCState *s1, const char *filename)
FILE *f;
int fd, mode, ret;
int *section_order;
- int shnum, i, phnum, file_offset, offset, size, j, tmp, sh_order_index, k;
- unsigned long addr;
+ int shnum, i, phnum, file_offset, offset, size, j, sh_order_index, k;
+ long long tmp;
+ uplong addr;
Section *strsec, *s;
ElfW(Shdr) shdr, *sh;
ElfW(Phdr) *phdr, *ph;
@@ -1430,9 +1431,9 @@ static int elf_output_file(TCCState *s1, const char *filename)
unsigned long saved_dynamic_data_offset;
ElfW(Sym) *sym;
int type, file_type;
- unsigned long rel_addr, rel_size;
+ uplong rel_addr, rel_size;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- unsigned long bss_addr, bss_size;
+ uplong bss_addr, bss_size;
#endif
file_type = s1->output_type;
@@ -1747,7 +1748,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
addr = s1->text_addr;
/* we ensure that (addr % ELF_PAGE_SIZE) == file_offset %
ELF_PAGE_SIZE */
- a_offset = addr & (s1->section_align - 1);
+ a_offset = (int) (addr & (s1->section_align - 1));
p_offset = file_offset & (s1->section_align - 1);
if (a_offset < p_offset)
a_offset += s1->section_align;
@@ -1821,7 +1822,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
tmp = addr;
addr = (addr + s->sh_addralign - 1) &
~(s->sh_addralign - 1);
- file_offset += addr - tmp;
+ file_offset += (int) ( addr - tmp );
s->sh_offset = file_offset;
s->sh_addr = addr;
diff --git a/tccgen.c b/tccgen.c
index dc67f02..7295267 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -64,7 +64,7 @@ ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
ST_DATA char *funcname;
-ST_DATA CType char_pointer_type, func_old_type, int_type;
+ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
/* ------------------------------------------------------------------------- */
static void gen_cast(CType *type);
@@ -325,6 +325,17 @@ ST_FUNC void vpushi(int v)
vsetc(&int_type, VT_CONST, &cval);
}
+/* push a pointer sized constant */
+static void vpushs(long long v)
+{
+ CValue cval;
+ if (PTR_SIZE == 4)
+ cval.i = (int)v;
+ else
+ cval.ull = v;
+ vsetc(&size_type, VT_CONST, &cval);
+}
+
/* push long long constant */
static void vpushll(long long v)
{
@@ -441,6 +452,14 @@ ST_FUNC void vswap(void)
{
SValue tmp;
+ /* cannot let cpu flags if other instruction are generated. Also
+ avoid leaving VT_JMP anywhere except on the top of the stack
+ because it would complicate the code generator. */
+ if (vtop >= vstack) {
+ int v = vtop->r & VT_VALMASK;
+ if (v == VT_CMP || (v & ~1) == VT_JMP)
+ gv(RC_INT);
+ }
tmp = vtop[0];
vtop[0] = vtop[-1];
vtop[-1] = tmp;
@@ -942,7 +961,7 @@ static void lbuild(int t)
/* rotate n first stack elements to the bottom
I1 ... In -> I2 ... In I1 [top is right]
*/
-static void vrotb(int n)
+ST_FUNC void vrotb(int n)
{
int i;
SValue tmp;
@@ -953,35 +972,27 @@ static void vrotb(int n)
vtop[0] = tmp;
}
-/* rotate n first stack elements to the top
- I1 ... In -> In I1 ... I(n-1) [top is right]
+/* rotate the n elements before entry e towards the top
+ I1 ... In ... -> In I1 ... I(n-1) ... [top is right]
*/
-ST_FUNC void vrott(int n)
+ST_FUNC void vrote(SValue *e, int n)
{
int i;
SValue tmp;
- tmp = vtop[0];
+ tmp = *e;
for(i = 0;i < n - 1; i++)
- vtop[-i] = vtop[-i - 1];
- vtop[-n + 1] = tmp;
+ e[-i] = e[-i - 1];
+ e[-n + 1] = tmp;
}
-#ifdef TCC_TARGET_ARM
-/* like vrott but in other direction
- In ... I1 -> I(n-1) ... I1 In [top is right]
+/* rotate n first stack elements to the top
+ I1 ... In -> In I1 ... I(n-1) [top is right]
*/
-ST_FUNC void vnrott(int n)
+ST_FUNC void vrott(int n)
{
- int i;
- SValue tmp;
-
- tmp = vtop[-n + 1];
- for(i = n - 1; i > 0; i--)
- vtop[-i] = vtop[-i + 1];
- vtop[0] = tmp;
+ vrote(vtop, n);
}
-#endif
/* pop stack value */
ST_FUNC void vpop(void)
@@ -1505,7 +1516,8 @@ static inline int is_null_pointer(SValue *p)
if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
return 0;
return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) ||
- ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0);
+ ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0) ||
+ ((p->type.t & VT_BTYPE) == VT_PTR && p->c.ptr == 0);
}
static inline int is_integer_btype(int bt)
@@ -2258,6 +2270,8 @@ static void gen_assign_cast(CType *dt)
st = &vtop->type; /* source type */
dbt = dt->t & VT_BTYPE;
sbt = st->t & VT_BTYPE;
+ if (sbt == VT_VOID)
+ tcc_error("Cannot assign void value");
if (dt->t & VT_CONSTANT)
tcc_warning("assignment of read-only location");
switch(dbt) {
@@ -2333,8 +2347,9 @@ ST_FUNC void vstore(void)
ft = vtop[-1].type.t;
sbt = vtop->type.t & VT_BTYPE;
dbt = ft & VT_BTYPE;
- if (((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) ||
- (sbt == VT_INT && dbt == VT_SHORT)) {
+ if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) ||
+ (sbt == VT_INT && dbt == VT_SHORT))
+ && !(vtop->type.t & VT_BITFIELD)) {
/* optimize char/short casts */
delayed_cast = VT_MUSTCAST;
vtop->type.t = ft & (VT_TYPE & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)));
@@ -3587,12 +3602,12 @@ ST_FUNC void unary(void)
if (!(type.t & VT_VLA)) {
if (size < 0)
tcc_error("sizeof applied to an incomplete type");
- vpushi(size);
+ vpushs(size);
} else {
vla_runtime_type_size(&type, &align);
}
} else {
- vpushi(align);
+ vpushs(align);
}
vtop->type.t |= VT_UNSIGNED;
break;
@@ -4130,14 +4145,22 @@ static void expr_cond(void)
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
type.t |= VT_UNSIGNED;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
- /* XXX: test pointer compatibility */
- type = type1;
+ /* If one is a null ptr constant the result type
+ is the other. */
+ if (is_null_pointer (vtop))
+ type = type1;
+ else if (is_null_pointer (&sv))
+ type = type2;
+ /* XXX: test pointer compatibility, C99 has more elaborate
+ rules here. */
+ else
+ type = type1;
} else if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
/* XXX: test function pointer compatibility */
- type = type1;
+ type = bt1 == VT_FUNC ? type1 : type2;
} else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) {
/* XXX: test structure compatibility */
- type = type1;
+ type = bt1 == VT_STRUCT ? type1 : type2;
} else if (bt1 == VT_VOID || bt2 == VT_VOID) {
/* NOTE: as an extension, we accept void on only one side */
type.t = VT_VOID;
@@ -4290,6 +4313,25 @@ static int is_label(void)
}
}
+static void label_or_decl(int l)
+{
+ int last_tok;
+
+ /* fast test first */
+ if (tok >= TOK_UIDENT)
+ {
+ /* no need to save tokc because tok is an identifier */
+ last_tok = tok;
+ next();
+ if (tok == ':') {
+ unget_tok(last_tok);
+ return;
+ }
+ unget_tok(last_tok);
+ }
+ decl(l);
+}
+
static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
int case_reg, int is_expr)
{
@@ -4363,7 +4405,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
}
}
while (tok != '}') {
- decl(VT_LOCAL);
+ label_or_decl(VT_LOCAL);
if (tok != '}') {
if (is_expr)
vpop();
diff --git a/tccpe.c b/tccpe.c
index 51f4c53..4dec1d8 100644
--- a/tccpe.c
+++ b/tccpe.c
@@ -38,10 +38,6 @@
# define ADDR3264 DWORD
#endif
-#if defined _WIN32 && (defined _WIN64) == (defined TCC_TARGET_X86_64)
-#define TCC_IS_NATIVE
-#endif
-
#ifdef _WIN32
void dbg_printf (const char *fmt, ...)
{
@@ -339,7 +335,7 @@ struct pe_info {
const char *filename;
int type;
DWORD sizeofheaders;
- DWORD imagebase;
+ ADDR3264 imagebase;
DWORD start_addr;
DWORD imp_offs;
DWORD imp_size;
@@ -1870,11 +1866,10 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename)
ret = pe_write(&pe);
tcc_free(pe.sec_info);
} else {
-#ifndef TCC_IS_NATIVE
- tcc_error_noabort("-run supported only on native platform");
-#endif
+#ifdef TCC_IS_NATIVE
pe.thunk = data_section;
pe_build_imports(&pe);
+#endif
}
#ifdef PE_PRINT_SECTIONS
diff --git a/tccpp.c b/tccpp.c
index ff47838..aff5a53 100644
--- a/tccpp.c
+++ b/tccpp.c
@@ -112,15 +112,13 @@ static void cstr_realloc(CString *cstr, int new_size)
while (size < new_size)
size = size * 2;
data = tcc_realloc(cstr->data_allocated, size);
- if (!data)
- tcc_error("memory full");
cstr->data_allocated = data;
cstr->size_allocated = size;
cstr->data = data;
}
/* add a byte */
-ST_INLN void cstr_ccat(CString *cstr, int ch)
+PUB_FUNC void cstr_ccat(CString *cstr, int ch)
{
int size;
size = cstr->size + 1;
@@ -130,7 +128,7 @@ ST_INLN void cstr_ccat(CString *cstr, int ch)
cstr->size = size;
}
-ST_FUNC void cstr_cat(CString *cstr, const char *str)
+PUB_FUNC void cstr_cat(CString *cstr, const char *str)
{
int c;
for(;;) {
@@ -143,7 +141,7 @@ ST_FUNC void cstr_cat(CString *cstr, const char *str)
}
/* add a wide char */
-ST_FUNC void cstr_wccat(CString *cstr, int ch)
+PUB_FUNC void cstr_wccat(CString *cstr, int ch)
{
int size;
size = cstr->size + sizeof(nwchar_t);
@@ -153,20 +151,20 @@ ST_FUNC void cstr_wccat(CString *cstr, int ch)
cstr->size = size;
}
-ST_FUNC void cstr_new(CString *cstr)
+PUB_FUNC void cstr_new(CString *cstr)
{
memset(cstr, 0, sizeof(CString));
}
/* free string and reset it to NULL */
-ST_FUNC void cstr_free(CString *cstr)
+PUB_FUNC void cstr_free(CString *cstr)
{
tcc_free(cstr->data_allocated);
cstr_new(cstr);
}
/* XXX: unicode ? */
-ST_FUNC void add_char(CString *cstr, int c)
+static void add_char(CString *cstr, int c)
{
if (c == '\'' || c == '\"' || c == '\\') {
/* XXX: could be more precise if char or string */
@@ -200,8 +198,6 @@ static TokenSym *tok_alloc_new(TokenSym **pts, const char *str, int len)
i = tok_ident - TOK_IDENT;
if ((i % TOK_ALLOC_INCR) == 0) {
ptable = tcc_realloc(table_ident, (i + TOK_ALLOC_INCR) * sizeof(TokenSym *));
- if (!ptable)
- tcc_error("memory full");
table_ident = ptable;
}
@@ -844,8 +840,6 @@ static int *tok_str_realloc(TokenString *s)
len = s->allocated_len * 2;
}
str = tcc_realloc(s->str, len * sizeof(int));
- if (!str)
- tcc_error("memory full");
s->allocated_len = len;
s->str = str;
return str;
@@ -2028,12 +2022,16 @@ static void parse_number(const char *p)
if (lcount >= 2)
tcc_error("three 'l's in integer constant");
lcount++;
+#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
if (lcount == 2) {
+#endif
if (tok == TOK_CINT)
tok = TOK_CLLONG;
else if (tok == TOK_CUINT)
tok = TOK_CULLONG;
+#if !defined TCC_TARGET_X86_64 || defined TCC_TARGET_PE
}
+#endif
ch = *p++;
} else if (t == 'U') {
if (ucount >= 1)
@@ -2699,10 +2697,25 @@ static int macro_subst_tok(TokenString *tok_str,
goto redo;
}
} else {
- /* XXX: incorrect with comments */
ch = file->buf_ptr[0];
- while (is_space(ch) || ch == '\n')
- cinp();
+ while (is_space(ch) || ch == '\n' || ch == '/')
+ {
+ if (ch == '/')
+ {
+ int c;
+ uint8_t *p = file->buf_ptr;
+ PEEKC(c, p);
+ if (c == '*') {
+ p = parse_comment(p);
+ file->buf_ptr = p - 1;
+ } else if (c == '/') {
+ p = parse_line_comment(p);
+ file->buf_ptr = p - 1;
+ } else
+ break;
+ }
+ cinp();
+ }
t = ch;
}
if (t != '(') /* no macro subst */
@@ -2997,8 +3010,16 @@ ST_INLN void unget_tok(int last_tok)
{
int i, n;
int *q;
- unget_saved_macro_ptr = macro_ptr;
- unget_buffer_enabled = 1;
+ if (unget_buffer_enabled)
+ {
+ /* assert(macro_ptr == unget_saved_buffer + 1);
+ assert(*macro_ptr == 0); */
+ }
+ else
+ {
+ unget_saved_macro_ptr = macro_ptr;
+ unget_buffer_enabled = 1;
+ }
q = unget_saved_buffer;
macro_ptr = q;
*q++ = tok;
diff --git a/tccrun.c b/tccrun.c
index 64a1dfd..41081cc 100644
--- a/tccrun.c
+++ b/tccrun.c
@@ -20,6 +20,9 @@
#include "tcc.h"
+/* only native compiler supports -run */
+#ifdef TCC_IS_NATIVE
+
#ifdef CONFIG_TCC_BACKTRACE
ST_DATA int rt_num_callers = 6;
ST_DATA const char **rt_bound_error_msg;
@@ -217,6 +220,8 @@ static void set_pages_executable(void *ptr, unsigned long length)
}
/* ------------------------------------------------------------- */
+#endif /* TCC_IS_NATIVE */
+
#ifdef CONFIG_TCC_BACKTRACE
PUB_FUNC void tcc_set_num_callers(int n)
@@ -461,7 +466,9 @@ static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level)
int i;
if (level == 0) {
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__APPLE__)
+ *paddr = uc->uc_mcontext->__ss.__eip;
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
*paddr = uc->uc_mcontext.mc_eip;
#elif defined(__dietlibc__)
*paddr = uc->uc_mcontext.eip;
@@ -470,7 +477,9 @@ static int rt_get_caller_pc(unsigned long *paddr, ucontext_t *uc, int level)
#endif
return 0;
} else {
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__APPLE__)
+ fp = uc->uc_mcontext->__ss.__ebp;
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
fp = uc->uc_mcontext.mc_ebp;
#elif defined(__dietlibc__)
fp = uc->uc_mcontext.ebp;
@@ -500,14 +509,18 @@ static int rt_get_caller_pc(unsigned long *paddr,
if (level == 0) {
/* XXX: only support linux */
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__APPLE__)
+ *paddr = uc->uc_mcontext->__ss.__rip;
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
*paddr = uc->uc_mcontext.mc_rip;
#else
*paddr = uc->uc_mcontext.gregs[REG_RIP];
#endif
return 0;
} else {
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#if defined(__APPLE__)
+ fp = uc->uc_mcontext->__ss.__rbp;
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
fp = uc->uc_mcontext.mc_rbp;
#else
fp = uc->uc_mcontext.gregs[REG_RBP];
diff --git a/tests/Makefile b/tests/Makefile
index 8cd906d..e07cdc3 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -18,6 +18,12 @@ ifdef DISABLE_STATIC
export LD_LIBRARY_PATH:=$(CURDIR)/..
endif
+ifeq ($(TARGETOS),Darwin)
+CFLAGS+=-Wl,-flat_namespace,-undefined,warning
+export MACOSX_DEPLOYMENT_TARGET:=10.2
+NATIVE_DEFINES+=-D_ANSI_SOURCE
+endif
+
# run local version of tcc with local libraries and includes
TCC = ../tcc -B..
RUN_TCC = $(NATIVE_DEFINES) -run -DONE_SOURCE ../tcc.c -B..
@@ -45,7 +51,7 @@ libtcc_test$(EXESUF): libtcc_test.c ../$(LIBTCC)
# test.ref - generate using gcc
# copy only tcclib.h so GCC's stddef and stdarg will be used
test.ref: tcctest.c
- cp -u ../include/tcclib.h .
+ cp ../include/tcclib.h .
$(CC) -o tcctest.gcc $< -I. -w $(CFLAGS) -std=gnu99
./tcctest.gcc > $@
diff --git a/tests/tcctest.c b/tests/tcctest.c
index f0d82cf..1b04c1f 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -85,6 +85,10 @@ void statement_expr_test(void);
void asm_test(void);
void builtin_test(void);
void weak_test(void);
+void global_data_test(void);
+void cmp_comparison_test(void);
+void math_cmp_test(void);
+void callsave_test(void);
int fib(int n);
void num(int n);
@@ -287,6 +291,10 @@ comment
/* test function macro substitution when the function name is
substituted */
TEST2();
+
+ /* And again when the name and parenthes are separated by a
+ comment. */
+ TEST2 /* the comment */ ();
}
@@ -431,6 +439,7 @@ void loop_test()
printf("\n");
}
+typedef int typedef_and_label;
void goto_test()
{
@@ -439,6 +448,8 @@ void goto_test()
printf("goto:\n");
i = 0;
+ /* This needs to parse as label, not as start of decl. */
+ typedef_and_label:
s_loop:
if (i >= 10)
goto s_end;
@@ -583,6 +594,10 @@ int main(int argc, char **argv)
asm_test();
builtin_test();
weak_test();
+ global_data_test();
+ cmp_comparison_test();
+ math_cmp_test();
+ callsave_test();
return 0;
}
@@ -1122,25 +1137,30 @@ struct structa1 struct_assign_test2(struct structa1 s1, int t)
void struct_assign_test(void)
{
- struct structa1 lsta1, lsta2;
+ struct S {
+ struct structa1 lsta1, lsta2;
+ int i;
+ } s, *ps;
+ ps = &s;
+ ps->i = 4;
#if 0
printf("struct_assign_test:\n");
- lsta1.f1 = 1;
- lsta1.f2 = 2;
- printf("%d %d\n", lsta1.f1, lsta1.f2);
- lsta2 = lsta1;
- printf("%d %d\n", lsta2.f1, lsta2.f2);
+ s.lsta1.f1 = 1;
+ s.lsta1.f2 = 2;
+ printf("%d %d\n", s.lsta1.f1, s.lsta1.f2);
+ s.lsta2 = s.lsta1;
+ printf("%d %d\n", s.lsta2.f1, s.lsta2.f2);
#else
- lsta2.f1 = 1;
- lsta2.f2 = 2;
+ s.lsta2.f1 = 1;
+ s.lsta2.f2 = 2;
#endif
- struct_assign_test1(lsta2, 3, 4.5);
+ struct_assign_test1(ps->lsta2, 3, 4.5);
- printf("before call: %d %d\n", lsta2.f1, lsta2.f2);
- lsta2 = struct_assign_test2(lsta2, 4);
- printf("after call: %d %d\n", lsta2.f1, lsta2.f2);
+ printf("before call: %d %d\n", s.lsta2.f1, s.lsta2.f2);
+ ps->lsta2 = struct_assign_test2(ps->lsta2, ps->i);
+ printf("after call: %d %d\n", ps->lsta2.f1, ps->lsta2.f2);
static struct {
void (*elem)();
@@ -1461,6 +1481,8 @@ void c99_bool_test(void)
void bitfield_test(void)
{
int a;
+ short sa;
+ unsigned char ca;
struct sbf1 {
int f1 : 3;
int : 2;
@@ -1482,6 +1504,9 @@ void bitfield_test(void)
st1.f5++;
printf("%d %d %d %d %d\n",
st1.f1, st1.f2, st1.f3, st1.f4, st1.f5);
+ sa = st1.f5;
+ ca = st1.f5;
+ printf("%d %d\n", sa, ca);
st1.f1 = 7;
if (st1.f1 == -1)
@@ -2136,6 +2161,8 @@ void c99_vla_test(int size1, int size2)
#endif
}
+typedef __SIZE_TYPE__ uintptr_t;
+
void sizeof_test(void)
{
int a;
@@ -2156,6 +2183,20 @@ void sizeof_test(void)
ptr = NULL;
printf("sizeof(**ptr) = %d\n", sizeof (**ptr));
+ /* The type of sizeof should be as large as a pointer, actually
+ it should be size_t. */
+ printf("sizeof(sizeof(int) = %d\n", sizeof(sizeof(int)));
+ uintptr_t t = 1;
+ uintptr_t t2;
+ /* Effectively <<32, but defined also on 32bit machines. */
+ t <<= 16;
+ t <<= 16;
+ t++;
+ /* This checks that sizeof really can be used to manipulate
+ uintptr_t objects, without truncation. */
+ t2 = t & -sizeof(uintptr_t);
+ printf ("%lu %lu\n", t, t2);
+
/* some alignof tests */
printf("__alignof__(int) = %d\n", __alignof__(int));
printf("__alignof__(unsigned int) = %d\n", __alignof__(unsigned int));
@@ -2486,3 +2527,154 @@ void const_warn_test(void)
{
const_func(1);
}
+
+struct condstruct {
+ int i;
+};
+
+int getme (struct condstruct *s, int i)
+{
+ int i1 = (i == 0 ? 0 : s)->i;
+ int i2 = (i == 0 ? s : 0)->i;
+ int i3 = (i == 0 ? (void*)0 : s)->i;
+ int i4 = (i == 0 ? s : (void*)0)->i;
+ return i1 + i2 + i3 + i4;
+}
+
+struct global_data
+{
+ int a[40];
+ int *b[40];
+};
+
+struct global_data global_data;
+
+int global_data_getstuff (int *, int);
+
+void global_data_callit (int i)
+{
+ *global_data.b[i] = global_data_getstuff (global_data.b[i], 1);
+}
+
+int global_data_getstuff (int *p, int i)
+{
+ return *p + i;
+}
+
+void global_data_test (void)
+{
+ global_data.a[0] = 42;
+ global_data.b[0] = &global_data.a[0];
+ global_data_callit (0);
+ printf ("%d\n", global_data.a[0]);
+}
+
+struct cmpcmpS
+{
+ unsigned char fill : 3;
+ unsigned char b1 : 1;
+ unsigned char b2 : 1;
+ unsigned char fill2 : 3;
+};
+
+int glob1, glob2, glob3;
+
+void compare_comparisons (struct cmpcmpS *s)
+{
+ if (s->b1 != (glob1 == glob2)
+ || (s->b2 != (glob1 == glob3)))
+ printf ("comparing comparisons broken\n");
+}
+
+void cmp_comparison_test(void)
+{
+ struct cmpcmpS s;
+ s.b1 = 1;
+ glob1 = 42; glob2 = 42;
+ s.b2 = 0;
+ glob3 = 43;
+ compare_comparisons (&s);
+ return 0;
+}
+
+int fcompare (double a, double b, int code)
+{
+ switch (code) {
+ case 0: return a == b;
+ case 1: return a != b;
+ case 2: return a < b;
+ case 3: return a >= b;
+ case 4: return a > b;
+ case 5: return a <= b;
+ }
+}
+
+void math_cmp_test(void)
+{
+ double nan = 0.0/0.0;
+ double one = 1.0;
+ double two = 2.0;
+ int comp = 0;
+#define bug(a,b,op,iop,part) printf("Test broken: %s %s %s %s %d\n", #a, #b, #op, #iop, part)
+
+ /* This asserts that "a op b" is _not_ true, but "a iop b" is true.
+ And it does this in various ways so that all code generation paths
+ are checked (generating inverted tests, or non-inverted tests, or
+ producing a 0/1 value without jumps (that's done in the fcompare
+ function). */
+#define FCMP(a,b,op,iop,code) \
+ if (fcompare (a,b,code)) \
+ bug (a,b,op,iop,1); \
+ if (a op b) \
+ bug (a,b,op,iop,2); \
+ if (a iop b) \
+ ; \
+ else \
+ bug (a,b,op,iop,3); \
+ if ((a op b) || comp) \
+ bug (a,b,op,iop,4); \
+ if ((a iop b) || comp) \
+ ; \
+ else \
+ bug (a,b,op,iop,5);
+
+ /* Equality tests. */
+ FCMP(nan, nan, ==, !=, 0);
+ FCMP(one, two, ==, !=, 0);
+ FCMP(one, one, !=, ==, 1);
+ /* Non-equality is a bit special. */
+ if (!fcompare (nan, nan, 1))
+ bug (nan, nan, !=, ==, 6);
+
+ /* Relational tests on numbers. */
+ FCMP(two, one, <, >=, 2);
+ FCMP(one, two, >=, <, 3);
+ FCMP(one, two, >, <=, 4);
+ FCMP(two, one, <=, >, 5);
+
+ /* Relational tests on NaNs. Note that the inverse op here is
+ always !=, there's no operator in C that is equivalent to !(a < b),
+ when NaNs are involved, same for the other relational ops. */
+ FCMP(nan, nan, <, !=, 2);
+ FCMP(nan, nan, >=, !=, 3);
+ FCMP(nan, nan, >, !=, 4);
+ FCMP(nan, nan, <=, !=, 5);
+}
+
+double get100 () { return 100.0; }
+
+void callsave_test(void)
+{
+ int i, s; double *d; double t;
+ s = sizeof (double);
+ printf ("callsavetest: %d\n", s);
+ d = alloca (sizeof(double));
+ d[0] = 10.0;
+ /* x86-64 had a bug were the next call to get100 would evict
+ the lvalue &d[0] as VT_LLOCAL, and the reload would be done
+ in int type, not pointer type. When alloca returns a pointer
+ with the high 32 bit set (which is likely on x86-64) the access
+ generates a segfault. */
+ i = d[0] > get100 ();
+ printf ("%d\n", i);
+}
diff --git a/win32/build-tcc.bat b/win32/build-tcc.bat
index 21bf3a8..9e7f8eb 100644
--- a/win32/build-tcc.bat
+++ b/win32/build-tcc.bat
@@ -27,10 +27,7 @@ echo>..\config.h #define TCC_VERSION "0.9.25"
:libtcc
if not exist libtcc\nul mkdir libtcc
copy ..\libtcc.h libtcc\libtcc.h
-%CC% %target% -DONE_SOURCE ../libtcc.c -c -o libtcc.o
-%AR% rcs libtcc/libtcc.a libtcc.o
-:libtcc.dll
-%CC% %target% -shared -DLIBTCC_AS_DLL -DONE_SOURCE ../libtcc.c -o libtcc.dll
+%CC% %target% -shared -DLIBTCC_AS_DLL -DONE_SOURCE ../libtcc.c -o libtcc.dll -Wl,-out-implib,libtcc/libtcc.a
tiny_impdef libtcc.dll -o lib/libtcc.def
:tcc
diff --git a/win32/tcc-win32.txt b/win32/tcc-win32.txt
index 563967f..64ff885 100644
--- a/win32/tcc-win32.txt
+++ b/win32/tcc-win32.txt
@@ -64,7 +64,7 @@
For the 'libtcc_test' example type
- tcc examples/libtcc_test.c -I. libtcc.dll
+ tcc examples/libtcc_test.c -I libtcc -ltcc
Import Definition Files:
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 4d2521d..1fa8dd5 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -36,6 +36,8 @@
#define RC_RDX 0x0010
#define RC_R8 0x0100
#define RC_R9 0x0200
+#define RC_R10 0x0400
+#define RC_R11 0x0800
#define RC_XMM0 0x0020
#define RC_ST0 0x0040 /* only for long double */
#define RC_IRET RC_RAX /* function return: integer register */
@@ -104,19 +106,19 @@ ST_FUNC void gen_le64(int64_t c);
#include "tcc.h"
#include <assert.h>
-ST_DATA const int reg_classes[NB_REGS] = {
+ST_DATA const int reg_classes[] = {
/* eax */ RC_INT | RC_RAX,
/* ecx */ RC_INT | RC_RCX,
/* edx */ RC_INT | RC_RDX,
/* xmm0 */ RC_FLOAT | RC_XMM0,
/* st0 */ RC_ST0,
-#if NB_REGS == 10
0,
0,
0,
RC_INT | RC_R8,
RC_INT | RC_R9,
-#endif
+ RC_INT | RC_R10,
+ RC_INT | RC_R11
};
static unsigned long func_sub_sp_offset;
@@ -367,8 +369,10 @@ void load(int r, SValue *sv)
v1.type.t = VT_PTR;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.ul = fc;
- load(r, &v1);
fr = r;
+ if (!(reg_classes[fr] & RC_INT))
+ fr = get_reg(RC_INT);
+ load(fr, &v1);
}
ll = 0;
if ((ft & VT_BTYPE) == VT_FLOAT) {
@@ -410,7 +414,7 @@ void load(int r, SValue *sv)
} else {
orex(1,0,r,0x8b);
o(0x05 + REG_VALUE(r) * 8); /* mov xx(%rip), r */
- gen_gotpcrel(fr, sv->sym, fc);
+ gen_gotpcrel(r, sv->sym, fc);
}
#endif
} else if (is64_type(ft)) {
@@ -425,7 +429,18 @@ void load(int r, SValue *sv)
gen_modrm(r, VT_LOCAL, sv->sym, fc);
} else if (v == VT_CMP) {
orex(0,r,0,0);
- oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */
+ if ((fc & ~0x100) != TOK_NE)
+ oad(0xb8 + REG_VALUE(r), 0); /* mov $0, r */
+ else
+ oad(0xb8 + REG_VALUE(r), 1); /* mov $1, r */
+ if (fc & 0x100)
+ {
+ /* This was a float compare. If the parity bit is
+ set the result was unordered, meaning false for everything
+ except TOK_NE, and true for TOK_NE. */
+ fc &= ~0x100;
+ o(0x037a + (REX_BASE(r) << 8));
+ }
orex(0,r,0, 0x0f); /* setxx %br */
o(fc);
o(0xc0 + REG_VALUE(r));
@@ -816,7 +831,6 @@ static const uint8_t arg_regs[REGN] = {
void gfunc_call(int nb_args)
{
int size, align, r, args_size, i;
- SValue *orig_vtop;
int nb_reg_args = 0;
int nb_sse_args = 0;
int sse_reg, gen_reg;
@@ -841,7 +855,6 @@ void gfunc_call(int nb_args)
/* for struct arguments, we need to call memcpy and the function
call breaks register passing arguments we are preparing.
So, we process arguments which will be passed by stack first. */
- orig_vtop = vtop;
gen_reg = nb_reg_args;
sse_reg = nb_sse_args;
@@ -857,6 +870,14 @@ void gfunc_call(int nb_args)
}
for(i = 0; i < nb_args; i++) {
+ /* Swap argument to top, it will possibly be changed here,
+ and might use more temps. All arguments must remain on the
+ stack, so that get_reg can correctly evict some of them onto
+ stack. We could use also use a vrott(nb_args) at the end
+ of this loop, but this seems faster. */
+ SValue tmp = vtop[0];
+ vtop[0] = vtop[-i];
+ vtop[-i] = tmp;
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
size = type_size(&vtop->type, &align);
/* align to stack align size */
@@ -868,18 +889,9 @@ void gfunc_call(int nb_args)
r = get_reg(RC_INT);
orex(1, r, 0, 0x89); /* mov %rsp, r */
o(0xe0 + REG_VALUE(r));
- {
- /* following code breaks vtop[1], vtop[2], and vtop[3] */
- SValue tmp1 = vtop[1];
- SValue tmp2 = vtop[2];
- SValue tmp3 = vtop[3];
- vset(&vtop->type, r | VT_LVAL, 0);
- vswap();
- vstore();
- vtop[1] = tmp1;
- vtop[2] = tmp2;
- vtop[3] = tmp3;
- }
+ vset(&vtop->type, r | VT_LVAL, 0);
+ vswap();
+ vstore();
args_size += size;
} else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
gv(RC_ST0);
@@ -909,10 +921,14 @@ void gfunc_call(int nb_args)
args_size += 8;
}
}
- vtop--;
+
+ /* And swap the argument back to it's original position. */
+ tmp = vtop[0];
+ vtop[0] = vtop[-i];
+ vtop[-i] = tmp;
}
- vtop = orig_vtop;
+ /* XXX This should be superfluous. */
save_regs(0); /* save used temporary registers */
/* then, we prepare register passing arguments.
@@ -949,6 +965,12 @@ void gfunc_call(int nb_args)
vtop--;
}
+ /* We shouldn't have many operands on the stack anymore, but the
+ call address itself is still there, and it might be in %eax
+ (or edx/ecx) currently, which the below writes would clobber.
+ So evict all remaining operands here. */
+ save_regs(0);
+
/* Copy R10 and R11 into RDX and RCX, respectively */
if (nb_reg_args > 2) {
o(0xd2894c); /* mov %r10, %rdx */
@@ -1150,6 +1172,24 @@ int gtst(int inv, int t)
v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
/* fast case : can jump directly since flags are set */
+ if (vtop->c.i & 0x100)
+ {
+ /* This was a float compare. If the parity flag is set
+ the result was unordered. For anything except != this
+ means false and we don't jump (anding both conditions).
+ For != this means true (oring both).
+ Take care about inverting the test. We need to jump
+ to our target if the result was unordered and test wasn't NE,
+ otherwise if unordered we don't want to jump. */
+ vtop->c.i &= ~0x100;
+ if (!inv == (vtop->c.i != TOK_NE))
+ o(0x067a); /* jp +6 */
+ else
+ {
+ g(0x0f);
+ t = psym(0x8a, t); /* jp t */
+ }
+ }
g(0x0f);
t = psym((vtop->c.i - 16) ^ inv, t);
} else if (v == VT_JMP || v == VT_JMPI) {
@@ -1420,7 +1460,7 @@ void gen_opf(int op)
if ((r & VT_VALMASK) == VT_LLOCAL) {
SValue v1;
r = get_reg(RC_INT);
- v1.type.t = VT_INT;
+ v1.type.t = VT_PTR;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.ul = fc;
load(r, &v1);
@@ -1458,7 +1498,7 @@ void gen_opf(int op)
vtop--;
vtop->r = VT_CMP;
- vtop->c.i = op;
+ vtop->c.i = op | 0x100;
} else {
/* no memory reference possible for long double operations */
if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
@@ -1491,7 +1531,7 @@ void gen_opf(int op)
if ((r & VT_VALMASK) == VT_LLOCAL) {
SValue v1;
r = get_reg(RC_INT);
- v1.type.t = VT_INT;
+ v1.type.t = VT_PTR;
v1.r = VT_LOCAL | VT_LVAL;
v1.c.ul = fc;
load(r, &v1);