mirror of
git://repo.or.cz/tinycc.git
synced 2026-07-10 21:38:47 +08:00
Compare commits
4 Commits
199e135142
...
80e7040d0c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80e7040d0c | ||
|
|
2662b7b43c | ||
|
|
deb7a3fc73 | ||
|
|
8845b6cd45 |
30
.github/workflows/build.yml
vendored
30
.github/workflows/build.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
test-x86_64-win32:
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 4
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc (x86_64-win32)
|
||||
@ -44,10 +44,22 @@ jobs:
|
||||
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-x86_64-gcc"
|
||||
echo ::endgroup::
|
||||
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: amd64
|
||||
- name: build with MSVC (x86_64-win32)
|
||||
shell: cmd
|
||||
run: |
|
||||
echo ::group:: run build-tcc.bat
|
||||
cd win32
|
||||
call build-tcc.bat -t 64 -c cl
|
||||
echo ::endgroup::
|
||||
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
|
||||
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
|
||||
|
||||
test-i386-win32:
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 4
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc (i386-win32)
|
||||
@ -59,7 +71,19 @@ jobs:
|
||||
set CHERE_INVOKING=yes
|
||||
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-i686-gcc"
|
||||
echo ::endgroup::
|
||||
C:\msys64\usr\bin\bash -l -c "./configure && make all && make test -k"
|
||||
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: x86
|
||||
- name: build with MSVC (i386-win32)
|
||||
shell: cmd
|
||||
run: |
|
||||
echo ::group:: run build-tcc.bat
|
||||
cd win32
|
||||
call build-tcc.bat -t 32 -c cl
|
||||
echo ::endgroup::
|
||||
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
|
||||
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
|
||||
|
||||
test-armv7-linux:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
@ -1493,8 +1493,7 @@ from_stack:
|
||||
addr = (n + nf + sn) * 4;
|
||||
sn += size;
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL,
|
||||
addr + 12);
|
||||
gfunc_set_param(sym, addr + 12, 0);
|
||||
}
|
||||
last_itod_magic=0;
|
||||
leaffunc = 1;
|
||||
|
||||
@ -1242,9 +1242,8 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
int off = (a[i] < 16 ? 160 + a[i] / 2 * 8 :
|
||||
a[i] < 32 ? 16 + (a[i] - 16) / 2 * 16 :
|
||||
224 + ((a[i] - 32) >> 1 << 1));
|
||||
sym_push(sym->v & ~SYM_FIELD, &sym->type,
|
||||
(a[i] & 1 ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
|
||||
off);
|
||||
|
||||
gfunc_set_param(sym, off, a[i] & 1);
|
||||
|
||||
if (a[i] < 16) {
|
||||
int align, size = type_size(&sym->type, &align);
|
||||
|
||||
@ -1968,7 +1968,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
/* define parameters */
|
||||
while ((sym = sym->next) != NULL) {
|
||||
type = &sym->type;
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
|
||||
gfunc_set_param(sym, addr, 0);
|
||||
size = type_size(type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
|
||||
|
||||
@ -417,6 +417,7 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
/* allocate the necessary size on stack */
|
||||
#ifdef TCC_TARGET_PE
|
||||
if (size >= 4096) {
|
||||
save_reg(TREG_EDX);
|
||||
r = get_reg(RC_EAX);
|
||||
oad(0x68, size); // push size
|
||||
/* cannot call normal 'alloca' with bound checking */
|
||||
@ -577,8 +578,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
param_addr = addr;
|
||||
addr += size;
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, param_addr);
|
||||
gfunc_set_param(sym, param_addr, 0);
|
||||
param_index++;
|
||||
}
|
||||
func_ret_sub = 0;
|
||||
|
||||
@ -17,13 +17,13 @@ _(__bound_alloca):
|
||||
mov %eax, %ecx
|
||||
test %eax,%eax
|
||||
jz p6
|
||||
add $15+1,%eax
|
||||
and $-16,%eax
|
||||
add $3 + 1,%eax
|
||||
and $-4,%eax
|
||||
|
||||
#ifdef _WIN32
|
||||
p4:
|
||||
cmp $4096,%eax
|
||||
jbe p5
|
||||
jb p5
|
||||
test %eax,-4096(%esp)
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
@ -33,7 +33,6 @@ p5:
|
||||
#endif
|
||||
|
||||
sub %eax,%esp
|
||||
and $-16,%esp
|
||||
mov %esp,%eax
|
||||
|
||||
push %edx
|
||||
@ -72,12 +71,11 @@ _(__bound_alloca_nr):
|
||||
#else
|
||||
pop %rdx
|
||||
mov %rdi,%rax
|
||||
and %eax,%eax
|
||||
jz p3
|
||||
mov %rax,%rsi # size, a second parm to the __bound_new_region
|
||||
|
||||
add $15 + 1,%rax # add one extra to separate regions
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rdi # pointer, a first parm to the __bound_new_region
|
||||
|
||||
@ -15,14 +15,14 @@ _(alloca):
|
||||
_(__alloca):
|
||||
pop %edx
|
||||
pop %eax
|
||||
add $15,%eax
|
||||
and $-16,%eax
|
||||
add $3,%eax
|
||||
and $-4,%eax
|
||||
jz p3
|
||||
|
||||
#ifdef _WIN32
|
||||
p1:
|
||||
cmp $4096,%eax
|
||||
jbe p2
|
||||
jb p2
|
||||
test %eax,-4096(%esp)
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
@ -30,7 +30,6 @@ p1:
|
||||
p2:
|
||||
#endif
|
||||
sub %eax,%esp
|
||||
and $-16,%esp
|
||||
mov %esp,%eax
|
||||
p3:
|
||||
push %edx
|
||||
@ -55,7 +54,7 @@ _(alloca):
|
||||
#ifdef _WIN32
|
||||
p1:
|
||||
cmp $4096,%rax
|
||||
jbe p2
|
||||
jb p2
|
||||
test %rax,-4096(%rsp)
|
||||
sub $4096,%rsp
|
||||
sub $4096,%rax
|
||||
|
||||
45
libtcc.c
45
libtcc.c
@ -804,7 +804,6 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
|
||||
s1->error_set_jmp_enabled = 1;
|
||||
|
||||
if (setjmp(s1->error_jmp_buf) == 0) {
|
||||
s1->nb_errors = 0;
|
||||
|
||||
if (fd == -1) {
|
||||
int len = strlen(str);
|
||||
@ -1816,8 +1815,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
||||
const TCCOption *popt;
|
||||
const char *optarg, *r;
|
||||
const char *run = NULL;
|
||||
int x;
|
||||
int tool = 0, arg_start = 0, not_empty = 0, optind = 1;
|
||||
int optind = 1, empty = 1, x;
|
||||
char **argv = *pargv;
|
||||
int argc = *pargc;
|
||||
|
||||
@ -1836,21 +1834,16 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
||||
continue;
|
||||
}
|
||||
optind++;
|
||||
if (tool) { /* ignore all except -v and @listfile */
|
||||
s->verbose += !strcmp(r, "-v");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r[0] != '-' || r[1] == '\0') { /* file or '-' (stdin) */
|
||||
args_parser_add_file(s, r, s->filetype);
|
||||
not_empty = 1;
|
||||
empty = 0;
|
||||
dorun:
|
||||
if (run) {
|
||||
/* tcc -run <file> <args...> */
|
||||
if (tcc_set_options(s, run))
|
||||
if (tcc_set_options(s, run) < 0)
|
||||
return -1;
|
||||
arg_start = optind - 1; /* argv[0] will be <file> */
|
||||
break;
|
||||
x = 0;
|
||||
goto extra_action;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -1923,14 +1916,16 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
||||
case TCC_OPTION_g:
|
||||
s->do_debug = 2;
|
||||
s->dwarf = CONFIG_DWARF_VERSION;
|
||||
g_redo:
|
||||
if (strstart("dwarf", &optarg)) {
|
||||
s->dwarf = (*optarg) ? (0 - atoi(optarg)) : DEFAULT_DWARF_VERSION;
|
||||
} else if (0 == strcmp("stabs", optarg)) {
|
||||
s->dwarf = 0;
|
||||
} else if (isnum(*optarg)) {
|
||||
x = *optarg - '0';
|
||||
x = *optarg++ - '0';
|
||||
/* -g0 = no info, -g1 = lines/functions only, -g2 = full info */
|
||||
s->do_debug = x > 2 ? 2 : x == 0 && s->do_backtrace ? 1 : x;
|
||||
goto g_redo;
|
||||
#ifdef TCC_TARGET_PE
|
||||
} else if (0 == strcmp(".pdb", optarg)) {
|
||||
s->dwarf = 5, s->do_debug |= 16;
|
||||
@ -2030,7 +2025,6 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
||||
}
|
||||
break;
|
||||
case TCC_OPTION_W:
|
||||
s->warn_none = 0;
|
||||
if (optarg[0] && set_flag(s, options_W, optarg) < 0)
|
||||
goto unsupported_option;
|
||||
break;
|
||||
@ -2141,29 +2135,24 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
||||
case TCC_OPTION_ar:
|
||||
x = OPT_AR;
|
||||
extra_action:
|
||||
arg_start = optind - 1;
|
||||
if (not_empty)
|
||||
if (NULL == argv[0]) /* from tcc_set_options() */
|
||||
return -1;
|
||||
if (!empty && x)
|
||||
return tcc_error_noabort("cannot parse %s here", r);
|
||||
tool = x;
|
||||
break;
|
||||
--optind;
|
||||
*pargc = argc - optind;
|
||||
*pargv = argv + optind;
|
||||
return x;
|
||||
default:
|
||||
unsupported_option:
|
||||
tcc_warning_c(warn_unsupported)("unsupported option '%s'", r);
|
||||
break;
|
||||
}
|
||||
not_empty = 1;
|
||||
empty = 0;
|
||||
}
|
||||
|
||||
if (s->link_optind < s->link_argc)
|
||||
return tcc_error_noabort("argument to '-Wl,%s' is missing", s->link_argv[s->link_optind]);
|
||||
if (NULL == argv[0]) /* from tcc_set_options() */
|
||||
return 0;
|
||||
if (arg_start) {
|
||||
*pargc = argc - arg_start;
|
||||
*pargv = argv + arg_start;
|
||||
return tool;
|
||||
}
|
||||
if (not_empty)
|
||||
if (!empty)
|
||||
return 0;
|
||||
if (s->verbose == 2)
|
||||
return OPT_PRINT_DIRS;
|
||||
|
||||
@ -833,9 +833,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
|
||||
}
|
||||
}
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, &sym->type,
|
||||
(byref ? VT_LLOCAL : VT_LOCAL) | VT_LVAL,
|
||||
param_addr);
|
||||
gfunc_set_param(sym, param_addr, byref);
|
||||
}
|
||||
func_va_list_ofs = addr;
|
||||
num_va_regs = 0;
|
||||
|
||||
43
tcc.c
43
tcc.c
@ -283,51 +283,51 @@ static unsigned getclock_ms(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc0, char **argv0)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
TCCState *s, *s1;
|
||||
int ret, opt, n = 0, t = 0, done;
|
||||
unsigned start_time = 0, end_time = 0;
|
||||
const char *first_file;
|
||||
int argc; char **argv;
|
||||
int argc0 = argc;
|
||||
char **argv0 = argv;
|
||||
FILE *ppfp = stdout;
|
||||
|
||||
redo:
|
||||
argc = argc0, argv = argv0;
|
||||
s = s1 = tcc_new();
|
||||
opt = tcc_parse_args(s, &argc, &argv);
|
||||
if (opt < 0)
|
||||
return 1;
|
||||
|
||||
if (n == 0) {
|
||||
ret = 0;
|
||||
if (opt == OPT_HELP) {
|
||||
fputs(help, stdout);
|
||||
if (!s->verbose)
|
||||
return 0;
|
||||
++opt;
|
||||
}
|
||||
if (opt == OPT_HELP2) {
|
||||
fputs(help2, stdout);
|
||||
return 0;
|
||||
}
|
||||
if (opt == OPT_M32 || opt == OPT_M64)
|
||||
return tcc_tool_cross(s, argv, opt);
|
||||
if (s->verbose)
|
||||
if (s->verbose)
|
||||
goto help2;
|
||||
} else if (opt == OPT_HELP2) {
|
||||
help2: fputs(help2, stdout);
|
||||
} else if (opt == OPT_M32 || opt == OPT_M64) {
|
||||
ret = tcc_tool_cross(argv, opt);
|
||||
} else if (s->verbose)
|
||||
printf("%s", version);
|
||||
|
||||
if (opt == OPT_AR)
|
||||
return tcc_tool_ar(s, argc, argv);
|
||||
ret = tcc_tool_ar(argc, argv);
|
||||
#ifdef TCC_TARGET_PE
|
||||
if (opt == OPT_IMPDEF)
|
||||
return tcc_tool_impdef(s, argc, argv);
|
||||
ret = tcc_tool_impdef(argc, argv);
|
||||
#endif
|
||||
if (opt == OPT_V)
|
||||
return 0;
|
||||
if (opt == OPT_PRINT_DIRS) {
|
||||
/* initialize search dirs */
|
||||
set_environment(s);
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
print_search_dirs(s);
|
||||
return 0;
|
||||
}
|
||||
if (opt < 0) err:
|
||||
ret = 1, opt = -1;
|
||||
if (opt) {
|
||||
tcc_delete(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (s->nb_files == 0) {
|
||||
@ -345,7 +345,7 @@ redo:
|
||||
tcc_error_noabort("cannot specify output file with -c many files");
|
||||
}
|
||||
if (s->nb_errors)
|
||||
return 1;
|
||||
goto err;
|
||||
if (s->do_bench)
|
||||
start_time = getclock_ms();
|
||||
}
|
||||
@ -419,7 +419,6 @@ redo:
|
||||
tcc_print_stats(s, end_time - start_time);
|
||||
|
||||
tcc_delete(s);
|
||||
|
||||
if (!done)
|
||||
goto redo;
|
||||
if (ppfp && ppfp != stdout)
|
||||
|
||||
12
tcc.h
12
tcc.h
@ -95,13 +95,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#ifdef __clang__ // clang -fsanitize compains about: NULL+value
|
||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__ // clang -fsanitize compains about: NULL+value
|
||||
#undef offsetof
|
||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#ifndef countof
|
||||
@ -1507,6 +1506,7 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty);
|
||||
ST_FUNC void gbound_args(int nb_args);
|
||||
ST_DATA int func_bound_add_epilog;
|
||||
#endif
|
||||
ST_FUNC Sym *gfunc_set_param(Sym *s, int c, int byref);
|
||||
|
||||
/* ------------ tccelf.c ------------ */
|
||||
|
||||
@ -1857,7 +1857,7 @@ ST_FUNC void tcc_debug_eincl(TCCState *s1);
|
||||
ST_FUNC void tcc_debug_newfile(TCCState *s1);
|
||||
|
||||
ST_FUNC void tcc_debug_line(TCCState *s1);
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e);
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, Sym *s, Sym *e);
|
||||
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym);
|
||||
ST_FUNC void tcc_debug_prolog_epilog(TCCState *s1, int value);
|
||||
ST_FUNC void tcc_debug_funcend(TCCState *s1, int size);
|
||||
|
||||
12
tccdbg.c
12
tccdbg.c
@ -1625,7 +1625,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
|
||||
t = t->type.ref;
|
||||
debug_type = tcc_debug_find(s1, t, 0);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
debug_type = tcc_debug_add(s1, t, 0);
|
||||
cstr_new (&str);
|
||||
cstr_printf (&str, "%s:T%d=%c%d",
|
||||
@ -1664,7 +1664,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
Sym *e = t = t->type.ref;
|
||||
|
||||
debug_type = tcc_debug_find(s1, t, 0);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
debug_type = tcc_debug_add(s1, t, 0);
|
||||
cstr_new (&str);
|
||||
cstr_printf (&str, "%s:T%d=e",
|
||||
@ -1741,7 +1741,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
|
||||
if ((type & VT_BTYPE) == VT_STRUCT) {
|
||||
t = t->type.ref;
|
||||
debug_type = tcc_debug_find(s1, t, 1);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
int pos_sib = 0, i, *pos_type;
|
||||
|
||||
debug_type = tcc_debug_add(s1, t, 1);
|
||||
@ -1819,7 +1819,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
|
||||
else if (IS_ENUM(type)) {
|
||||
t = t->type.ref;
|
||||
debug_type = tcc_debug_find(s1, t, 1);
|
||||
if (debug_type == -1) {
|
||||
if (debug_type == -1 && t->c >= 0) {
|
||||
int pos_sib, pos_type;
|
||||
Sym sym = {0}; sym.type.t = VT_INT | (type & VT_UNSIGNED);
|
||||
|
||||
@ -2090,14 +2090,16 @@ static void tcc_debug_finish (TCCState *s1, struct _debug_info *cur)
|
||||
}
|
||||
}
|
||||
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e)
|
||||
ST_FUNC void tcc_add_debug_info(TCCState *s1, Sym *s, Sym *e)
|
||||
{
|
||||
CString debug_str;
|
||||
int param;
|
||||
|
||||
if (!(s1->do_debug & 2))
|
||||
return;
|
||||
|
||||
cstr_new (&debug_str);
|
||||
param = !e;
|
||||
for (; s != e; s = s->prev) {
|
||||
if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL)
|
||||
continue;
|
||||
|
||||
25
tccelf.c
25
tccelf.c
@ -318,8 +318,7 @@ ST_FUNC size_t section_add(Section *sec, addr_t size, int align)
|
||||
ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
|
||||
{
|
||||
size_t offset = section_add(sec, size, 1);
|
||||
// clang -fsanitize compains about: NULL+value
|
||||
return sec->data ? sec->data + offset : (void *)offset;
|
||||
return sec->data + offset;
|
||||
}
|
||||
|
||||
#ifndef ELF_OBJ_ONLY
|
||||
@ -1598,7 +1597,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
|
||||
|
||||
s = data_section;
|
||||
/* Align to PTR_SIZE */
|
||||
section_ptr_add(s, -s->data_offset & (PTR_SIZE - 1));
|
||||
section_add(s, 0, PTR_SIZE);
|
||||
o = s->data_offset;
|
||||
/* create a struct rt_context (see tccrun.c) */
|
||||
if (s1->dwarf) {
|
||||
@ -2837,7 +2836,6 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
||||
int textrel, got_sym, dt_flags_1;
|
||||
|
||||
file_type = s1->output_type;
|
||||
s1->nb_errors = 0;
|
||||
ret = -1;
|
||||
interp = dynstr = dynamic = NULL;
|
||||
sec_order = NULL;
|
||||
@ -3030,7 +3028,6 @@ static int elf_output_obj(TCCState *s1, const char *filename)
|
||||
{
|
||||
Section *s;
|
||||
int i, ret, file_offset;
|
||||
s1->nb_errors = 0;
|
||||
/* Allocate strings for section names */
|
||||
alloc_sec_names(s1, 1);
|
||||
file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4;
|
||||
@ -3049,6 +3046,7 @@ static int elf_output_obj(TCCState *s1, const char *filename)
|
||||
|
||||
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename)
|
||||
{
|
||||
s->nb_errors = 0;
|
||||
if (s->test_coverage)
|
||||
tcc_tcov_add_file(s, filename);
|
||||
if (s->output_type == TCC_OUTPUT_OBJ)
|
||||
@ -3254,21 +3252,19 @@ invalid:
|
||||
s->sh_entsize = sh->sh_entsize;
|
||||
sm_table[i].new_section = 1;
|
||||
found:
|
||||
size = sh->sh_size;
|
||||
/* align start of section */
|
||||
s->data_offset += -s->data_offset & (sh->sh_addralign - 1);
|
||||
offset = section_add(s, size, sh->sh_addralign);
|
||||
if (sh->sh_addralign > s->sh_addralign)
|
||||
s->sh_addralign = sh->sh_addralign;
|
||||
sm_table[i].offset = s->data_offset;
|
||||
sm_table[i].offset = offset;
|
||||
sm_table[i].s = s;
|
||||
/* concatenate sections */
|
||||
size = sh->sh_size;
|
||||
if (sh->sh_type != SHT_NOBITS) {
|
||||
if (sh->sh_type != SHT_NOBITS && size) {
|
||||
unsigned char *ptr;
|
||||
lseek(fd, file_offset + sh->sh_offset, SEEK_SET);
|
||||
ptr = section_ptr_add(s, size);
|
||||
ptr = s->data + offset;
|
||||
full_read(fd, ptr, size);
|
||||
} else {
|
||||
s->data_offset += size;
|
||||
}
|
||||
#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
||||
/* align code sections to instruction lenght */
|
||||
@ -3310,6 +3306,9 @@ invalid:
|
||||
}
|
||||
}
|
||||
|
||||
if (!symtab)
|
||||
goto done;
|
||||
|
||||
/* resolve symbols */
|
||||
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
|
||||
|
||||
@ -3405,7 +3404,7 @@ invalid:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
ret = 0;
|
||||
the_end:
|
||||
tcc_free(symtab);
|
||||
|
||||
384
tccgen.c
384
tccgen.c
@ -683,20 +683,25 @@ ST_INLN Sym *sym_find(int v)
|
||||
return table_ident[v]->sym_identifier;
|
||||
}
|
||||
|
||||
static int sym_scope(Sym *s)
|
||||
/* make sym in-/visible to the parser */
|
||||
static inline void sym_link(Sym *s, int yes)
|
||||
{
|
||||
if (IS_ENUM_VAL (s->type.t))
|
||||
return s->type.ref->sym_scope;
|
||||
else
|
||||
return s->sym_scope;
|
||||
TokenSym *ts = table_ident[(s->v & ~SYM_STRUCT) - TOK_IDENT];
|
||||
Sym **ps;
|
||||
if (s->v & SYM_STRUCT)
|
||||
ps = &ts->sym_struct;
|
||||
else
|
||||
ps = &ts->sym_identifier;
|
||||
if (yes)
|
||||
s->prev_tok = *ps, *ps = s;
|
||||
else
|
||||
*ps = s->prev_tok;
|
||||
}
|
||||
|
||||
/* push a given symbol on the symbol stack */
|
||||
ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
|
||||
{
|
||||
Sym *s, **ps;
|
||||
TokenSym *ts;
|
||||
|
||||
if (local_stack)
|
||||
ps = &local_stack;
|
||||
else
|
||||
@ -706,17 +711,15 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
|
||||
s->r = r;
|
||||
/* don't record fields or anonymous symbols */
|
||||
/* XXX: simplify */
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
/* record symbol in token array */
|
||||
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
|
||||
if (v & SYM_STRUCT)
|
||||
ps = &ts->sym_struct;
|
||||
else
|
||||
ps = &ts->sym_identifier;
|
||||
s->prev_tok = *ps;
|
||||
*ps = s;
|
||||
sym_link(s, 1);
|
||||
s->sym_scope = local_scope;
|
||||
if (s->prev_tok && sym_scope(s->prev_tok) == s->sym_scope)
|
||||
if (s->prev_tok
|
||||
&& (IS_ENUM_VAL (s->prev_tok->type.t)
|
||||
? s->prev_tok->type.ref->sym_scope
|
||||
: s->prev_tok->sym_scope)
|
||||
== s->sym_scope)
|
||||
tcc_error("redeclaration of '%s'",
|
||||
get_tok_str(v & ~SYM_STRUCT, NULL));
|
||||
}
|
||||
@ -746,8 +749,7 @@ ST_FUNC Sym *global_identifier_push(int v, int t, int c)
|
||||
pop them yet from the list, but do remove them from the token array. */
|
||||
ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
|
||||
{
|
||||
Sym *s, *ss, **ps;
|
||||
TokenSym *ts;
|
||||
Sym *s, *ss;
|
||||
int v;
|
||||
|
||||
s = *ptop;
|
||||
@ -755,15 +757,8 @@ ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep)
|
||||
ss = s->prev;
|
||||
v = s->v;
|
||||
/* remove symbol in token array */
|
||||
/* XXX: simplify */
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT];
|
||||
if (v & SYM_STRUCT)
|
||||
ps = &ts->sym_struct;
|
||||
else
|
||||
ps = &ts->sym_identifier;
|
||||
*ps = s->prev_tok;
|
||||
}
|
||||
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
sym_link(s, 0);
|
||||
if (!keep)
|
||||
sym_free(s);
|
||||
s = ss;
|
||||
@ -829,6 +824,19 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
|
||||
*ptop = slast;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* debug: print symbols on stack from s ... last */
|
||||
static inline void psyms(const char *msg, Sym *s, Sym *last)
|
||||
{
|
||||
printf("%-8s scope v c r type.t\n", msg);
|
||||
while (s && s != last) {
|
||||
printf(" %8x %08x %08x %08x %08x %s\n",
|
||||
s->sym_scope, s->v, s->c, s->r, s->type.t, get_tok_str(s->v, 0));
|
||||
s = s->prev;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
static void vcheck_cmp(void)
|
||||
{
|
||||
@ -1219,6 +1227,9 @@ static void patch_type(Sym *sym, CType *type)
|
||||
|
||||
} else if ((sym->type.t & VT_BTYPE) == VT_FUNC) {
|
||||
int static_proto = sym->type.t & VT_STATIC;
|
||||
int ft1 = sym->type.ref->f.func_type;
|
||||
int ft2 = type->ref->f.func_type;
|
||||
|
||||
/* warn if static follows non-static function declaration */
|
||||
if ((type->t & VT_STATIC) && !static_proto
|
||||
/* XXX this test for inline shouldn't be here. Until we
|
||||
@ -1239,15 +1250,14 @@ static void patch_type(Sym *sym, CType *type)
|
||||
struct FuncAttr f = sym->type.ref->f;
|
||||
/* put complete type, use static from prototype */
|
||||
sym->type.t = (type->t & ~(VT_STATIC|VT_INLINE)) | static_proto;
|
||||
if (ft1 != FUNC_OLD)
|
||||
type->ref->f.func_type = ft1;
|
||||
sym->type.ref = type->ref;
|
||||
merge_funcattr(&sym->type.ref->f, &f);
|
||||
} else {
|
||||
sym->type.t &= ~VT_INLINE | static_proto;
|
||||
}
|
||||
|
||||
if (sym->type.ref->f.func_type == FUNC_OLD
|
||||
&& type->ref->f.func_type != FUNC_OLD) {
|
||||
sym->type.ref = type->ref;
|
||||
if (ft1 == FUNC_OLD && ft2 != FUNC_OLD)
|
||||
sym->type.ref = type->ref;
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -1284,10 +1294,8 @@ static Sym *sym_copy(Sym *s0, Sym **ps)
|
||||
Sym *s;
|
||||
s = sym_malloc(), *s = *s0;
|
||||
s->prev = *ps, *ps = s;
|
||||
if (s->v < SYM_FIRST_ANOM) {
|
||||
ps = &table_ident[s->v - TOK_IDENT]->sym_identifier;
|
||||
s->prev_tok = *ps, *ps = s;
|
||||
}
|
||||
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
sym_link(s, 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -1677,16 +1685,15 @@ static void add_local_bounds(Sym *s, Sym *e)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Wrapper around sym_pop, that potentially also registers local bounds. */
|
||||
static void pop_local_syms(Sym *b, int keep)
|
||||
/* add debug info for locals or function parameters, optionally
|
||||
register bounds */
|
||||
static void tcc_debug_end_scope(Sym *b, int bounds)
|
||||
{
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && !keep && (local_scope || !func_var))
|
||||
if (tcc_state->do_bounds_check && bounds)
|
||||
add_local_bounds(local_stack, b);
|
||||
#endif
|
||||
if (debug_modes)
|
||||
tcc_add_debug_info (tcc_state, !local_scope, local_stack, b);
|
||||
sym_pop(&local_stack, b, keep);
|
||||
tcc_add_debug_info (tcc_state, local_stack, b);
|
||||
}
|
||||
|
||||
/* increment an lvalue pointer */
|
||||
@ -2959,15 +2966,17 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
|
||||
if (bt2 == VT_LLONG)
|
||||
type.t &= t2;
|
||||
/* convert to unsigned if it does not fit in a long long */
|
||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
|
||||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
|
||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) ||
|
||||
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
|
||||
type.t |= VT_UNSIGNED;
|
||||
} else {
|
||||
/* integer operations */
|
||||
type.t = VT_INT | (VT_LONG & (t1 | t2));
|
||||
/* convert to unsigned if it does not fit in an integer */
|
||||
if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
|
||||
(t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
|
||||
if (((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)
|
||||
&& (!(t1 & VT_BITFIELD) || BIT_SIZE(t1) == 32))
|
||||
|| ((t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)
|
||||
&& (!(t2 & VT_BITFIELD) || BIT_SIZE(t2) == 32)))
|
||||
type.t |= VT_UNSIGNED;
|
||||
}
|
||||
if (dest)
|
||||
@ -3851,10 +3860,14 @@ static void parse_attribute(AttributeDef *ad)
|
||||
{
|
||||
int t, n;
|
||||
char *astr;
|
||||
AttributeDef ad_tmp;
|
||||
|
||||
redo:
|
||||
if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2)
|
||||
return;
|
||||
if (NULL == ad) /* skip over / ignore attributes */
|
||||
ad = &ad_tmp;
|
||||
|
||||
next();
|
||||
skip('(');
|
||||
skip('(');
|
||||
@ -4509,7 +4522,7 @@ do_decl:
|
||||
expect("identifier");
|
||||
else {
|
||||
int v = btype.ref->v;
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
|
||||
if (tcc_state->ms_extensions == 0)
|
||||
expect("identifier");
|
||||
}
|
||||
@ -4554,6 +4567,7 @@ do_decl:
|
||||
tcc_error("width of '%s' exceeds its type",
|
||||
get_tok_str(v, NULL));
|
||||
} else if (bit_size == bsize
|
||||
&& !*tcc_state->pack_stack_ptr
|
||||
&& !ad.a.packed && !ad1.a.packed) {
|
||||
/* no need for bit fields */
|
||||
;
|
||||
@ -4921,7 +4935,7 @@ static int asm_label_instr(void)
|
||||
static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
{
|
||||
int n, l, t1, arg_size, align;
|
||||
Sym **plast, *s, *first;
|
||||
Sym **plast, *s, *first, **ps, *sr;
|
||||
AttributeDef ad1;
|
||||
CType pt;
|
||||
TokenString *vla_array_tok = NULL;
|
||||
@ -4932,11 +4946,20 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
next();
|
||||
if (TYPE_DIRECT == (td & (TYPE_DIRECT|TYPE_ABSTRACT)))
|
||||
return 0;
|
||||
|
||||
/* we push a anonymous symbol which will contain the function prototype */
|
||||
/* it also serves as a boundary for the function parameter scope */
|
||||
ps = local_stack ? &local_stack : &global_stack;
|
||||
++local_scope;
|
||||
sr = sym_push2(ps, SYM_FIELD, 0, 0);
|
||||
|
||||
if (tok == ')')
|
||||
l = 0;
|
||||
else if (parse_btype(&pt, &ad1, 0))
|
||||
l = FUNC_NEW;
|
||||
else if (td & (TYPE_DIRECT|TYPE_ABSTRACT)) {
|
||||
sym_pop(ps, sr->prev, 0);
|
||||
--local_scope;
|
||||
merge_attr (ad, &ad1);
|
||||
return 0;
|
||||
} else
|
||||
@ -4945,7 +4968,6 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
first = NULL;
|
||||
plast = &first;
|
||||
arg_size = 0;
|
||||
++local_scope;
|
||||
if (l) {
|
||||
for(;;) {
|
||||
/* read param name and compute offset */
|
||||
@ -4959,7 +4981,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
n = SYM_FIELD;
|
||||
} else {
|
||||
n = tok;
|
||||
pt.t = VT_VOID; /* invalid type */
|
||||
pt.t = VT_INT | VT_EXTERN; /* default type */
|
||||
pt.ref = NULL;
|
||||
next();
|
||||
}
|
||||
@ -4968,8 +4990,7 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
convert_parameter_type(&pt);
|
||||
arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
|
||||
/* these symbols may be evaluated for VLArrays (see below, under
|
||||
nocode_wanted) which is why we push them here as normal symbols
|
||||
temporarily. Example: int func(int a, int b[++a]); */
|
||||
nocode_wanted) Example: int func(int a, int b[++a]); */
|
||||
s = sym_push(n, &pt, VT_LOCAL|VT_LVAL, 0);
|
||||
*plast = s;
|
||||
plast = &s->next;
|
||||
@ -4988,12 +5009,6 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
/* if no parameters, then old type prototype */
|
||||
l = FUNC_OLD;
|
||||
skip(')');
|
||||
/* remove parameter symbols from token table, keep on stack */
|
||||
if (first) {
|
||||
sym_pop(local_stack ? &local_stack : &global_stack, first->prev, 1);
|
||||
for (s = first; s; s = s->next)
|
||||
s->v |= SYM_FIELD;
|
||||
}
|
||||
--local_scope;
|
||||
/* NOTE: const is ignored in returned type as it has a special
|
||||
meaning in gcc / C++ */
|
||||
@ -5006,15 +5021,19 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
|
||||
skip(']'); /* only handle simple "[]" */
|
||||
mk_pointer(type);
|
||||
}
|
||||
/* we push a anonymous symbol which will contain the function prototype */
|
||||
ad->f.func_args = arg_size;
|
||||
ad->f.func_type = l;
|
||||
s = sym_push(SYM_FIELD, type, 0, 0);
|
||||
sr->type = *type, s = sr;
|
||||
s->a = ad->a;
|
||||
s->f = ad->f;
|
||||
s->next = first;
|
||||
type->t = VT_FUNC;
|
||||
type->ref = s;
|
||||
|
||||
/* unlink symbols from the token table, keep on stack */
|
||||
sym_pop(ps, sr, 1);
|
||||
//psyms("---", *ps, sr);
|
||||
|
||||
} else if (tok == '[') {
|
||||
int saved_nocode_wanted = nocode_wanted;
|
||||
/* array definition */
|
||||
@ -5612,6 +5631,8 @@ ST_FUNC void unary(void)
|
||||
as statement expressions can't ever be entered from the
|
||||
outside, so any reactivation of code emission (from labels
|
||||
or loop heads) can be disabled again after the end of it. */
|
||||
/* default return value is (void) */
|
||||
vpushi(0), vtop->type.t = VT_VOID;
|
||||
block(STMT_EXPR);
|
||||
/* If the statement expr can be entered, then we retain the current
|
||||
nocode_wanted state (from e.g. a 'return 0;' in the stmt-expr).
|
||||
@ -6967,6 +6988,9 @@ static void prev_scope(struct scope *o, int is_expr)
|
||||
if (o->cl.s != o->prev->cl.s)
|
||||
block_cleanup(o->prev);
|
||||
|
||||
if (debug_modes)
|
||||
tcc_debug_end_scope(o->lstk, !is_expr);
|
||||
|
||||
/* pop locally defined labels */
|
||||
label_pop(&local_label_stack, o->llstk, is_expr);
|
||||
|
||||
@ -6979,7 +7003,7 @@ static void prev_scope(struct scope *o, int is_expr)
|
||||
tables, though. sym_pop will do that. */
|
||||
|
||||
/* pop locally defined symbols */
|
||||
pop_local_syms(o->lstk, is_expr);
|
||||
sym_pop(&local_stack, o->lstk, is_expr);
|
||||
cur_scope = o->prev;
|
||||
--local_scope;
|
||||
}
|
||||
@ -7033,12 +7057,6 @@ static void block(int flags)
|
||||
struct scope o;
|
||||
Sym *s;
|
||||
|
||||
if (flags & STMT_EXPR) {
|
||||
/* default return value is (void) */
|
||||
vpushi(0);
|
||||
vtop->type.t = VT_VOID;
|
||||
}
|
||||
|
||||
again:
|
||||
t = tok;
|
||||
/* If the token carries a value, next() might destroy it. Only with
|
||||
@ -7054,8 +7072,8 @@ again:
|
||||
new_scope_s(&o);
|
||||
skip('(');
|
||||
gexpr();
|
||||
skip(')');
|
||||
a = gvtst(1, 0);
|
||||
skip(')');
|
||||
block(0);
|
||||
if (tok == TOK_ELSE) {
|
||||
d = gjmp(0);
|
||||
@ -7073,8 +7091,8 @@ again:
|
||||
d = gind();
|
||||
skip('(');
|
||||
gexpr();
|
||||
skip(')');
|
||||
a = gvtst(1, 0);
|
||||
skip(')');
|
||||
b = 0;
|
||||
lblock(&a, &b);
|
||||
gjmp_addr(d);
|
||||
@ -7102,8 +7120,6 @@ again:
|
||||
while (tok != '}') {
|
||||
decl(VT_LOCAL);
|
||||
if (tok != '}') {
|
||||
if (flags & STMT_EXPR)
|
||||
vpop();
|
||||
block(flags | STMT_COMPOUND);
|
||||
}
|
||||
}
|
||||
@ -7205,9 +7221,9 @@ again:
|
||||
skip(TOK_WHILE);
|
||||
skip('(');
|
||||
gexpr();
|
||||
c = gvtst(0, 0);
|
||||
skip(')');
|
||||
skip(';');
|
||||
c = gvtst(0, 0);
|
||||
gsym_addr(c, d);
|
||||
gsym(a);
|
||||
prev_scope_s(&o);
|
||||
@ -7225,9 +7241,9 @@ again:
|
||||
new_scope_s(&o);
|
||||
skip('(');
|
||||
gexpr();
|
||||
skip(')');
|
||||
if (!is_integer_btype(vtop->type.t & VT_BTYPE))
|
||||
tcc_error("switch value not an integer");
|
||||
skip(')');
|
||||
sw->sv = *vtop--; /* save switch value */
|
||||
a = 0;
|
||||
b = gjmp(0); /* jump to first case */
|
||||
@ -7347,11 +7363,9 @@ again:
|
||||
s->cleanupstate = cur_scope->cl.s;
|
||||
|
||||
block_after_label:
|
||||
{
|
||||
/* Accept attributes after labels (e.g. 'unused') */
|
||||
AttributeDef ad_tmp;
|
||||
parse_attribute(&ad_tmp);
|
||||
}
|
||||
/* Accept attributes after labels (e.g. 'unused') */
|
||||
parse_attribute(NULL);
|
||||
|
||||
if (debug_modes)
|
||||
tcc_tcov_reset_ind(tcc_state);
|
||||
vla_restore(cur_scope->vla.loc);
|
||||
@ -8071,20 +8085,32 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
|
||||
is put in the value stack. If 'has_init' is 2, a special parsing
|
||||
is done to handle string constants. */
|
||||
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
int has_init, int v, int global)
|
||||
int has_init, int v, int scope)
|
||||
{
|
||||
int size, align, addr;
|
||||
TokenString *init_str = NULL;
|
||||
|
||||
Section *sec;
|
||||
Sym *flexible_array;
|
||||
Sym *sym;
|
||||
Sym *sym = NULL;
|
||||
int saved_nocode_wanted = nocode_wanted;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED;
|
||||
#endif
|
||||
init_params p = {0};
|
||||
|
||||
if (scope == VT_CONST) {
|
||||
/* see if a global symbol was already defined */
|
||||
sym = sym_find(v);
|
||||
if (sym) {
|
||||
patch_storage(sym, ad, type);
|
||||
/* we accept several definitions of the same global variable. */
|
||||
if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)
|
||||
return;
|
||||
type = &sym->type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always allocate static or global variables */
|
||||
if (v && (r & VT_VALMASK) == VT_CONST)
|
||||
nocode_wanted |= DATA_ONLY_WANTED;
|
||||
@ -8100,12 +8126,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
// (arrays of incomplete types are handled in array parsing)
|
||||
if (!(type->t & VT_ARRAY))
|
||||
tcc_error("initialization of incomplete type");
|
||||
|
||||
/* If the base type itself was an array type of unspecified size
|
||||
(like in 'typedef int arr[]; arr x = {1};') then we will
|
||||
overwrite the unknown size by the real one for this decl.
|
||||
We need to unshare the ref symbol holding that size. */
|
||||
type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c);
|
||||
p.flex_array_ref = type->ref;
|
||||
|
||||
} else if (has_init && (type->t & VT_BTYPE) == VT_STRUCT) {
|
||||
@ -8211,26 +8231,6 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
vset(type, r, addr);
|
||||
}
|
||||
} else {
|
||||
sym = NULL;
|
||||
if (v && global) {
|
||||
/* see if the symbol was already defined */
|
||||
sym = sym_find(v);
|
||||
if (sym) {
|
||||
if (p.flex_array_ref && (sym->type.t & type->t & VT_ARRAY)
|
||||
&& sym->type.ref->c > type->ref->c) {
|
||||
/* flex array was already declared with explicit size
|
||||
extern int arr[10];
|
||||
int arr[] = { 1,2,3 }; */
|
||||
type->ref->c = sym->type.ref->c;
|
||||
size = type_size(type, &align);
|
||||
}
|
||||
patch_storage(sym, ad, type);
|
||||
/* we accept several definitions of the same global variable. */
|
||||
if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF)
|
||||
goto no_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate symbol in corresponding section */
|
||||
sec = ad->section;
|
||||
if (!sec) {
|
||||
@ -8291,6 +8291,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
||||
if (type->t & VT_VLA) {
|
||||
int a;
|
||||
|
||||
if (has_init)
|
||||
tcc_error("variable length array cannot be initialized");
|
||||
|
||||
if (NODATA_WANTED)
|
||||
goto no_alloc;
|
||||
|
||||
@ -8373,11 +8376,35 @@ static void func_vla_arg(Sym *sym)
|
||||
func_vla_arg_code(arg->type.ref);
|
||||
}
|
||||
|
||||
/* set the local stack address for function parameter from gfunc_prolog() */
|
||||
ST_FUNC Sym *gfunc_set_param(Sym *s, int c, int byref)
|
||||
{
|
||||
s = sym_find(s->v);
|
||||
if (!s) /* unnamed parameters, not enabled */
|
||||
return NULL;
|
||||
s->c = c;
|
||||
if (byref)
|
||||
s->r = VT_LLOCAL | VT_LVAL;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* push parameters (and their types), last first */
|
||||
static void sym_push_params(Sym *ref)
|
||||
{
|
||||
Sym *s;
|
||||
for (s = ref; s->next; s = s->next)
|
||||
;
|
||||
for (; s && s != ref; s = s->prev)
|
||||
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
sym_copy(s, &local_stack);
|
||||
}
|
||||
|
||||
/* parse a function defined by symbol 'sym' and generate its code in
|
||||
'cur_text_section' */
|
||||
static void gen_function(Sym *sym)
|
||||
{
|
||||
struct scope f = { 0 };
|
||||
|
||||
cur_scope = root_scope = &f;
|
||||
nocode_wanted = 0;
|
||||
|
||||
@ -8406,20 +8433,21 @@ static void gen_function(Sym *sym)
|
||||
|
||||
/* push a dummy symbol to enable local sym storage */
|
||||
sym_push2(&local_stack, SYM_FIELD, 0, 0);
|
||||
local_scope = 1; /* for function parameters */
|
||||
nb_temp_local_vars = 0;
|
||||
gfunc_prolog(sym);
|
||||
tcc_debug_prolog_epilog(tcc_state, 0);
|
||||
/* push parameters */
|
||||
sym_push_params(sym->type.ref);
|
||||
//psyms(funcname, local_stack, 0);
|
||||
|
||||
local_scope = 0;
|
||||
rsym = 0;
|
||||
nb_temp_local_vars = 0;
|
||||
|
||||
gfunc_prolog(sym);
|
||||
tcc_debug_prolog_epilog(tcc_state, 0);
|
||||
func_vla_arg(sym);
|
||||
block(0);
|
||||
gsym(rsym);
|
||||
|
||||
nocode_wanted = 0;
|
||||
/* reset local stack */
|
||||
pop_local_syms(NULL, 0);
|
||||
tcc_debug_end_scope(NULL, !func_var);
|
||||
tcc_debug_prolog_epilog(tcc_state, 1);
|
||||
gfunc_epilog();
|
||||
|
||||
@ -8428,11 +8456,12 @@ static void gen_function(Sym *sym)
|
||||
|
||||
/* patch symbol size */
|
||||
elfsym(sym)->st_size = ind - func_ind;
|
||||
|
||||
cur_text_section->data_offset = ind;
|
||||
local_scope = 0;
|
||||
|
||||
sym_pop(&local_stack, NULL, 0);
|
||||
label_pop(&global_label_stack, NULL, 0);
|
||||
sym_pop(&all_cleanups, NULL, 0);
|
||||
local_scope = 0;
|
||||
|
||||
/* It's better to crash than to generate wrong code */
|
||||
cur_text_section = NULL;
|
||||
@ -8510,6 +8539,27 @@ static void do_Static_assert(void)
|
||||
skip(';');
|
||||
}
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
static void pe_check_linkage(CType *type, AttributeDef *ad)
|
||||
{
|
||||
if (!ad->a.dllimport && !ad->a.dllexport)
|
||||
return;
|
||||
if (type->t & VT_STATIC)
|
||||
tcc_error("cannot have dll linkage with static");
|
||||
if (type->t & VT_TYPEDEF) {
|
||||
const char *m = ad->a.dllimport ? "im" : "ex";
|
||||
tcc_warning("'dll%sport' attribute ignored for typedef", m);
|
||||
ad->a.dllimport = 0;
|
||||
ad->a.dllexport = 0;
|
||||
} else if (ad->a.dllimport) {
|
||||
if ((type->t & VT_BTYPE) == VT_FUNC)
|
||||
ad->a.dllimport = 0;
|
||||
else
|
||||
type->t |= VT_EXTERN;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 'l' is VT_LOCAL or VT_CONST to define default storage type
|
||||
or VT_CMP if parsing old style parameter list
|
||||
or VT_JMP if parsing c99 for decl: for (int i = 0, ...) */
|
||||
@ -8517,7 +8567,7 @@ static int decl(int l)
|
||||
{
|
||||
int v, has_init, r, oldint;
|
||||
CType type, btype;
|
||||
Sym *sym, *s;
|
||||
Sym *sym;
|
||||
AttributeDef ad, adbase;
|
||||
ElfSym *esym;
|
||||
|
||||
@ -8556,22 +8606,30 @@ static int decl(int l)
|
||||
}
|
||||
|
||||
if (tok == ';') {
|
||||
if ((btype.t & VT_BTYPE) == VT_STRUCT) {
|
||||
v = btype.ref->v;
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM)
|
||||
tcc_warning("unnamed struct/union that defines no instances");
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
if (IS_ENUM(btype.t)) {
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
if ((btype.t & VT_BTYPE) == VT_STRUCT
|
||||
&& (btype.ref->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
; /* struct decl with named tag */
|
||||
else if (IS_ENUM(btype.t))
|
||||
; /* enum decl */
|
||||
else
|
||||
tcc_warning("useless type defines no instances");
|
||||
if (l == VT_JMP)
|
||||
return 1;
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
|
||||
while (1) { /* iterate thru each declaration */
|
||||
type = btype;
|
||||
ad = adbase;
|
||||
if ((btype.t & VT_ARRAY) && btype.ref->c < 0) {
|
||||
/* If the base type itself was an array type of unspecified
|
||||
size (like in 'typedef int arr[]; arr x = {1};') then
|
||||
we will overwrite the unknown size by the real one for
|
||||
this decl. We need to unshare the ref symbol holding
|
||||
that size. */
|
||||
type.ref = sym_push(SYM_FIELD, &type.ref->type, 0, type.ref->c);
|
||||
}
|
||||
type_decl(&type, &ad, &v, TYPE_DIRECT);
|
||||
#if 0
|
||||
{
|
||||
@ -8589,23 +8647,7 @@ static int decl(int l)
|
||||
if (sym->f.func_type == FUNC_OLD && l == VT_CONST) {
|
||||
func_vt = type;
|
||||
decl(VT_CMP);
|
||||
|
||||
/* Allow mixing old/new prototypes
|
||||
* void func(float a);
|
||||
* int main(void) { func(1.0); }
|
||||
* void func(a) float a; { printf("%g\n", a); }
|
||||
*/
|
||||
s = sym_find(v);
|
||||
if (type.ref->next && // skip old func(); definitions
|
||||
s && s->type.ref &&
|
||||
s->type.ref->f.func_type == FUNC_NEW) {
|
||||
sym->f.func_type = FUNC_NEW;
|
||||
if (!is_compatible_types(&s->type, &type))
|
||||
tcc_error("incompatible redefinition of '%s'",
|
||||
get_tok_str(v, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
if ((type.t & (VT_EXTERN|VT_INLINE)) == (VT_EXTERN|VT_INLINE)) {
|
||||
/* always_inline functions must be handled as if they
|
||||
don't generate multiple global defs, even if extern
|
||||
@ -8634,47 +8676,33 @@ static int decl(int l)
|
||||
}
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
if (ad.a.dllimport || ad.a.dllexport) {
|
||||
if (type.t & VT_STATIC)
|
||||
tcc_error("cannot have dll linkage with static");
|
||||
if (type.t & VT_TYPEDEF) {
|
||||
tcc_warning("'%s' attribute ignored for typedef",
|
||||
ad.a.dllimport ? (ad.a.dllimport = 0, "dllimport") :
|
||||
(ad.a.dllexport = 0, "dllexport"));
|
||||
} else if (ad.a.dllimport) {
|
||||
if ((type.t & VT_BTYPE) == VT_FUNC)
|
||||
ad.a.dllimport = 0;
|
||||
else
|
||||
type.t |= VT_EXTERN;
|
||||
}
|
||||
}
|
||||
pe_check_linkage(&type, &ad);
|
||||
#endif
|
||||
if (tok == '{') {
|
||||
Sym *sa;
|
||||
|
||||
if (l != VT_CONST)
|
||||
tcc_error("cannot use local functions");
|
||||
if ((type.t & VT_BTYPE) != VT_FUNC)
|
||||
expect("function definition");
|
||||
|
||||
/* reject abstract declarators in function definition
|
||||
make old style params without decl have int type */
|
||||
sym = type.ref;
|
||||
while ((sym = sym->next) != NULL) {
|
||||
if (!(sym->v & ~SYM_FIELD))
|
||||
expect("identifier");
|
||||
if (type.ref->f.func_type == FUNC_OLD &&
|
||||
sym->type.t == VT_FLOAT)
|
||||
sym->type.t = VT_DOUBLE;
|
||||
if (sym->type.t == VT_VOID)
|
||||
sym->type = int_type;
|
||||
}
|
||||
|
||||
/* apply post-declaraton attributes */
|
||||
merge_funcattr(&type.ref->f, &ad.f);
|
||||
|
||||
/* put function symbol */
|
||||
type.t &= ~VT_EXTERN;
|
||||
sym = external_sym(v, &type, 0, &ad);
|
||||
|
||||
/* reject abstract declarators in function definition
|
||||
make old-style float params double */
|
||||
for (sa = sym->type.ref; (sa = sa->next) != NULL;) {
|
||||
if (!(sa->v & ~SYM_FIELD))
|
||||
expect("identifier");
|
||||
if (sa->type.t == VT_FLOAT
|
||||
&& sym->type.ref->f.func_type == FUNC_OLD) {
|
||||
sa->type.t = VT_DOUBLE;
|
||||
}
|
||||
}
|
||||
|
||||
/* static inline functions are just recorded as a kind
|
||||
of macro. Their code will be emitted at the end of
|
||||
the compilation unit only if they are used */
|
||||
@ -8697,6 +8725,7 @@ static int decl(int l)
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
has_init = 0;
|
||||
if (l == VT_CMP) {
|
||||
/* find parameter in function parameter list */
|
||||
for (sym = func_vt.ref->next; sym; sym = sym->next)
|
||||
@ -8708,7 +8737,7 @@ static int decl(int l)
|
||||
if (type.t & VT_STORAGE) /* 'register' is okay */
|
||||
tcc_error("storage class specified for '%s'",
|
||||
get_tok_str(v, NULL));
|
||||
if (sym->type.t != VT_VOID)
|
||||
if (!(sym->type.t & VT_EXTERN))
|
||||
tcc_error("redefinition of parameter '%s'",
|
||||
get_tok_str(v, NULL));
|
||||
convert_parameter_type(&type);
|
||||
@ -8744,9 +8773,9 @@ static int decl(int l)
|
||||
/* not lvalue if array */
|
||||
r |= VT_LVAL;
|
||||
}
|
||||
has_init = (tok == '=');
|
||||
if (has_init && (type.t & VT_VLA))
|
||||
tcc_error("variable length array cannot be initialized");
|
||||
|
||||
if (tok == '=')
|
||||
has_init = 1;
|
||||
|
||||
if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST))
|
||||
|| (type.t & VT_BTYPE) == VT_FUNC
|
||||
@ -8763,12 +8792,13 @@ static int decl(int l)
|
||||
r |= VT_CONST;
|
||||
else
|
||||
r |= VT_LOCAL;
|
||||
type.t &= ~VT_EXTERN;
|
||||
if (has_init)
|
||||
next();
|
||||
else if (l == VT_CONST)
|
||||
/* uninitialized global variables may be overridden */
|
||||
type.t |= VT_EXTERN;
|
||||
decl_initializer_alloc(&type, &ad, r, has_init, v, l == VT_CONST);
|
||||
decl_initializer_alloc(&type, &ad, r, has_init, v, l);
|
||||
}
|
||||
|
||||
if (ad.alias_target && l == VT_CONST) {
|
||||
@ -8786,7 +8816,7 @@ static int decl(int l)
|
||||
}
|
||||
if (tok != ',') {
|
||||
if (l == VT_JMP)
|
||||
return 1;
|
||||
return has_init ? v : 1;
|
||||
skip(';');
|
||||
break;
|
||||
}
|
||||
|
||||
36
tccpp.c
36
tccpp.c
@ -102,7 +102,7 @@ ST_FUNC void skip(int c)
|
||||
if (tok != c) {
|
||||
char tmp[40];
|
||||
pstrcpy(tmp, sizeof tmp, get_tok_str(c, &tokc));
|
||||
tcc_error("'%s' expected (got \"%s\")", tmp, get_tok_str(tok, &tokc));
|
||||
tcc_error("'%s' expected (got '%s')", tmp, get_tok_str(tok, &tokc));
|
||||
}
|
||||
next();
|
||||
}
|
||||
@ -117,16 +117,6 @@ ST_FUNC void expect(const char *msg)
|
||||
|
||||
#define USE_TAL
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# if defined _M_AMD64 || defined _M_ARM64 || defined _M_ARM64EC || defined _M_IA64 || defined _M_X64
|
||||
# define POINTER_SIZE 8
|
||||
# else
|
||||
# define POINTER_SIZE 4
|
||||
# endif
|
||||
#else
|
||||
# define POINTER_SIZE sizeof(void *)
|
||||
#endif
|
||||
|
||||
#ifndef USE_TAL
|
||||
#define tal_free(al, p) tcc_free(p)
|
||||
#define tal_realloc(al, p, size) tcc_realloc(p, size)
|
||||
@ -143,7 +133,6 @@ ST_FUNC void expect(const char *msg)
|
||||
#define tal_free(al, p) tal_free_impl(al, p, __FILE__, __LINE__)
|
||||
#define tal_realloc(al, p, size) tal_realloc_impl(&al, p, size, __FILE__, __LINE__)
|
||||
#define TAL_DEBUG_PARAMS , const char *file, int line
|
||||
#define TAL_DEBUG_FILE_LEN 40
|
||||
#endif
|
||||
|
||||
#define TOKSYM_TAL_SIZE (768 * 1024) /* allocator for tiny TokenSym in table_ident */
|
||||
@ -167,13 +156,16 @@ typedef struct TinyAlloc {
|
||||
} TinyAlloc;
|
||||
|
||||
typedef struct tal_header_t {
|
||||
ALIGNED(POINTER_SIZE) unsigned size;
|
||||
size_t size; /* word align */
|
||||
#ifdef TAL_DEBUG
|
||||
int line_num; /* negative line_num used for double free check */
|
||||
char file_name[TAL_DEBUG_FILE_LEN + 1];
|
||||
char file_name[40];
|
||||
#endif
|
||||
} tal_header_t;
|
||||
|
||||
#define TAL_ALIGN(size) \
|
||||
(((size) + (sizeof (size_t) - 1)) & ~(sizeof (size_t) - 1))
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static TinyAlloc *tal_new(TinyAlloc **pal, unsigned limit, unsigned size)
|
||||
@ -208,7 +200,7 @@ tail_call:
|
||||
tal_header_t *header = (tal_header_t *)p;
|
||||
if (header->line_num > 0) {
|
||||
fprintf(stderr, "%s:%d: chunk of %d bytes leaked\n",
|
||||
header->file_name, header->line_num, header->size);
|
||||
header->file_name, header->line_num, (int)header->size);
|
||||
}
|
||||
p += header->size + sizeof(tal_header_t);
|
||||
}
|
||||
@ -256,7 +248,7 @@ static void *tal_realloc_impl(TinyAlloc **pal, void *p, unsigned size TAL_DEBUG_
|
||||
tal_header_t *header;
|
||||
void *ret;
|
||||
int is_own;
|
||||
unsigned adj_size = (size + POINTER_SIZE - 1) & -POINTER_SIZE;
|
||||
unsigned adj_size = TAL_ALIGN(size);
|
||||
TinyAlloc *al = *pal;
|
||||
|
||||
tail_call:
|
||||
@ -266,9 +258,8 @@ tail_call:
|
||||
header = (tal_header_t *)al->p;
|
||||
header->size = adj_size;
|
||||
#ifdef TAL_DEBUG
|
||||
{ int ofs = strlen(file) - TAL_DEBUG_FILE_LEN;
|
||||
strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), TAL_DEBUG_FILE_LEN);
|
||||
header->file_name[TAL_DEBUG_FILE_LEN] = 0;
|
||||
{ int ofs = strlen(file) + 1 - sizeof header->file_name;
|
||||
strcpy(header->file_name, file + (ofs > 0 ? ofs : 0));
|
||||
header->line_num = line; }
|
||||
#endif
|
||||
ret = al->p + sizeof(tal_header_t);
|
||||
@ -2986,6 +2977,11 @@ maybe_newline:
|
||||
tok = c;
|
||||
p++;
|
||||
break;
|
||||
case 0xEF: /* UTF8 BOM ? */
|
||||
if (p[1] == 0xBB && p[2] == 0xBF && p == file->buffer) {
|
||||
p += 3;
|
||||
goto redo_no_start;
|
||||
}
|
||||
default:
|
||||
if (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */
|
||||
goto parse_ident_fast;
|
||||
@ -3637,7 +3633,7 @@ static void putdefs(CString *cs, const char *p)
|
||||
|
||||
static void tcc_predefs(TCCState *s1, CString *cs, int is_asm)
|
||||
{
|
||||
cstr_printf(cs, "#define __TINYC__ 9%.2s\n", *& TCC_VERSION + 4);
|
||||
cstr_printf(cs, "#define __TINYC__ 9%.2s\n", &TCC_VERSION[4]);
|
||||
putdefs(cs, target_machine_defs);
|
||||
putdefs(cs, target_os_defs);
|
||||
|
||||
|
||||
13
tccrun.c
13
tccrun.c
@ -312,6 +312,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, unsigned ptr_diff)
|
||||
addr_t mem, addr;
|
||||
|
||||
if (NULL == ptr) {
|
||||
s1->nb_errors = 0;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pe_output_file(s1, NULL);
|
||||
#else
|
||||
@ -495,10 +496,6 @@ static void bt_link(TCCState *s1)
|
||||
{
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
rt_context *rc;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
void *p;
|
||||
#endif
|
||||
|
||||
if (!s1->do_backtrace)
|
||||
return;
|
||||
rc = tcc_get_symbol(s1, "__rt_info");
|
||||
@ -511,6 +508,7 @@ static void bt_link(TCCState *s1)
|
||||
rc->prog_base &= 0xffffffff00000000ULL;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (s1->do_bounds_check) {
|
||||
void *p;
|
||||
if ((p = tcc_get_symbol(s1, "__bound_init")))
|
||||
((void(*)(void*,int))p)(rc->bounds_start, 1);
|
||||
}
|
||||
@ -599,6 +597,13 @@ static void rt_exit(rt_frame *f, int code)
|
||||
s = rt_find_state(f);
|
||||
rt_post_sem();
|
||||
if (s && s->run_lj) {
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (f->fp) { /* called from signal */
|
||||
void *p = tcc_get_symbol(s, "__bound_exit");
|
||||
if (p)
|
||||
((void (*)(void))p)();
|
||||
}
|
||||
#endif
|
||||
if (code == 0)
|
||||
code = RT_EXIT_ZERO;
|
||||
((void(*)(void*,int))s->run_lj)(s->run_jb, code);
|
||||
|
||||
12
tcctools.c
12
tcctools.c
@ -54,7 +54,7 @@ static int ar_usage(int ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
|
||||
ST_FUNC int tcc_tool_ar(int argc, char **argv)
|
||||
{
|
||||
static const ArHdr arhdr_init = {
|
||||
"/ ",
|
||||
@ -360,7 +360,7 @@ the_end:
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
|
||||
ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv)
|
||||
ST_FUNC int tcc_tool_impdef(int argc, char **argv)
|
||||
{
|
||||
int ret, v, i;
|
||||
char infile[260];
|
||||
@ -487,9 +487,9 @@ the_end:
|
||||
|
||||
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
|
||||
|
||||
ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int option)
|
||||
ST_FUNC int tcc_tool_cross(char **argv, int option)
|
||||
{
|
||||
tcc_error_noabort("-m%d not implemented.", option);
|
||||
fprintf(stderr, "tcc -m%d not implemented\n", option);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -546,7 +546,7 @@ static int execvp_win32(const char *prog, char **argv)
|
||||
#define execvp execvp_win32
|
||||
#endif /* _WIN32 */
|
||||
|
||||
ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int target)
|
||||
ST_FUNC int tcc_tool_cross(char **argv, int target)
|
||||
{
|
||||
char program[4096];
|
||||
char *a0 = argv[0];
|
||||
@ -565,7 +565,7 @@ ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int target)
|
||||
|
||||
if (strcmp(a0, program))
|
||||
execvp(argv[0] = program, argv);
|
||||
tcc_error_noabort("could not run '%s'", program);
|
||||
fprintf(stderr, "tcc: could not run '%s'\n", program);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ endif
|
||||
|
||||
all test :
|
||||
@echo ------------ version ------------
|
||||
@ASAN_OPTIONS=detect_leaks=0 $(TCC_LOCAL) -v
|
||||
@$(TCC_LOCAL) -v
|
||||
@$(MAKE) --no-print-directory -s clean
|
||||
@$(MAKE) --no-print-directory -s -r _all
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
int printf(const char*, ...);
|
||||
|
||||
#if defined test_56_btype_excess_1
|
||||
struct A {} int i;
|
||||
|
||||
#elif defined test_57_btype_excess_2
|
||||
char int i;
|
||||
|
||||
#elif defined test_58_function_redefinition
|
||||
int f(void) { return 0; }
|
||||
int f(void) { return 1; }
|
||||
@ -253,7 +253,7 @@ int main () {
|
||||
hello(123);
|
||||
return 0;
|
||||
}
|
||||
int printf(const char*, ...);
|
||||
|
||||
#if defined test_func_3
|
||||
static int hello(int a)
|
||||
#elif defined test_func_5
|
||||
@ -272,7 +272,7 @@ int hello(int a)
|
||||
int xxx[];
|
||||
#endif
|
||||
int bar();
|
||||
int printf(const char*, ...);
|
||||
|
||||
int main ()
|
||||
{
|
||||
#if !defined test_var_3
|
||||
@ -333,7 +333,7 @@ int main()
|
||||
x
|
||||
|
||||
#elif defined test_stray_backslash2
|
||||
int printf(const char*, ...);
|
||||
|
||||
int main()
|
||||
{
|
||||
#define _S(x) #x
|
||||
@ -438,7 +438,7 @@ void func(int a, int if);
|
||||
int amain(int argc, char *argv[static argc + 1])
|
||||
{
|
||||
int i;
|
||||
int printf(const char*, ...);
|
||||
|
||||
for (i = 0; i < argc; ++i)
|
||||
printf("arg[%d] = \"%s\"\n", i, argv[i]);
|
||||
return 0;
|
||||
@ -510,10 +510,45 @@ int main()
|
||||
#ifdef test_reverse_funcargs
|
||||
# pragma comment(option, "-freverse-funcargs")
|
||||
#endif
|
||||
int printf(const char*, ...);
|
||||
|
||||
int main()
|
||||
{
|
||||
printf(" %d %d %d\n", printf("1"), printf("22"), printf("333"));
|
||||
}
|
||||
|
||||
#elif defined test_scope_1 \
|
||||
|| defined test_scope_2 \
|
||||
|| defined test_scope_3
|
||||
|
||||
struct xxx {int x[4];};
|
||||
|
||||
/* 'ee' not defined outside of function, 'i' not redefined */
|
||||
int bar(enum ee { a = 12, b = 34 } i, int(*f)(int i))
|
||||
{
|
||||
printf("bar %d %d %d\n", i, a, b);
|
||||
return 0;
|
||||
}
|
||||
/* 'xxx' not defined outside of function */
|
||||
int foo(struct xxx {int x[3];}*p)
|
||||
{
|
||||
printf("foo %d", sizeof *p);
|
||||
return p->x[3];
|
||||
}
|
||||
#ifdef test_scope_2
|
||||
/* incompatible redefinition */
|
||||
int foo(struct xxx {int x[2];}*p);
|
||||
#endif
|
||||
#ifndef test_scope_3
|
||||
enum ee { a = 1, b };
|
||||
#endif
|
||||
|
||||
struct xxx x = { 11,22,33,44 };
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf(" %d %d\n", foo(&x), sizeof (struct xxx));
|
||||
enum ee e = b;
|
||||
bar(13 + e, 0);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
[test_56_btype_excess_1]
|
||||
60_errors_and_warnings.c:2: error: too many basic types
|
||||
60_errors_and_warnings.c:4: error: too many basic types
|
||||
|
||||
[test_57_btype_excess_2]
|
||||
60_errors_and_warnings.c:5: error: too many basic types
|
||||
60_errors_and_warnings.c:6: error: too many basic types
|
||||
|
||||
[test_58_function_redefinition]
|
||||
60_errors_and_warnings.c:9: error: redefinition of 'f'
|
||||
@ -71,10 +71,10 @@
|
||||
60_errors_and_warnings.c:153: error: expression expected before ','
|
||||
|
||||
[test_invalid_2]
|
||||
60_errors_and_warnings.c:156: error: ';' expected (got "{")
|
||||
60_errors_and_warnings.c:156: error: ';' expected (got '{')
|
||||
|
||||
[test_invalid_3]
|
||||
60_errors_and_warnings.c:160: error: ',' expected (got "a")
|
||||
60_errors_and_warnings.c:160: error: ',' expected (got 'a')
|
||||
|
||||
[test_invalid_4]
|
||||
60_errors_and_warnings.c:164: error: division by zero in constant
|
||||
@ -179,7 +179,7 @@ bar : 3 ; 3
|
||||
60_errors_and_warnings.c:372: error: statement expression outside of function
|
||||
|
||||
[test_invalid_tokckill]
|
||||
60_errors_and_warnings.c:375: error: ';' expected (got "3")
|
||||
60_errors_and_warnings.c:375: error: ';' expected (got '3')
|
||||
|
||||
[test_duplicate_member]
|
||||
60_errors_and_warnings.c:381: error: duplicate member 'a'
|
||||
@ -188,7 +188,7 @@ bar : 3 ; 3
|
||||
60_errors_and_warnings.c:394: error: duplicate member 'd'
|
||||
|
||||
[test_conflicting_array_definition]
|
||||
60_errors_and_warnings.c:399: error: incompatible types for redefinition of 'array'
|
||||
60_errors_and_warnings.c:399: error: too many initializers
|
||||
|
||||
[test_incompatible_local_redef]
|
||||
60_errors_and_warnings.c:406: error: incompatible redefinition of 'localfunctype'
|
||||
@ -250,3 +250,15 @@ arg[1] = "Y"
|
||||
|
||||
[test_reverse_funcargs]
|
||||
333221 1 2 3
|
||||
|
||||
[test_scope_1]
|
||||
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
|
||||
foo 12 44 16
|
||||
bar 15 12 34
|
||||
|
||||
[test_scope_2]
|
||||
60_errors_and_warnings.c:539: error: incompatible types for redefinition of 'foo'
|
||||
|
||||
[test_scope_3]
|
||||
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
|
||||
60_errors_and_warnings.c:549: error: initialization of incomplete type
|
||||
|
||||
@ -6,66 +6,106 @@ int printf(const char*, ...);
|
||||
int main (void)
|
||||
{
|
||||
struct {
|
||||
unsigned ub:3;
|
||||
unsigned u:32;
|
||||
unsigned long long ullb:35;
|
||||
unsigned long long ull:64;
|
||||
unsigned u3:3;
|
||||
unsigned u31:31;
|
||||
unsigned u32:32;
|
||||
unsigned long ul31:31;
|
||||
unsigned long ul32:32;
|
||||
unsigned long long ull31:31;
|
||||
unsigned long long ull32:32;
|
||||
unsigned long long ull33:33;
|
||||
unsigned long long ull64:64;
|
||||
unsigned char c;
|
||||
} s = { 1, 1, 1 };
|
||||
} s = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
|
||||
promote(s.ub);
|
||||
promote(s.u);
|
||||
promote(s.ullb);
|
||||
promote(s.ull);
|
||||
promote(s.u3);
|
||||
promote(s.u31);
|
||||
promote(s.u32);
|
||||
promote(s.ul31);
|
||||
promote(s.ul32);
|
||||
promote(s.ull31);
|
||||
promote(s.ull32);
|
||||
promote(s.ull33);
|
||||
promote(s.ull64);
|
||||
promote(s.c);
|
||||
printf("\n");
|
||||
|
||||
promote((1 ? s.ub : 1));
|
||||
promote((1 ? s.u : 1));
|
||||
promote((1 ? s.ullb : 1));
|
||||
promote((1 ? s.ull : 1));
|
||||
promote((1 ? s.u3 : 1));
|
||||
promote((1 ? s.u31 : 1));
|
||||
promote((1 ? s.u32 : 1));
|
||||
promote((1 ? s.ul31 : 1));
|
||||
promote((1 ? s.ul32 : 1));
|
||||
promote((1 ? s.ull31 : 1));
|
||||
promote((1 ? s.ull32 : 1));
|
||||
promote((1 ? s.ull33 : 1));
|
||||
promote((1 ? s.ull64 : 1));
|
||||
promote((1 ? s.c : 1));
|
||||
printf("\n");
|
||||
|
||||
promote(s.ub << 1);
|
||||
promote(s.u << 1);
|
||||
promote(s.ullb << 1);
|
||||
promote(s.ull << 1);
|
||||
promote(s.u3 << 1);
|
||||
promote(s.u31 << 1);
|
||||
promote(s.u32 << 1);
|
||||
promote(s.ul31 << 1);
|
||||
promote(s.ul32 << 1);
|
||||
promote(s.ull31 << 1);
|
||||
promote(s.ull32 << 1);
|
||||
promote(s.ull33 << 1);
|
||||
promote(s.ull64 << 1);
|
||||
promote(s.c << 1);
|
||||
printf("\n");
|
||||
|
||||
promote(+s.ub);
|
||||
promote(+s.u);
|
||||
promote(+s.ullb);
|
||||
promote(+s.ull);
|
||||
promote(+s.u3);
|
||||
promote(+s.u31);
|
||||
promote(+s.u32);
|
||||
promote(+s.ul31);
|
||||
promote(+s.ul32);
|
||||
promote(+s.ull31);
|
||||
promote(+s.ull32);
|
||||
promote(+s.ull33);
|
||||
promote(+s.ull64);
|
||||
promote(+s.c);
|
||||
printf("\n");
|
||||
|
||||
promote(-s.ub);
|
||||
promote(-s.u);
|
||||
promote(-s.ullb);
|
||||
promote(-s.ull);
|
||||
promote(-s.u3);
|
||||
promote(-s.u31);
|
||||
promote(-s.u32);
|
||||
promote(-s.ul31);
|
||||
promote(-s.ul32);
|
||||
promote(-s.ull31);
|
||||
promote(-s.ull32);
|
||||
promote(-s.ull33);
|
||||
promote(-s.ull64);
|
||||
promote(-s.c);
|
||||
printf("\n");
|
||||
|
||||
promote(~s.ub);
|
||||
promote(~s.u);
|
||||
promote(~s.ullb);
|
||||
promote(~s.ull);
|
||||
promote(~s.u3);
|
||||
promote(~s.u31);
|
||||
promote(~s.u32);
|
||||
promote(~s.ul31);
|
||||
promote(~s.ul32);
|
||||
promote(~s.ull31);
|
||||
promote(~s.ull32);
|
||||
promote(~s.ull33);
|
||||
promote(~s.ull64);
|
||||
promote(~s.c);
|
||||
printf("\n");
|
||||
|
||||
promote(!s.ub);
|
||||
promote(!s.u);
|
||||
promote(!s.ullb);
|
||||
promote(!s.ull);
|
||||
promote(!s.u3);
|
||||
promote(!s.u31);
|
||||
promote(!s.u32);
|
||||
promote(!s.ul31);
|
||||
promote(!s.ul32);
|
||||
promote(!s.ull31);
|
||||
promote(!s.ull32);
|
||||
promote(!s.ull33);
|
||||
promote(!s.ull64);
|
||||
promote(!s.c);
|
||||
printf("\n");
|
||||
|
||||
promote(+(unsigned)s.ub);
|
||||
promote(-(unsigned)s.ub);
|
||||
promote(~(unsigned)s.ub);
|
||||
promote(!(unsigned)s.ub);
|
||||
promote(+(unsigned)s.u3);
|
||||
promote(-(unsigned)s.u3);
|
||||
promote(~(unsigned)s.u3);
|
||||
promote(!(unsigned)s.u3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,46 +1,81 @@
|
||||
signed : s.ub
|
||||
unsigned : s.u
|
||||
signed : s.ullb
|
||||
unsigned : s.ull
|
||||
signed : s.u3
|
||||
signed : s.u31
|
||||
unsigned : s.u32
|
||||
signed : s.ul31
|
||||
unsigned : s.ul32
|
||||
signed : s.ull31
|
||||
unsigned : s.ull32
|
||||
unsigned : s.ull33
|
||||
unsigned : s.ull64
|
||||
signed : s.c
|
||||
|
||||
signed : (1 ? s.ub : 1)
|
||||
unsigned : (1 ? s.u : 1)
|
||||
signed : (1 ? s.ullb : 1)
|
||||
unsigned : (1 ? s.ull : 1)
|
||||
signed : (1 ? s.u3 : 1)
|
||||
signed : (1 ? s.u31 : 1)
|
||||
unsigned : (1 ? s.u32 : 1)
|
||||
signed : (1 ? s.ul31 : 1)
|
||||
unsigned : (1 ? s.ul32 : 1)
|
||||
signed : (1 ? s.ull31 : 1)
|
||||
unsigned : (1 ? s.ull32 : 1)
|
||||
unsigned : (1 ? s.ull33 : 1)
|
||||
unsigned : (1 ? s.ull64 : 1)
|
||||
signed : (1 ? s.c : 1)
|
||||
|
||||
signed : s.ub << 1
|
||||
unsigned : s.u << 1
|
||||
signed : s.ullb << 1
|
||||
unsigned : s.ull << 1
|
||||
signed : s.u3 << 1
|
||||
signed : s.u31 << 1
|
||||
unsigned : s.u32 << 1
|
||||
signed : s.ul31 << 1
|
||||
unsigned : s.ul32 << 1
|
||||
signed : s.ull31 << 1
|
||||
unsigned : s.ull32 << 1
|
||||
unsigned : s.ull33 << 1
|
||||
unsigned : s.ull64 << 1
|
||||
signed : s.c << 1
|
||||
|
||||
signed : +s.ub
|
||||
unsigned : +s.u
|
||||
signed : +s.ullb
|
||||
unsigned : +s.ull
|
||||
signed : +s.u3
|
||||
signed : +s.u31
|
||||
unsigned : +s.u32
|
||||
signed : +s.ul31
|
||||
unsigned : +s.ul32
|
||||
signed : +s.ull31
|
||||
unsigned : +s.ull32
|
||||
unsigned : +s.ull33
|
||||
unsigned : +s.ull64
|
||||
signed : +s.c
|
||||
|
||||
signed : -s.ub
|
||||
unsigned : -s.u
|
||||
signed : -s.ullb
|
||||
unsigned : -s.ull
|
||||
signed : -s.u3
|
||||
signed : -s.u31
|
||||
unsigned : -s.u32
|
||||
signed : -s.ul31
|
||||
unsigned : -s.ul32
|
||||
signed : -s.ull31
|
||||
unsigned : -s.ull32
|
||||
unsigned : -s.ull33
|
||||
unsigned : -s.ull64
|
||||
signed : -s.c
|
||||
|
||||
signed : ~s.ub
|
||||
unsigned : ~s.u
|
||||
signed : ~s.ullb
|
||||
unsigned : ~s.ull
|
||||
signed : ~s.u3
|
||||
signed : ~s.u31
|
||||
unsigned : ~s.u32
|
||||
signed : ~s.ul31
|
||||
unsigned : ~s.ul32
|
||||
signed : ~s.ull31
|
||||
unsigned : ~s.ull32
|
||||
unsigned : ~s.ull33
|
||||
unsigned : ~s.ull64
|
||||
signed : ~s.c
|
||||
|
||||
signed : !s.ub
|
||||
signed : !s.u
|
||||
signed : !s.ullb
|
||||
signed : !s.ull
|
||||
signed : !s.u3
|
||||
signed : !s.u31
|
||||
signed : !s.u32
|
||||
signed : !s.ul31
|
||||
signed : !s.ul32
|
||||
signed : !s.ull31
|
||||
signed : !s.ull32
|
||||
signed : !s.ull33
|
||||
signed : !s.ull64
|
||||
signed : !s.c
|
||||
|
||||
unsigned : +(unsigned)s.ub
|
||||
unsigned : -(unsigned)s.ub
|
||||
unsigned : ~(unsigned)s.ub
|
||||
signed : !(unsigned)s.ub
|
||||
unsigned : +(unsigned)s.u3
|
||||
unsigned : -(unsigned)s.u3
|
||||
unsigned : ~(unsigned)s.u3
|
||||
signed : !(unsigned)s.u3
|
||||
|
||||
@ -102,7 +102,6 @@ GEN-ALWAYS =
|
||||
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
|
||||
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
||||
-e 's;0x[0-9A-Fa-f]\{1,\};0x?;g'
|
||||
112_backtrace.test: LEAK=ASAN_OPTIONS=detect_leaks=0
|
||||
|
||||
# this test creates two DLLs and an EXE
|
||||
113_btdll.test: T1 = \
|
||||
@ -137,7 +136,7 @@ all test tests2.all: $(filter-out $(SKIP),$(TESTS))
|
||||
@echo Test: $*...
|
||||
@$(call T1,$<) $(T3)
|
||||
|
||||
T1 = $(LEAK) $(TCC) $(FLAGS) $(T2) $(ARGS)
|
||||
T1 = $(TCC) $(FLAGS) $(T2) $(ARGS)
|
||||
T2 = $(if $(NORUN),$1 -o $(basename $@).exe && ./$(basename $@).exe,-run $1)
|
||||
T3 = $(FILTER) >$*.output 2>&1 || true \
|
||||
&& diff -Nbu $(filter %.expect,$^) $*.output \
|
||||
|
||||
@ -132,6 +132,10 @@ if %TX%==32 echo>> ..\config.h #ifdef TCC_TARGET_I386
|
||||
echo>> ..\config.h #define CONFIG_TCC_CROSSPREFIX "%PX%-"
|
||||
echo>> ..\config.h #endif
|
||||
|
||||
@rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1
|
||||
@rem %CC% -DC2STR ..\conftest.c -o c2str.exe
|
||||
@rem .\c2str.exe ../include/tccdefs.h ../tccdefs_.h
|
||||
|
||||
for %%f in (*tcc.exe *tcc.dll) do @del %%f
|
||||
|
||||
@if _%TCC_C%_==__ goto compiler_2parts
|
||||
@ -200,8 +204,9 @@ exit /B %ERRORLEVEL%
|
||||
.\tcc -B. -m%1 -c ../lib/alloca.S
|
||||
.\tcc -B. -m%1 -c ../lib/alloca-bt.S
|
||||
.\tcc -B. -m%1 -c ../lib/stdatomic.c
|
||||
.\tcc -B. -m%1 -c ../lib/atomic.S
|
||||
.\tcc -B. -m%1 -c ../lib/builtin.c
|
||||
.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o builtin.o
|
||||
.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o
|
||||
.\tcc -B. -m%1 -c ../lib/bcheck.c -o lib/%2bcheck.o -bt -I..
|
||||
.\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o
|
||||
.\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o
|
||||
|
||||
@ -376,10 +376,16 @@ extern "C" {
|
||||
_CRTIMP int __cdecl _set_error_mode(int _Mode);
|
||||
void __cdecl srand(unsigned int _Seed);
|
||||
double __cdecl strtod(const char *_Str,char **_EndPtr);
|
||||
float __cdecl strtof(const char *nptr, char **endptr);
|
||||
#if !defined __NO_ISOCEXT /* in libmingwex.a */
|
||||
#if __TINYC__
|
||||
__CRT_INLINE float __cdecl strtof (const char *p, char ** e) { return strtod(p, e); }
|
||||
__CRT_INLINE long double __cdecl strtold(const char *p, char ** e) { return strtod(p, e); }
|
||||
#else
|
||||
float __cdecl strtof (const char * __restrict__, char ** __restrict__);
|
||||
long double __cdecl strtold(const char * __restrict__, char ** __restrict__);
|
||||
#endif
|
||||
#else
|
||||
float __cdecl strtof(const char *nptr, char **endptr);
|
||||
#endif /* __NO_ISOCEXT */
|
||||
_CRTIMP double __cdecl _strtod_l(const char *_Str,char **_EndPtr,_locale_t _Locale);
|
||||
long __cdecl strtol(const char *_Str,char **_EndPtr,int _Radix);
|
||||
|
||||
@ -859,7 +859,7 @@ extern "C" {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef !defined (InterlockedAnd64)
|
||||
#ifndef InterlockedAnd64
|
||||
#define InterlockedAnd64 InterlockedAnd64_Inline
|
||||
|
||||
__CRT_INLINE LONGLONG InterlockedAnd64_Inline (LONGLONG volatile *Destination,LONGLONG Value) {
|
||||
|
||||
@ -975,8 +975,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
if (reg_param_index < REGN) {
|
||||
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LLOCAL | VT_LVAL, addr);
|
||||
gfunc_set_param(sym, addr, 1);
|
||||
} else {
|
||||
if (reg_param_index < REGN) {
|
||||
/* save arguments passed by register */
|
||||
@ -989,8 +988,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
|
||||
}
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, addr);
|
||||
gfunc_set_param(sym, addr, 0);
|
||||
}
|
||||
addr += 8;
|
||||
reg_param_index++;
|
||||
@ -1587,8 +1585,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
}
|
||||
default: break; /* nothing to be done for x86_64_mode_none */
|
||||
}
|
||||
sym_push(sym->v & ~SYM_FIELD, type,
|
||||
VT_LOCAL | VT_LVAL, param_addr);
|
||||
gfunc_set_param(sym, param_addr, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|
||||
Loading…
Reference in New Issue
Block a user