mirror of
https://github.com/frida/tinycc
synced 2024-12-25 14:36:49 +03:00
Tests in abitest.c now work on Win32.
I expect that Linux-x86 is probably fine. All other architectures except ARM are definitely broken since I haven't yet implemented gfunc_sret for these, although replicating the current behaviour should be straightforward.
This commit is contained in:
parent
ce5e12c2f9
commit
2bbfaf436f
18
Makefile
18
Makefile
@ -45,7 +45,13 @@ endif
|
||||
|
||||
# make libtcc as static or dynamic library?
|
||||
ifdef DISABLE_STATIC
|
||||
ifndef CONFIG_WIN32
|
||||
LIBTCC=libtcc.so.1.0
|
||||
else
|
||||
LIBTCC=libtcc.dll
|
||||
LIBTCC_DLL=yes
|
||||
LIBTCC_EXTRA=libtcc.def libtcc.a
|
||||
endif
|
||||
LINK_LIBTCC=-Wl,-rpath,"$(libdir)"
|
||||
ifdef DISABLE_RPATH
|
||||
LINK_LIBTCC=
|
||||
@ -126,7 +132,7 @@ ifdef CONFIG_USE_LIBGCC
|
||||
LIBTCC1=
|
||||
endif
|
||||
|
||||
TCCLIBS = $(LIBTCC1) $(LIBTCC)
|
||||
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCC_EXTRA)
|
||||
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
|
||||
|
||||
ifdef CONFIG_CROSS
|
||||
@ -185,14 +191,21 @@ endif
|
||||
$(LIBTCC_OBJ) tcc.o : %.o : %.c $(LIBTCC_INC)
|
||||
$(CC) -o $@ -c $< $(NATIVE_DEFINES) $(CPPFLAGS) $(CFLAGS)
|
||||
|
||||
ifndef LIBTCC_DLL
|
||||
libtcc.a: $(LIBTCC_OBJ)
|
||||
$(AR) rcs $@ $^
|
||||
endif
|
||||
|
||||
libtcc.so.1.0: $(LIBTCC_OBJ)
|
||||
$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS)
|
||||
|
||||
libtcc.so.1.0: CFLAGS+=-fPIC
|
||||
|
||||
ifdef LIBTCC_DLL
|
||||
libtcc.dll libtcc.def libtcc.a: $(LIBTCC_OBJ)
|
||||
$(CC) -shared $^ -o $@ $(LDFLAGS) -Wl,--output-def,libtcc.def,--out-implib,libtcc.a
|
||||
endif
|
||||
|
||||
# windows utilities
|
||||
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
|
||||
$(CC) -o $@ $< $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
@ -286,7 +299,8 @@ install: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
||||
cp -r $(top_srcdir)/win32/examples/. "$(tccdir)/examples"
|
||||
$(INSTALL) -m644 $(addprefix $(top_srcdir)/include/,$(TCC_INCLUDES)) "$(tccdir)/include"
|
||||
$(INSTALL) -m644 tcc-doc.html $(top_srcdir)/win32/tcc-win32.txt "$(tccdir)/doc"
|
||||
$(INSTALL) -m644 $(LIBTCC) $(top_srcdir)/libtcc.h "$(tccdir)/libtcc"
|
||||
$(INSTALL) -m644 $(top_srcdir)/libtcc.h $(LIBTCC_EXTRA) "$(tccdir)/libtcc"
|
||||
$(INSTALL) -m644 $(LIBTCC) $(tccdir)
|
||||
ifdef CONFIG_CROSS
|
||||
mkdir -p "$(tccdir)/lib/32"
|
||||
mkdir -p "$(tccdir)/lib/64"
|
||||
|
13
arm-gen.c
13
arm-gen.c
@ -800,6 +800,19 @@ int assign_fpreg(struct avail_regs *avregs, int align, int size)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return 1 if this function returns via an sret pointer, 0 otherwise */
|
||||
ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align) {
|
||||
size = type_size(vt, &align);
|
||||
if (size > 4) {
|
||||
return 1;
|
||||
} else {
|
||||
*align = 4;
|
||||
ret->ref = NULL;
|
||||
ret->t = VT_INT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
35
i386-gen.c
35
i386-gen.c
@ -364,6 +364,28 @@ static void gcall_or_jmp(int is_jmp)
|
||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
|
||||
|
||||
/* Return 1 if this function returns via an sret pointer, 0 otherwise */
|
||||
ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *ret_align) {
|
||||
*ret_align = 1; // Never have to re-align return values for x86
|
||||
#ifdef TCC_TARGET_PE
|
||||
int size, align;
|
||||
size = type_size(vt, &align);
|
||||
if (size > 8) {
|
||||
return 1;
|
||||
} else if (size > 4) {
|
||||
ret->ref = NULL;
|
||||
ret->t = VT_LLONG;
|
||||
return 0;
|
||||
} else {
|
||||
ret->ref = NULL;
|
||||
ret->t = VT_INT;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
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. */
|
||||
@ -444,10 +466,6 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
}
|
||||
gcall_or_jmp(0);
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
if ((func_sym->type.t & VT_BTYPE) == VT_STRUCT)
|
||||
args_size -= 4;
|
||||
#endif
|
||||
if (args_size && func_call != FUNC_STDCALL)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
@ -491,7 +509,12 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
/* if the function returns a structure, then add an
|
||||
implicit pointer parameter */
|
||||
func_vt = sym->type;
|
||||
#ifdef TCC_TARGET_PE
|
||||
size = type_size(&func_vt,&align);
|
||||
if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) {
|
||||
#else
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
#endif
|
||||
/* XXX: fastcall case ? */
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
@ -526,10 +549,6 @@ ST_FUNC void gfunc_prolog(CType *func_type)
|
||||
/* pascal type call ? */
|
||||
if (func_call == FUNC_STDCALL)
|
||||
func_ret_sub = addr - 8;
|
||||
#ifdef TCC_TARGET_PE
|
||||
else if (func_vc)
|
||||
func_ret_sub = 4;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* leave some room for bound checking code */
|
||||
|
1
tcc.h
1
tcc.h
@ -1267,6 +1267,7 @@ ST_FUNC void gsym_addr(int t, int a);
|
||||
ST_FUNC void gsym(int t);
|
||||
ST_FUNC void load(int r, SValue *sv);
|
||||
ST_FUNC void store(int r, SValue *v);
|
||||
ST_FUNC int gfunc_sret(CType *vt, CType *ret, int *align);
|
||||
ST_FUNC void gfunc_call(int nb_args);
|
||||
ST_FUNC void gfunc_prolog(CType *func_type);
|
||||
ST_FUNC void gfunc_epilog(void);
|
||||
|
95
tccgen.c
95
tccgen.c
@ -3850,7 +3850,7 @@ ST_FUNC void unary(void)
|
||||
} else if (tok == '(') {
|
||||
SValue ret;
|
||||
Sym *sa;
|
||||
int nb_args;
|
||||
int nb_args, sret;
|
||||
|
||||
/* function call */
|
||||
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
||||
@ -3874,18 +3874,26 @@ ST_FUNC void unary(void)
|
||||
ret.r2 = VT_CONST;
|
||||
/* compute first implicit argument if a structure is returned */
|
||||
if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
/* get some space for the returned structure */
|
||||
size = type_size(&s->type, &align);
|
||||
loc = (loc - size) & -align;
|
||||
ret.type = s->type;
|
||||
ret.r = VT_LOCAL | VT_LVAL;
|
||||
/* pass it as 'int' to avoid structure arg passing
|
||||
problems */
|
||||
vseti(VT_LOCAL, loc);
|
||||
ret.c = vtop->c;
|
||||
nb_args++;
|
||||
int ret_align;
|
||||
sret = gfunc_sret(&s->type, &ret.type, &ret_align);
|
||||
if (sret) {
|
||||
/* get some space for the returned structure */
|
||||
size = type_size(&s->type, &align);
|
||||
loc = (loc - size) & -align;
|
||||
ret.type = s->type;
|
||||
ret.r = VT_LOCAL | VT_LVAL;
|
||||
/* pass it as 'int' to avoid structure arg passing
|
||||
problems */
|
||||
vseti(VT_LOCAL, loc);
|
||||
ret.c = vtop->c;
|
||||
nb_args++;
|
||||
}
|
||||
} else {
|
||||
ret.type = s->type;
|
||||
sret = 0;
|
||||
ret.type = s->type;
|
||||
}
|
||||
|
||||
if (!sret) {
|
||||
/* return in register */
|
||||
if (is_float(ret.type.t)) {
|
||||
ret.r = reg_fret(ret.type.t);
|
||||
@ -3919,6 +3927,17 @@ ST_FUNC void unary(void)
|
||||
/* return value */
|
||||
vsetc(&ret.type, ret.r, &ret.c);
|
||||
vtop->r2 = ret.r2;
|
||||
/* handle packed struct return */
|
||||
if (((s->type.t & VT_BTYPE) == VT_STRUCT) && !sret) {
|
||||
size = type_size(&s->type, &align);
|
||||
loc = (loc - size) & -align;
|
||||
int addr = loc;
|
||||
vset(&ret.type, VT_LOCAL | VT_LVAL, addr);
|
||||
vswap();
|
||||
vstore();
|
||||
vtop--;
|
||||
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@ -4466,40 +4485,38 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
gexpr();
|
||||
gen_assign_cast(&func_vt);
|
||||
if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
CType type;
|
||||
/* if returning structure, must copy it to implicit
|
||||
first pointer arg location */
|
||||
#ifdef TCC_ARM_EABI
|
||||
int align, size;
|
||||
size = type_size(&func_vt,&align);
|
||||
if(size <= 4)
|
||||
{
|
||||
if((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & 3))
|
||||
&& (align & 3))
|
||||
{
|
||||
int addr;
|
||||
loc = (loc - size) & -4;
|
||||
CType type, ret_type;
|
||||
int ret_align;
|
||||
if (gfunc_sret(&func_vt, &ret_type, &ret_align)) {
|
||||
/* if returning structure, must copy it to implicit
|
||||
first pointer arg location */
|
||||
type = func_vt;
|
||||
mk_pointer(&type);
|
||||
vset(&type, VT_LOCAL | VT_LVAL, func_vc);
|
||||
indir();
|
||||
vswap();
|
||||
/* copy structure value to pointer */
|
||||
vstore();
|
||||
} else {
|
||||
/* returning structure packed into registers */
|
||||
int size, addr, align;
|
||||
size = type_size(&func_vt,&align);
|
||||
if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
|
||||
&& (align & (ret_align-1))) {
|
||||
loc = (loc - size) & -align;
|
||||
addr = loc;
|
||||
type = func_vt;
|
||||
vset(&type, VT_LOCAL | VT_LVAL, addr);
|
||||
vswap();
|
||||
vstore();
|
||||
vset(&int_type, VT_LOCAL | VT_LVAL, addr);
|
||||
vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
|
||||
}
|
||||
vtop->type = int_type;
|
||||
gv(RC_IRET);
|
||||
} else {
|
||||
#endif
|
||||
type = func_vt;
|
||||
mk_pointer(&type);
|
||||
vset(&type, VT_LOCAL | VT_LVAL, func_vc);
|
||||
indir();
|
||||
vswap();
|
||||
/* copy structure value to pointer */
|
||||
vstore();
|
||||
#ifdef TCC_ARM_EABI
|
||||
vtop->type = ret_type;
|
||||
if (is_float(ret_type.t))
|
||||
gv(rc_fret(ret_type.t));
|
||||
else
|
||||
gv(RC_IRET);
|
||||
}
|
||||
#endif
|
||||
} else if (is_float(func_vt.t)) {
|
||||
gv(rc_fret(func_vt.t));
|
||||
} else {
|
||||
|
@ -13,7 +13,7 @@ TESTS = \
|
||||
hello-run \
|
||||
libtest \
|
||||
test3 \
|
||||
abitest-exe \
|
||||
abitest \
|
||||
moretests
|
||||
|
||||
# test4 -- problem with -static
|
||||
@ -180,12 +180,16 @@ asmtest: asmtest.ref
|
||||
|
||||
# Check that code generated by libtcc is binary compatible with
|
||||
# that generated by CC
|
||||
abitest$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir) -g -O0
|
||||
abitest-cc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
|
||||
$(CC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
|
||||
|
||||
abitest-exe: abitest$(EXESUF)
|
||||
abitest-tcc$(EXESUF): abitest.c $(top_builddir)/$(LIBTCC)
|
||||
$(TCC) -o $@ $^ $(CPPFLAGS) $(CFLAGS) $(NATIVE_DEFINES) $(LIBS) $(LINK_LIBTCC) $(LDFLAGS) -I$(top_srcdir)
|
||||
|
||||
abitest: abitest-cc$(EXESUF) abitest-tcc$(EXESUF)
|
||||
@echo ------------ $@ ------------
|
||||
abitest$(EXESUF) lib_path=..
|
||||
abitest-cc$(EXESUF) lib_path=..
|
||||
abitest-tcc$(EXESUF) lib_path=..
|
||||
|
||||
# targets for development
|
||||
%.bin: %.c tcc
|
||||
|
@ -37,24 +37,62 @@ static int run_callback(const char *src, callback_type callback) {
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct test1_type_s {int x, y;} test1_type;
|
||||
typedef test1_type (*test1_function_type) ();
|
||||
/*
|
||||
* reg_pack_test: return a small struct which should be packed into
|
||||
* registers (Win32) during return.
|
||||
*/
|
||||
typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
|
||||
typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
|
||||
|
||||
static int test1_callback(void *ptr) {
|
||||
test1_type r;
|
||||
r = ((test1_function_type)ptr)();
|
||||
return ((r.x == 10) && (r.y == 35)) ? 0 : -1;
|
||||
static int reg_pack_test_callback(void *ptr) {
|
||||
reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
|
||||
reg_pack_test_type a = {10, 35};
|
||||
reg_pack_test_type r;
|
||||
r = f(a);
|
||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int test1() {
|
||||
static int reg_pack_test(void) {
|
||||
const char *src =
|
||||
"typedef struct test1_type_s {int x, y;} test1_type;"
|
||||
"test1_type f() {\n"
|
||||
" test1_type r = {10, 35};\n"
|
||||
"typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
|
||||
"reg_pack_test_type f(reg_pack_test_type a) {\n"
|
||||
" reg_pack_test_type r = {a.x*5, a.y*3};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, test1_callback);
|
||||
return run_callback(src, reg_pack_test_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* sret_test: Create a struct large enough to be returned via sret
|
||||
* (hidden pointer as first function argument)
|
||||
*/
|
||||
typedef struct sret_test_type_s {
|
||||
long long a;
|
||||
long long b;
|
||||
} sret_test_type;
|
||||
|
||||
typedef sret_test_type (*sret_test_function_type) (sret_test_type);
|
||||
|
||||
static int sret_test_callback(void *ptr) {
|
||||
sret_test_function_type f = (sret_test_function_type)(ptr);
|
||||
sret_test_type x = {5436LL, 658277698LL};
|
||||
sret_test_type r = f(x);
|
||||
return ((r.a==x.a*35)&&(r.b==x.b*19)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int sret_test(void) {
|
||||
const char *src =
|
||||
"typedef struct sret_test_type_s {\n"
|
||||
" long long a;\n"
|
||||
" long long b;\n"
|
||||
"} sret_test_type;\n"
|
||||
"sret_test_type f(sret_test_type x) {\n"
|
||||
" sret_test_type r = {x.a*35, x.b*19};\n"
|
||||
" return r;\n"
|
||||
"}\n";
|
||||
|
||||
return run_callback(src, sret_test_callback);
|
||||
}
|
||||
|
||||
#define RUN_TEST(t) \
|
||||
@ -75,6 +113,7 @@ int main(int argc, char **argv) {
|
||||
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
|
||||
tccdir = argv[1] + 9;
|
||||
|
||||
RUN_TEST(test1);
|
||||
RUN_TEST(reg_pack_test);
|
||||
RUN_TEST(sret_test);
|
||||
return retval;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user