mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-29 06:10:09 +08:00
added libtcc - fixed spill reg bugs
This commit is contained in:
parent
1e14c90c7a
commit
8f64c13c40
253
tcc.c
253
tcc.c
@ -38,6 +38,8 @@
|
|||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "libtcc.h"
|
||||||
|
|
||||||
//#define DEBUG
|
//#define DEBUG
|
||||||
/* preprocessor debug */
|
/* preprocessor debug */
|
||||||
//#define PP_DEBUG
|
//#define PP_DEBUG
|
||||||
@ -245,6 +247,10 @@ int gnu_ext = 1;
|
|||||||
/* use Tiny C extensions */
|
/* use Tiny C extensions */
|
||||||
int tcc_ext = 1;
|
int tcc_ext = 1;
|
||||||
|
|
||||||
|
struct TCCState {
|
||||||
|
int dummy;
|
||||||
|
};
|
||||||
|
|
||||||
/* The current value can be: */
|
/* The current value can be: */
|
||||||
#define VT_VALMASK 0x00ff
|
#define VT_VALMASK 0x00ff
|
||||||
#define VT_CONST 0x00f0 /* constant in vc
|
#define VT_CONST 0x00f0 /* constant in vc
|
||||||
@ -491,7 +497,7 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init);
|
|||||||
int gv(int rc);
|
int gv(int rc);
|
||||||
void gv2(int rc1, int rc2);
|
void gv2(int rc1, int rc2);
|
||||||
void move_reg(int r, int s);
|
void move_reg(int r, int s);
|
||||||
void save_regs(void);
|
void save_regs(int n);
|
||||||
void save_reg(int r);
|
void save_reg(int r);
|
||||||
void vpop(void);
|
void vpop(void);
|
||||||
void vswap(void);
|
void vswap(void);
|
||||||
@ -2450,7 +2456,7 @@ void save_reg(int r)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* special long long case */
|
/* special long long case */
|
||||||
if ((p->t & VT_BTYPE) == VT_LLONG) {
|
if ((t & VT_BTYPE) == VT_LLONG) {
|
||||||
sv.c.ul += 4;
|
sv.c.ul += 4;
|
||||||
store(p->r2, &sv);
|
store(p->r2, &sv);
|
||||||
}
|
}
|
||||||
@ -2501,12 +2507,13 @@ int get_reg(int rc)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save_regs(void)
|
/* save registers up to (vtop - n) stack entry */
|
||||||
|
void save_regs(int n)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
SValue *p;
|
SValue *p, *p1;
|
||||||
|
p1 = vtop - n;
|
||||||
for(p=vstack;p<=vtop;p++) {
|
for(p = vstack;p <= p1; p++) {
|
||||||
r = p->r & VT_VALMASK;
|
r = p->r & VT_VALMASK;
|
||||||
if (r < VT_CONST) {
|
if (r < VT_CONST) {
|
||||||
save_reg(r);
|
save_reg(r);
|
||||||
@ -3810,7 +3817,7 @@ void vstore(void)
|
|||||||
gaddrof();
|
gaddrof();
|
||||||
gfunc_param(&gf);
|
gfunc_param(&gf);
|
||||||
|
|
||||||
save_regs();
|
save_regs(0);
|
||||||
vpushi((int)&memcpy);
|
vpushi((int)&memcpy);
|
||||||
gfunc_call(&gf);
|
gfunc_call(&gf);
|
||||||
/* leave source on stack */
|
/* leave source on stack */
|
||||||
@ -4660,7 +4667,7 @@ void unary(void)
|
|||||||
}
|
}
|
||||||
/* get return type */
|
/* get return type */
|
||||||
s = sym_find((unsigned)vtop->t >> VT_STRUCT_SHIFT);
|
s = sym_find((unsigned)vtop->t >> VT_STRUCT_SHIFT);
|
||||||
save_regs(); /* save used temporary registers */
|
save_regs(0); /* save used temporary registers */
|
||||||
gfunc_start(&gf, s->r);
|
gfunc_start(&gf, s->r);
|
||||||
next();
|
next();
|
||||||
sa = s->next; /* first parameter */
|
sa = s->next; /* first parameter */
|
||||||
@ -4879,6 +4886,8 @@ void expr_eq(void)
|
|||||||
eor();
|
eor();
|
||||||
if (tok == '?') {
|
if (tok == '?') {
|
||||||
next();
|
next();
|
||||||
|
save_regs(1); /* we need to save all registers here except
|
||||||
|
at the top because it is a branch point */
|
||||||
t = gtst(1, 0);
|
t = gtst(1, 0);
|
||||||
gexpr();
|
gexpr();
|
||||||
/* XXX: long long handling ? */
|
/* XXX: long long handling ? */
|
||||||
@ -5832,17 +5841,13 @@ void resolve_global_syms(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* compile a C file. Return non zero if errors. */
|
/* compile the C file opened in 'file'. Return non zero if errors. */
|
||||||
int tcc_compile_file(const char *filename1)
|
int tcc_compile(TCCState *s)
|
||||||
{
|
{
|
||||||
Sym *define_start;
|
Sym *define_start;
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
funcname = "";
|
funcname = "";
|
||||||
|
|
||||||
file = tcc_open(filename1);
|
|
||||||
if (!file)
|
|
||||||
error("file '%s' not found", filename1);
|
|
||||||
include_stack_ptr = include_stack;
|
include_stack_ptr = include_stack;
|
||||||
ifdef_stack_ptr = ifdef_stack;
|
ifdef_stack_ptr = ifdef_stack;
|
||||||
|
|
||||||
@ -5868,7 +5873,6 @@ int tcc_compile_file(const char *filename1)
|
|||||||
decl(VT_CONST);
|
decl(VT_CONST);
|
||||||
if (tok != -1)
|
if (tok != -1)
|
||||||
expect("declaration");
|
expect("declaration");
|
||||||
tcc_close(file);
|
|
||||||
|
|
||||||
/* end of translation unit info */
|
/* end of translation unit info */
|
||||||
if (do_debug) {
|
if (do_debug) {
|
||||||
@ -5886,23 +5890,48 @@ int tcc_compile_file(const char *filename1)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define a symbol. A value can also be provided with the '=' operator */
|
int tcc_compile_file(TCCState *s, const char *filename1)
|
||||||
/* XXX: currently only handles integers and string defines. should use
|
{
|
||||||
tcc parser, but would need a custom 'FILE *' */
|
int ret;
|
||||||
void define_symbol(const char *sym)
|
file = tcc_open(filename1);
|
||||||
|
if (!file)
|
||||||
|
error("file '%s' not found", filename1);
|
||||||
|
ret = tcc_compile(s);
|
||||||
|
tcc_close(file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcc_compile_string(TCCState *s, const char *str)
|
||||||
|
{
|
||||||
|
BufferedFile bf1, *bf = &bf1;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* init file structure */
|
||||||
|
bf->fd = -1;
|
||||||
|
bf->buf_ptr = (char *)str;
|
||||||
|
bf->buf_end = (char *)str + strlen(bf->buffer);
|
||||||
|
pstrcpy(bf->filename, sizeof(bf->filename), "<string>");
|
||||||
|
bf->line_num = 1;
|
||||||
|
file = bf;
|
||||||
|
|
||||||
|
ret = tcc_compile(s);
|
||||||
|
|
||||||
|
/* currently, no need to close */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* define a symbol. A value can also be provided with the '=' operator */
|
||||||
|
void tcc_define_symbol(TCCState *s, const char *sym, const char *value)
|
||||||
{
|
{
|
||||||
char *p;
|
|
||||||
BufferedFile bf1, *bf = &bf1;
|
BufferedFile bf1, *bf = &bf1;
|
||||||
|
|
||||||
pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
|
pstrcpy(bf->buffer, IO_BUF_SIZE, sym);
|
||||||
p = strchr(bf->buffer, '=');
|
pstrcat(bf->buffer, IO_BUF_SIZE, " ");
|
||||||
if (!p) {
|
/* default value */
|
||||||
/* default value */
|
if (!value)
|
||||||
pstrcat(bf->buffer, IO_BUF_SIZE, " 1");
|
value = "1";
|
||||||
} else {
|
pstrcat(bf->buffer, IO_BUF_SIZE, value);
|
||||||
*p = ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* init file structure */
|
/* init file structure */
|
||||||
bf->fd = -1;
|
bf->fd = -1;
|
||||||
bf->buf_ptr = bf->buffer;
|
bf->buf_ptr = bf->buffer;
|
||||||
@ -5921,7 +5950,7 @@ void define_symbol(const char *sym)
|
|||||||
file = NULL;
|
file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void undef_symbol(const char *sym)
|
void tcc_undefine_symbol(TCCState *s1, const char *sym)
|
||||||
{
|
{
|
||||||
TokenSym *ts;
|
TokenSym *ts;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
@ -5934,15 +5963,39 @@ void undef_symbol(const char *sym)
|
|||||||
|
|
||||||
/* open a dynamic library so that its symbol are available for
|
/* open a dynamic library so that its symbol are available for
|
||||||
compiled programs */
|
compiled programs */
|
||||||
void open_dll(char *libname)
|
/* XXX: open the lib only to actually run the program */
|
||||||
|
int tcc_add_dll(TCCState *s, const char *library_name)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
|
||||||
void *h;
|
void *h;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "lib%s.so", libname);
|
h = dlopen(library_name, RTLD_GLOBAL | RTLD_LAZY);
|
||||||
h = dlopen(buf, RTLD_GLOBAL | RTLD_LAZY);
|
|
||||||
if (!h)
|
if (!h)
|
||||||
error((char *)dlerror());
|
error((char *)dlerror());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the symbol already exists, then it is redefined */
|
||||||
|
int tcc_add_symbol(TCCState *s, const char *name, void *value)
|
||||||
|
{
|
||||||
|
TokenSym *ts;
|
||||||
|
Sym *ext_sym;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
ts = tok_alloc(name, 0);
|
||||||
|
v = ts->tok;
|
||||||
|
ext_sym = sym_find1(&extern_stack, v);
|
||||||
|
if (ext_sym) {
|
||||||
|
if (ext_sym->r & VT_FORWARD) {
|
||||||
|
greloc_patch(ext_sym, (long)value);
|
||||||
|
} else {
|
||||||
|
/* redefine symbol */
|
||||||
|
ext_sym->c = (long)value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ext_sym = sym_push1(&extern_stack, v, VT_INT, (long)value);
|
||||||
|
ext_sym->r = VT_CONST;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *resolve_sym(const char *sym)
|
static void *resolve_sym(const char *sym)
|
||||||
@ -6059,7 +6112,7 @@ static void put_stabd(int type, int other, int desc)
|
|||||||
/* XXX: generate startup code */
|
/* XXX: generate startup code */
|
||||||
/* XXX: better program header generation */
|
/* XXX: better program header generation */
|
||||||
/* XXX: handle realloc'ed sections (instead of mmaping them) */
|
/* XXX: handle realloc'ed sections (instead of mmaping them) */
|
||||||
void build_exe(char *filename)
|
int tcc_output_file(TCCState *s, const char *filename, int file_type)
|
||||||
{
|
{
|
||||||
Elf32_Ehdr ehdr;
|
Elf32_Ehdr ehdr;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
@ -6188,6 +6241,7 @@ void build_exe(char *filename)
|
|||||||
}
|
}
|
||||||
fwrite(shdr, 1, shnum * sizeof(Elf32_Shdr), f);
|
fwrite(shdr, 1, shnum * sizeof(Elf32_Shdr), f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print the position in the source file of PC value 'pc' by reading
|
/* print the position in the source file of PC value 'pc' by reading
|
||||||
@ -6337,11 +6391,13 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* launch the compiled program with the given arguments */
|
/* launch the compiled program with the given arguments */
|
||||||
int launch_exe(int argc, char **argv)
|
int tcc_run(TCCState *s1, int argc, char **argv)
|
||||||
{
|
{
|
||||||
Sym *s;
|
Sym *s;
|
||||||
int (*t)();
|
int (*t)();
|
||||||
|
|
||||||
|
resolve_extern_syms();
|
||||||
|
|
||||||
s = sym_find1(&extern_stack, TOK_MAIN);
|
s = sym_find1(&extern_stack, TOK_MAIN);
|
||||||
if (!s || (s->r & VT_FORWARD))
|
if (!s || (s->r & VT_FORWARD))
|
||||||
error("main() not defined");
|
error("main() not defined");
|
||||||
@ -6382,10 +6438,71 @@ int launch_exe(int argc, char **argv)
|
|||||||
return (*t)(argc, argv);
|
return (*t)(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TCCState *tcc_new(void)
|
||||||
|
{
|
||||||
|
char *p, *r;
|
||||||
|
TCCState *s;
|
||||||
|
|
||||||
|
s = malloc(sizeof(TCCState));
|
||||||
|
if (!s)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* default include paths */
|
||||||
|
nb_include_paths = 0;
|
||||||
|
tcc_add_include_path(s, "/usr/include");
|
||||||
|
tcc_add_include_path(s, "/usr/lib/tcc");
|
||||||
|
tcc_add_include_path(s, "/usr/local/lib/tcc");
|
||||||
|
|
||||||
|
/* add all tokens */
|
||||||
|
tok_ident = TOK_IDENT;
|
||||||
|
p = tcc_keywords;
|
||||||
|
while (*p) {
|
||||||
|
r = p;
|
||||||
|
while (*r++);
|
||||||
|
tok_alloc(p, r - p - 1);
|
||||||
|
p = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* standard defines */
|
||||||
|
tcc_define_symbol(s, "__STDC__", NULL);
|
||||||
|
#ifdef __i386__
|
||||||
|
tcc_define_symbol(s, "__i386__", NULL);
|
||||||
|
#endif
|
||||||
|
/* tiny C specific defines */
|
||||||
|
tcc_define_symbol(s, "__TINYC__", NULL);
|
||||||
|
|
||||||
|
/* create standard sections */
|
||||||
|
text_section = new_section(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
|
||||||
|
data_section = new_section(".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
||||||
|
/* XXX: should change type to SHT_NOBITS */
|
||||||
|
bss_section = new_section(".bss", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcc_delete(TCCState *s)
|
||||||
|
{
|
||||||
|
free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tcc_add_include_path(TCCState *s, const char *pathname)
|
||||||
|
{
|
||||||
|
char *pathname1;
|
||||||
|
|
||||||
|
if (nb_include_paths >= INCLUDE_PATHS_MAX)
|
||||||
|
return -1;
|
||||||
|
pathname1 = strdup(pathname);
|
||||||
|
if (!pathname1)
|
||||||
|
return -1;
|
||||||
|
include_paths[nb_include_paths++] = pathname1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(LIBTCC)
|
||||||
|
|
||||||
void help(void)
|
void help(void)
|
||||||
{
|
{
|
||||||
printf("tcc version 0.9.6 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
|
printf("tcc version 0.9.7 - Tiny C Compiler - Copyright (C) 2001, 2002 Fabrice Bellard\n"
|
||||||
"usage: tcc [-Idir] [-Dsym[=val]] [-Usym] [-llib] [-g] [-b]\n"
|
"usage: tcc [-Idir] [-Dsym[=val]] [-Usym] [-llib] [-g] [-b]\n"
|
||||||
" [-i infile] infile [infile_args...]\n"
|
" [-i infile] infile [infile_args...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -6403,37 +6520,11 @@ void help(void)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *p, *r, *outfile;
|
char *r, *outfile;
|
||||||
int optind;
|
int optind;
|
||||||
|
TCCState *s;
|
||||||
include_paths[0] = "/usr/include";
|
|
||||||
include_paths[1] = "/usr/lib/tcc";
|
|
||||||
include_paths[2] = "/usr/local/lib/tcc";
|
|
||||||
nb_include_paths = 3;
|
|
||||||
|
|
||||||
/* add all tokens */
|
|
||||||
tok_ident = TOK_IDENT;
|
|
||||||
p = tcc_keywords;
|
|
||||||
while (*p) {
|
|
||||||
r = p;
|
|
||||||
while (*r++);
|
|
||||||
tok_alloc(p, r - p - 1);
|
|
||||||
p = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* standard defines */
|
|
||||||
define_symbol("__STDC__");
|
|
||||||
#ifdef __i386__
|
|
||||||
define_symbol("__i386__");
|
|
||||||
#endif
|
|
||||||
/* tiny C specific defines */
|
|
||||||
define_symbol("__TINYC__");
|
|
||||||
|
|
||||||
/* create standard sections */
|
s = tcc_new();
|
||||||
text_section = new_section(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
|
|
||||||
data_section = new_section(".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
|
||||||
/* XXX: should change type to SHT_NOBITS */
|
|
||||||
bss_section = new_section(".bss", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
|
||||||
|
|
||||||
optind = 1;
|
optind = 1;
|
||||||
outfile = NULL;
|
outfile = NULL;
|
||||||
@ -6448,19 +6539,27 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
optind++;
|
optind++;
|
||||||
if (r[1] == 'I') {
|
if (r[1] == 'I') {
|
||||||
if (nb_include_paths >= INCLUDE_PATHS_MAX)
|
if (tcc_add_include_path(s, r + 2) < 0)
|
||||||
error("too many include paths");
|
error("too many include paths");
|
||||||
include_paths[nb_include_paths++] = r + 2;
|
|
||||||
} else if (r[1] == 'D') {
|
} else if (r[1] == 'D') {
|
||||||
define_symbol(r + 2);
|
char *sym, *value;
|
||||||
|
sym = r + 2;
|
||||||
|
value = strchr(sym, '=');
|
||||||
|
if (value) {
|
||||||
|
*value = '\0';
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
tcc_define_symbol(s, sym, value);
|
||||||
} else if (r[1] == 'U') {
|
} else if (r[1] == 'U') {
|
||||||
undef_symbol(r + 2);
|
tcc_undefine_symbol(s, r + 2);
|
||||||
} else if (r[1] == 'l') {
|
} else if (r[1] == 'l') {
|
||||||
open_dll(r + 2);
|
char buf[1024];
|
||||||
|
snprintf(buf, sizeof(buf), "lib%s.so", r + 2);
|
||||||
|
tcc_add_dll(s, buf);
|
||||||
} else if (r[1] == 'i') {
|
} else if (r[1] == 'i') {
|
||||||
if (optind >= argc)
|
if (optind >= argc)
|
||||||
goto show_help;
|
goto show_help;
|
||||||
tcc_compile_file(argv[optind++]);
|
tcc_compile_file(s, argv[optind++]);
|
||||||
} else if (!strcmp(r + 1, "bench")) {
|
} else if (!strcmp(r + 1, "bench")) {
|
||||||
do_bench = 1;
|
do_bench = 1;
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
@ -6468,7 +6567,7 @@ int main(int argc, char **argv)
|
|||||||
if (!do_bounds_check) {
|
if (!do_bounds_check) {
|
||||||
do_bounds_check = 1;
|
do_bounds_check = 1;
|
||||||
/* define symbol */
|
/* define symbol */
|
||||||
define_symbol("__BOUNDS_CHECKING_ON");
|
tcc_define_symbol(s, "__BOUNDS_CHECKING_ON", NULL);
|
||||||
/* create bounds sections */
|
/* create bounds sections */
|
||||||
bounds_section = new_section(".bounds",
|
bounds_section = new_section(".bounds",
|
||||||
SHT_PROGBITS, SHF_ALLOC);
|
SHT_PROGBITS, SHF_ALLOC);
|
||||||
@ -6512,19 +6611,19 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tcc_compile_file(argv[optind]);
|
tcc_compile_file(s, argv[optind]);
|
||||||
|
|
||||||
if (do_bench) {
|
if (do_bench) {
|
||||||
printf("total: %d idents, %d lines, %d bytes\n",
|
printf("total: %d idents, %d lines, %d bytes\n",
|
||||||
tok_ident - TOK_IDENT, total_lines, total_bytes);
|
tok_ident - TOK_IDENT, total_lines, total_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve_extern_syms();
|
|
||||||
|
|
||||||
if (outfile) {
|
if (outfile) {
|
||||||
build_exe(outfile);
|
tcc_output_file(s, outfile, TCC_FILE_EXE);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return launch_exe(argc - optind, argv + optind);
|
return tcc_run(s, argc - optind, argv + optind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user