tccgen: void values, etc...

originally, this was meant to avoid 'void' values leak
to the gen-xxx.c generators which would otherwise try
to load void from/to registers.  Also catch invalid types
such as 'unsigned bool' eariler.

tccgen.c:
- expr_cond()/gexpr(): ignore VT_VOID
- gen_cast(): set float reg with static initializers to make
  backends happier with invalid input
- init_putv():
  improve static compound literal initializers
Also:
- ignore "missing prototype" and "might return no value"
  for old style K&R functions

tcc.c, libtcc.c:
- tcc_set_output_type(): return errors from loading crt1.o

tcc.h/tccpp.c:
- fix horrible longstanding mistake with sizeof SValue.tab.
  Must have place for sizeof (long double) rather than the
  target's LDOUBLE_SIZE.

tccdefs.h:
- add a fake __[u]int128_t for all platforms

arm-gen.c:
- gen_cvt_ftof() must load to reg always

arm64-gen.c:
- simplify arm64_pcs() a bit

i386/x86_64-gen.c:
- do not assume char is signed (for cross compilation arm->x86)

tccelf/macho linker message:
- instead of
      "undefined symbol 'X'"
  now say
      "unresolved reference to 'X'"
  which makes it more clear that it is a _linker_error_.

tccasm.c:
- .align/p2align: use 'nop's in exec sections
This commit is contained in:
grischka 2026-01-10 21:51:08 +01:00
parent 016087c954
commit 7e01b20362
15 changed files with 161 additions and 151 deletions

View File

@ -2283,8 +2283,9 @@ void gen_cvt_ftoi(int t)
void gen_cvt_ftof(int t) void gen_cvt_ftof(int t)
{ {
#ifdef TCC_ARM_VFP #ifdef TCC_ARM_VFP
uint32_t r = gv(RC_FLOAT);
if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) { if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
uint32_t r = vfpr(gv(RC_FLOAT)); r = vfpr(r);
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t)); o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
} }
#else #else

View File

@ -278,7 +278,6 @@ static int arm64_type_size(int t)
case VT_DOUBLE: return 3; case VT_DOUBLE: return 3;
case VT_LDOUBLE: return 4; case VT_LDOUBLE: return 4;
case VT_BOOL: return 0; case VT_BOOL: return 0;
case VT_VOID: return 0;
} }
assert(0); assert(0);
return 0; return 0;
@ -832,11 +831,10 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
int hfa = arm64_hfa(type[i], 0); int hfa = arm64_hfa(type[i], 0);
int win_vararg_float = 0; int size, align, bt;
int size, align;
if ((type[i]->t & VT_ARRAY) || bt = type[i]->t & VT_BTYPE;
(type[i]->t & VT_BTYPE) == VT_FUNC) if (bt == VT_PTR || bt == VT_FUNC)
size = align = 8; size = align = 8;
else else
size = type_size(type[i], &align); size = type_size(type[i], &align);
@ -848,13 +846,10 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
} }
#elif defined(TCC_TARGET_PE) #elif defined(TCC_TARGET_PE)
if (variadic && i >= variadic && (hfa || is_float(type[i]->t))) { if (variadic && i >= variadic) {
hfa = 0; hfa = 0;
if (is_float(type[i]->t)) { if (is_float(bt))
win_vararg_float = 1; bt = VT_INT, size = align = 8;
size = 8;
align = 8;
}
} }
#endif #endif
if (hfa) if (hfa)
@ -871,12 +866,12 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
} }
continue; continue;
} }
else if ((type[i]->t & VT_BTYPE) == VT_STRUCT) else if (bt == VT_STRUCT)
// B.4 // B.4
size = (size + 7) & ~7; size = (size + 7) & ~7;
// C.1 // C.1
if (!win_vararg_float && is_float(type[i]->t) && nv < 8) { if (is_float(bt) && nv < 8) {
a[i] = 16 + (nv++ << 1); a[i] = 16 + (nv++ << 1);
continue; continue;
} }
@ -895,24 +890,24 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
} }
// C.4 // C.4
if (hfa || (type[i]->t & VT_BTYPE) == VT_LDOUBLE) { if (hfa || bt == VT_LDOUBLE) {
ns = (ns + 7) & ~7; ns = (ns + 7) & ~7;
ns = (ns + align - 1) & -align; ns = (ns + align - 1) & -align;
} }
// C.5 // C.5
if ((type[i]->t & VT_BTYPE) == VT_FLOAT) if (bt == VT_FLOAT)
size = 8; size = 8;
// C.6 // C.6
if (!win_vararg_float && (hfa || is_float(type[i]->t))) { if (hfa || is_float(bt)) {
a[i] = ns; a[i] = ns;
ns += size; ns += size;
continue; continue;
} }
// C.7 // C.7
if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size <= 8 && nx < 8) { if (bt != VT_STRUCT && size <= 8 && nx < 8) {
a[i] = nx++ << 1; a[i] = nx++ << 1;
continue; continue;
} }
@ -922,14 +917,14 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
nx = (nx + 1) & ~1; nx = (nx + 1) & ~1;
// C.9 // C.9
if ((type[i]->t & VT_BTYPE) != VT_STRUCT && size == 16 && nx < 7) { if (bt != VT_STRUCT && size == 16 && nx < 7) {
a[i] = nx << 1; a[i] = nx << 1;
nx += 2; nx += 2;
continue; continue;
} }
// C.10 // C.10
if ((type[i]->t & VT_BTYPE) == VT_STRUCT && size <= (8 - nx) * 8) { if (bt == VT_STRUCT && size <= (8 - nx) * 8) {
a[i] = nx << 1; a[i] = nx << 1;
nx += (size + 7) >> 3; nx += (size + 7) >> 3;
continue; continue;
@ -943,7 +938,7 @@ static unsigned long arm64_pcs_aux(int variadic, int n, CType **type, unsigned l
ns = (ns + align - 1) & -align; ns = (ns + align - 1) & -align;
// C.13 // C.13
if ((type[i]->t & VT_BTYPE) == VT_STRUCT) { if (bt == VT_STRUCT) {
a[i] = ns; a[i] = ns;
ns += size; ns += size;
continue; continue;
@ -974,11 +969,11 @@ static unsigned long arm64_pcs(int variadic, int n, CType **type, unsigned long
} }
// Argument types: // Argument types:
stack = arm64_pcs_aux(variadic, n, type + 1, a + 1); stack = arm64_pcs_aux(variadic, n - 1, type + 1, a + 1);
if (0) { if (0) {
int i; int i;
for (i = 0; i <= n; i++) { for (i = 0; i < n; i++) {
if (!i) if (!i)
printf("arm64_pcs return: "); printf("arm64_pcs return: ");
else else
@ -1076,9 +1071,9 @@ ST_FUNC void gfunc_call(int nb_args)
stack = arm64_pcs( stack = arm64_pcs(
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
old_style ? -1 : old_style ? /* all args like varargs in K&R style */ -1 :
#endif #endif
var_nb_arg, nb_args, t, a); var_nb_arg, nb_args + 1, t, a);
// Allocate space for structs replaced by pointer: // Allocate space for structs replaced by pointer:
for (i = nb_args; i; i--) for (i = nb_args; i; i--)
@ -1258,7 +1253,6 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
CType *func_type = &func_sym->type; CType *func_type = &func_sym->type;
int n = 0; int n = 0;
int i = 0; int i = 0;
int pcs_n;
Sym *sym; Sym *sym;
CType **t; CType **t;
unsigned long *a; unsigned long *a;
@ -1266,35 +1260,32 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
int last_int = 0; int last_int = 0;
int last_float = 0; int last_float = 0;
int variadic = func_sym->type.ref->f.func_type == FUNC_ELLIPSIS; int variadic = func_sym->type.ref->f.func_type == FUNC_ELLIPSIS;
int var_nb_arg = n_func_args(&func_sym->type); int var_nb_arg = variadic ? n_func_args(&func_sym->type) : 0;
int c;
func_vc = 144; // offset of where x8 is stored func_vc = 144; // offset of where x8 is stored
for (sym = func_type->ref; sym; sym = sym->next) for (sym = func_type->ref; sym; sym = sym->next)
++n; ++n;
pcs_n = n - 1; #ifdef TCC_TARGET_PE
c = n + variadic; n += variadic;
t = tcc_malloc(c * sizeof(*t)); #endif
a = tcc_malloc(c * sizeof(*a));
t = tcc_malloc(n * sizeof(*t));
a = tcc_malloc(n * sizeof(*a));
for (sym = func_type->ref; sym; sym = sym->next) for (sym = func_type->ref; sym; sym = sym->next)
t[i++] = &sym->type; t[i++] = &sym->type;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
if (variadic) { if (variadic)
t[i++] = &int_type; t[i] = &int_type;
++pcs_n;
}
#endif #endif
arm64_func_va_list_stack = arm64_pcs(variadic ? var_nb_arg : 0, arm64_func_va_list_stack = arm64_pcs(var_nb_arg, n, t, a);
pcs_n, t, a);
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
if (variadic) if (variadic)
arm64_func_va_list_stack = arm64_pe_param_off(a[n]); arm64_func_va_list_stack = arm64_pe_param_off(a[n - 1]);
#endif #endif
#if !defined(TCC_TARGET_MACHO) #if !defined(TCC_TARGET_MACHO)
@ -1304,6 +1295,7 @@ ST_FUNC void gfunc_prolog(Sym *func_sym)
last_float = 4; last_float = 4;
} }
#endif #endif
if (a && a[0] == 1) if (a && a[0] == 1)
use_x8 = 1; use_x8 = 1;
for (i = 1, sym = func_type->ref->next; sym; i++, sym = sym->next) { for (i = 1, sym = func_type->ref->next; sym; i++, sym = sym->next) {
@ -1563,7 +1555,8 @@ ST_FUNC void gfunc_return(CType *func_type)
CType *t = func_type; CType *t = func_type;
unsigned long a; unsigned long a;
arm64_pcs(0, 0, &t, &a); arm64_pcs(0, 1, &t, &a);
switch (a) { switch (a) {
case -1: case -1:
break; break;

View File

@ -271,7 +271,7 @@ static void gen_modrm(int opc, int op_r2, int r, Sym *sym, int c)
} else if ((r & VT_VALMASK) == VT_LOCAL) { } else if ((r & VT_VALMASK) == VT_LOCAL) {
o(opc); o(opc);
/* currently, we use only ebp as base */ /* currently, we use only ebp as base */
if (c == (char)c) { if (c == (signed char)c) {
/* short reference */ /* short reference */
o(0x45 | op_reg); o(0x45 | op_reg);
g(c); g(c);
@ -439,7 +439,7 @@ ST_FUNC void store(int r, SValue *v)
static void gadd_sp(int val) static void gadd_sp(int val)
{ {
if (val == (char)val) { if (val == (signed char)val) {
o(0xc483); o(0xc483);
g(val); g(val);
} else { } else {
@ -774,7 +774,7 @@ ST_FUNC void gjmp_addr(int a)
{ {
int r; int r;
r = a - ind - 2; r = a - ind - 2;
if (r == (char)r) { if (r == (signed char)r) {
g(0xeb); g(0xeb);
g(r); g(r);
} else { } else {
@ -787,7 +787,7 @@ ST_FUNC void gjmp_addr(int a)
ST_FUNC void gjmp_cond_addr(int a, int op) ST_FUNC void gjmp_cond_addr(int a, int op)
{ {
int r = a - ind - 2; int r = a - ind - 2;
if (r == (char)r) if (r == (signed char)r)
g(op - 32), g(r); g(op - 32), g(r);
else else
g(0x0f), gjmp2(op - 16, r - 4); g(0x0f), gjmp2(op - 16, r - 4);
@ -830,7 +830,7 @@ ST_FUNC void gen_opi(int op)
r = gv(RC_INT); r = gv(RC_INT);
vswap(); vswap();
c = vtop->c.i; c = vtop->c.i;
if (c == (char)c) { if (c == (signed char)c) {
/* generate inc and dec for smaller code */ /* generate inc and dec for smaller code */
if ((c == 1 || c == -1) && (op == '+' || op == '-')) { if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
opc = (c == 1) ^ (op == '+'); opc = (c == 1) ^ (op == '+');

View File

@ -90,8 +90,6 @@
#define __NO_TLS 1 #define __NO_TLS 1
#define __RUNETYPE_INTERNAL 1 #define __RUNETYPE_INTERNAL 1
# if __SIZEOF_POINTER__ == 8 # if __SIZEOF_POINTER__ == 8
/* FIXME, __int128_t is used by setjump */
#define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); }
#define __SIZEOF_SIZE_T__ 8 #define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_PTRDIFF_T__ 8 #define __SIZEOF_PTRDIFF_T__ 8
#else #else
@ -142,12 +140,6 @@
#endif #endif
#define __INT32_TYPE__ int #define __INT32_TYPE__ int
#if defined __aarch64__
/* GCC's __uint128_t appears in some Linux/OSX header files. Make it a
synonym for long double to get the size and alignment right. */
#define __uint128_t long double
#endif
#if !defined _WIN32 #if !defined _WIN32
/* glibc defines. We do not support __USER_NAME_PREFIX__ */ /* glibc defines. We do not support __USER_NAME_PREFIX__ */
#define __REDIRECT(name, proto, alias) name proto __asm__ (#alias) #define __REDIRECT(name, proto, alias) name proto __asm__ (#alias)
@ -187,6 +179,12 @@
# endif # endif
#endif #endif
/* GCC's __uint128_t appears in some Linux/OSX header files.
Just make it some type with same size and alignment. */
struct __uint128__ { char x[16]; } __attribute((__aligned__(16)));
#define __int128_t struct __uint128__
#define __uint128_t struct __uint128__
/* __builtin_va_list */ /* __builtin_va_list */
#if defined __x86_64__ #if defined __x86_64__
#if !defined _WIN32 #if !defined _WIN32

View File

@ -252,7 +252,7 @@ static void *default_reallocator(void *ptr, unsigned long size)
else { else {
ptr1 = realloc(ptr, size); ptr1 = realloc(ptr, size);
if (!ptr1) { if (!ptr1) {
fprintf(stderr, "memory full\n"); fprintf(stderr, "tcc: memory full\n");
exit (1); exit (1);
} }
} }
@ -1003,9 +1003,9 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
/* paths for crt objects */ /* paths for crt objects */
tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib) if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib)
tccelf_add_crtbegin(s); tccelf_add_crtbegin(s); /* may produce errors */
#endif #endif
return 0; return s->nb_errors ? -1 : 0;
} }
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)

16
tcc.c
View File

@ -35,7 +35,7 @@ static const char help[] =
"General options:\n" "General options:\n"
" -c compile only - generate an object file\n" " -c compile only - generate an object file\n"
" -o outfile set output filename\n" " -o outfile set output filename\n"
" -run run compiled source [with custom stdin: -rstdin FILE]\n" " -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n" " -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n" " -w disable all warnings\n"
@ -105,6 +105,7 @@ static const char help2[] =
" -static link to static libraries (not recommended)\n" " -static link to static libraries (not recommended)\n"
" -dumpversion print version\n" " -dumpversion print version\n"
" -print-search-dirs print search paths\n" " -print-search-dirs print search paths\n"
" -rstdin file with -run: use 'file' as custom stdin\n"
" -dt with -run/-E: auto-define 'test_...' macros\n" " -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n" "Ignored options:\n"
" -arch -C --param -pedantic -pipe -s -traditional\n" " -arch -C --param -pedantic -pipe -s -traditional\n"
@ -354,9 +355,10 @@ redo:
set_environment(s); set_environment(s);
if (s->output_type == 0) if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE; s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type); ret = tcc_set_output_type(s, s->output_type);
if (ppfp) if (ppfp)
s->ppfp = ppfp; s->ppfp = ppfp;
if ((s->output_type == TCC_OUTPUT_MEMORY if ((s->output_type == TCC_OUTPUT_MEMORY
|| s->output_type == TCC_OUTPUT_PREPROCESS) || s->output_type == TCC_OUTPUT_PREPROCESS)
&& (s->dflag & 16)) { /* -dt option */ && (s->dflag & 16)) { /* -dt option */
@ -369,7 +371,7 @@ redo:
/* compile or add each files or library */ /* compile or add each files or library */
first_file = NULL; first_file = NULL;
do { while (0 == ret) {
struct filespec *f = s->files[n]; struct filespec *f = s->files[n];
s->filetype = f->type; s->filetype = f->type;
if (f->type & AFF_TYPE_LIB) { if (f->type & AFF_TYPE_LIB) {
@ -381,9 +383,11 @@ redo:
first_file = f->name; first_file = f->name;
ret = tcc_add_file(s, f->name); ret = tcc_add_file(s, f->name);
} }
} while (++n < s->nb_files if (++n == s->nb_files)
&& 0 == ret break;
&& (s->output_type != TCC_OUTPUT_OBJ || s->option_r)); if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r)
break;
}
if (s->do_bench) if (s->do_bench)
end_time = getclock_ms(); end_time = getclock_ms();

9
tcc.h
View File

@ -475,6 +475,9 @@ typedef struct CType {
struct Sym *ref; struct Sym *ref;
} CType; } CType;
/* long double words on host(!) platform */
#define LDOUBLE_WORDS ((sizeof(long double)+3)/4)
/* constant value */ /* constant value */
typedef union CValue { typedef union CValue {
long double ld; long double ld;
@ -485,7 +488,7 @@ typedef union CValue {
char *data; char *data;
int size; int size;
} str; } str;
int tab[LDOUBLE_SIZE/4]; int tab[LDOUBLE_WORDS];
} CValue; } CValue;
/* value on stack */ /* value on stack */
@ -1446,8 +1449,8 @@ ST_DATA int nocode_wanted; /* true if no code generation wanted for an expressio
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */ ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic */ ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc; ST_DATA int func_vc; /* stack address for implicit struct return storage */
ST_DATA int func_ind; ST_DATA int func_ind; /* function start address */
ST_DATA const char *funcname; ST_DATA const char *funcname;
ST_FUNC void tccgen_init(TCCState *s1); ST_FUNC void tccgen_init(TCCState *s1);

View File

@ -510,7 +510,7 @@ static void pop_section(TCCState *s1)
static void asm_parse_directive(TCCState *s1, int global) static void asm_parse_directive(TCCState *s1, int global)
{ {
int n, offset, v, size, tok1; int n, offset, v, size, tok1, c;
Section *sec; Section *sec;
uint8_t *ptr; uint8_t *ptr;
@ -540,18 +540,25 @@ static void asm_parse_directive(TCCState *s1, int global)
/* the section must have a compatible alignment */ /* the section must have a compatible alignment */
if (sec->sh_addralign < n) if (sec->sh_addralign < n)
sec->sh_addralign = n; sec->sh_addralign = n;
c = sec->sh_flags & SHF_EXECINSTR;
} else { } else {
if (n < 0) if (n < 0)
n = 0; n = 0;
size = n; size = n, c = 0;
} }
v = 0; v = 0;
if (tok == ',') { if (tok == ',') {
next(); next();
v = asm_int_expr(s1); v = asm_int_expr(s1), c = 0;
} }
zero_pad: zero_pad:
if ((uint64_t)ind + size >= 1<<30)
tcc_error("too much data");
if (sec->sh_type != SHT_NOBITS) { if (sec->sh_type != SHT_NOBITS) {
if (c) {
gen_fill_nops(size);
break;
}
sec->data_offset = ind; sec->data_offset = ind;
ptr = section_ptr_add(sec, size); ptr = section_ptr_add(sec, size);
memset(ptr, v, size); memset(ptr, v, size);
@ -706,11 +713,9 @@ static void asm_parse_directive(TCCState *s1, int global)
expect("constant or same-section symbol"); expect("constant or same-section symbol");
n += esym->st_value; n += esym->st_value;
} }
if (n < 0 || n > 0x100000)
tcc_error(".org out of range");
if (n < ind) if (n < ind)
tcc_error("attempt to .org backwards"); tcc_error("attempt to .org backwards");
v = 0; v = c = 0;
size = n - ind; size = n - ind;
goto zero_pad; goto zero_pad;
} }

View File

@ -1106,7 +1106,7 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
if (sym_bind == STB_WEAK) if (sym_bind == STB_WEAK)
sym->st_value = 0; sym->st_value = 0;
else else
tcc_error_noabort("undefined symbol '%s'", name); tcc_error_noabort("unresolved reference to '%s'", name);
} else if (sh_num < SHN_LORESERVE) { } else if (sh_num < SHN_LORESERVE) {
/* add section base */ /* add section base */
@ -2074,7 +2074,7 @@ static void bind_exe_dynsyms(TCCState *s1, int is_PIE)
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
!strcmp(name, "_fp_hw")) { !strcmp(name, "_fp_hw")) {
} else { } else {
tcc_error_noabort("undefined symbol '%s'", name); tcc_error_noabort("unresolved reference to '%s'", name);
} }
} }
} }
@ -2105,7 +2105,7 @@ static void bind_libs_dynsyms(TCCState *s1)
if (esym->st_shndx == SHN_UNDEF) { if (esym->st_shndx == SHN_UNDEF) {
/* weak symbols can stay undefined */ /* weak symbols can stay undefined */
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
tcc_warning("undefined dynamic symbol '%s'", name); tcc_warning("unresolved dynamic reference to '%s'", name);
} }
} }
} }
@ -3301,6 +3301,8 @@ invalid:
continue; continue;
if (sh->sh_type != s->sh_type if (sh->sh_type != s->sh_type
&& strcmp (s->name, ".eh_frame") && strcmp (s->name, ".eh_frame")
/* some crt1.o seem to have two ".note.GNU-stack" (SHT_NOTE & SHT_PROGBITS) */
&& strcmp (s->name, ".note.GNU-stack")
) { ) {
tcc_error_noabort("section type conflict: %s %02x <> %02x", s->name, sh->sh_type, s->sh_type); tcc_error_noabort("section type conflict: %s %02x <> %02x", s->name, sh->sh_type, s->sh_type);
goto the_end; goto the_end;

View File

@ -70,8 +70,9 @@ ST_DATA int nocode_wanted; /* no code generation wanted */
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */ ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
ST_DATA int func_vc; ST_DATA int func_vc; /* stack address for implicit struct return storage */
ST_DATA int func_ind; ST_DATA int func_ind; /* function start address */
static int func_old;
ST_DATA const char *funcname; ST_DATA const char *funcname;
ST_DATA CType int_type, func_old_type, char_type, char_pointer_type; ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;
static CString initstr; static CString initstr;
@ -1385,7 +1386,7 @@ static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
/* make sure that type->ref is on global stack */ /* make sure that type->ref is on global stack */
move_ref_to_global(s); move_ref_to_global(s);
/* put into local scope */ /* put into local scope */
s = sym_copy(s, &local_stack); sym_copy(s, &local_stack);
} }
return s; return s;
} }
@ -1906,6 +1907,8 @@ ST_FUNC int gv(int rc)
#endif #endif
bt = vtop->type.t & VT_BTYPE; bt = vtop->type.t & VT_BTYPE;
if (bt == VT_VOID || bt == VT_STRUCT) /* should not happen */
return vtop->r;
#ifdef TCC_TARGET_RISCV64 #ifdef TCC_TARGET_RISCV64
/* XXX mega hack */ /* XXX mega hack */
@ -2929,7 +2932,8 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
type.ref = NULL; type.ref = NULL;
if (bt1 == VT_VOID || bt2 == VT_VOID) { if (bt1 == VT_VOID || bt2 == VT_VOID) {
ret = op == '?' ? 1 : 0; if (op != '?')
tcc_error("operation on void value");
/* NOTE: as an extension, we accept void on only one side */ /* NOTE: as an extension, we accept void on only one side */
type.t = VT_VOID; type.t = VT_VOID;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) { } else if (bt1 == VT_PTR || bt2 == VT_PTR) {
@ -3176,7 +3180,7 @@ op_err:
} }
// Make sure that we have converted to an rvalue: // Make sure that we have converted to an rvalue:
if (vtop->r & VT_LVAL) if (vtop->r & VT_LVAL)
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT); gv(RC_TYPE(vtop->type.t));
} }
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM #if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM
@ -3281,8 +3285,10 @@ again:
df = is_float(dbt); df = is_float(dbt);
dbt_bt = dbt & VT_BTYPE; dbt_bt = dbt & VT_BTYPE;
sbt_bt = sbt & VT_BTYPE; sbt_bt = sbt & VT_BTYPE;
if (dbt_bt == VT_VOID) if (dbt_bt == VT_VOID) {
vtop->r = vtop->r2 = VT_CONST;
goto done; goto done;
}
if (sbt_bt == VT_VOID) { if (sbt_bt == VT_VOID) {
error: error:
cast_error(&vtop->type, type); cast_error(&vtop->type, type);
@ -3361,8 +3367,11 @@ error:
} }
/* cannot generate code for global or static initializers */ /* cannot generate code for global or static initializers */
if (nocode_wanted & DATA_ONLY_WANTED) if (nocode_wanted & DATA_ONLY_WANTED) {
if (df)
vtop->r = get_reg(RC_FLOAT); /* don't confuse backends */
goto done; goto done;
}
/* non constant case: generate code */ /* non constant case: generate code */
if (dbt == VT_BOOL) { if (dbt == VT_BOOL) {
@ -4753,6 +4762,8 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
} else { } else {
if (bt != -1 || (st != -1 && u != VT_INT)) if (bt != -1 || (st != -1 && u != VT_INT))
goto tmbt; goto tmbt;
if ((t & VT_DEFSIGN) && (u == VT_VOID || u > VT_LLONG))
goto tmbt;
bt = u; bt = u;
} }
if (u != VT_INT) if (u != VT_INT)
@ -6112,6 +6123,7 @@ special_math_val:
tcc_error("'%s' undeclared", name); tcc_error("'%s' undeclared", name);
/* for simple function calls, we tolerate undeclared /* for simple function calls, we tolerate undeclared
external reference to int() function */ external reference to int() function */
if (!func_old)
tcc_warning_c(warn_implicit_function_declaration)( tcc_warning_c(warn_implicit_function_declaration)(
"implicit declaration of function '%s'", name); "implicit declaration of function '%s'", name);
s = external_global_sym(t, &func_old_type); s = external_global_sym(t, &func_old_type);
@ -6660,7 +6672,7 @@ static void expr_cond(void)
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
that `(expr ? a : b).mem` does not error with "lvalue expected" */ that `(expr ? a : b).mem` does not error with "lvalue expected" */
islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE); islv = VT_STRUCT == (type.t & VT_BTYPE);
/* now we convert second operand */ /* now we convert second operand */
if (c != 1) { if (c != 1) {
@ -6668,8 +6680,7 @@ static void expr_cond(void)
if (islv) { if (islv) {
mk_pointer(&vtop->type); mk_pointer(&vtop->type);
gaddrof(); gaddrof();
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) }
gaddrof();
} }
rc = RC_TYPE(type.t); rc = RC_TYPE(type.t);
@ -6680,6 +6691,7 @@ static void expr_cond(void)
tt = r2 = 0; tt = r2 = 0;
if (c < 0) { if (c < 0) {
if (type.t != VT_VOID)
r2 = gv(rc); r2 = gv(rc);
tt = gjmp(0); tt = gjmp(0);
} }
@ -6695,14 +6707,15 @@ static void expr_cond(void)
if (islv) { if (islv) {
mk_pointer(&vtop->type); mk_pointer(&vtop->type);
gaddrof(); gaddrof();
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) }
gaddrof();
} }
if (c < 0) { if (c < 0) {
if (type.t != VT_VOID) {
r1 = gv(rc); r1 = gv(rc);
move_reg(r2, r1, islv ? VT_PTR : type.t); move_reg(r2, r1, islv ? VT_PTR : type.t);
vtop->r = r2; vtop->r = r2;
}
gsym(tt); gsym(tt);
} }
@ -6745,6 +6758,7 @@ ST_FUNC void gexpr(void)
/* make builtin_constant_p((1,2)) return 0 (like on gcc) */ /* make builtin_constant_p((1,2)) return 0 (like on gcc) */
if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED) if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED)
if (vtop->type.t != VT_VOID && (vtop->type.t & VT_BTYPE) != VT_STRUCT)
gv(RC_TYPE(vtop->type.t)); gv(RC_TYPE(vtop->type.t));
} }
} }
@ -6855,11 +6869,10 @@ static void check_func_return(void)
{ {
if ((func_vt.t & VT_BTYPE) == VT_VOID) if ((func_vt.t & VT_BTYPE) == VT_VOID)
return; return;
if (!strcmp (funcname, "main") if ((!strcmp(funcname, "main") || func_old)
&& (func_vt.t & VT_BTYPE) == VT_INT) { && (func_vt.t & VT_BTYPE) == VT_INT) {
/* main returns 0 by default */ /* main returns 0 by default */
vpushi(0); vpushi(0);
gen_assign_cast(&func_vt);
gfunc_return(&func_vt); gfunc_return(&func_vt);
} else { } else {
tcc_warning("function might return no value: '%s'", funcname); tcc_warning("function might return no value: '%s'", funcname);
@ -7242,6 +7255,8 @@ again:
tcc_warning("void function returns a value"); tcc_warning("void function returns a value");
vtop--; vtop--;
} }
} else if (b && func_old && (func_vt.t & VT_BTYPE) == VT_INT) {
vpushi(0);
} else if (b) { } else if (b) {
tcc_warning("'return' with no value"); tcc_warning("'return' with no value");
b = 0; b = 0;
@ -7806,21 +7821,12 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
ptr = sec->data + c; ptr = sec->data + c;
val = vtop->c.i; val = vtop->c.i;
/* XXX: make code faster ? */ if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) && && vtop->sym->v >= SYM_FIRST_ANOM
vtop->sym->v >= SYM_FIRST_ANOM && && ((vtop->r & VT_LVAL) /* compound literal */
/* XXX This rejects compound literals like || bt == VT_STRUCT /* designator */
'(void *){ptr}'. The problem is that '&sym' is )) {
represented the same way, which would be ruled out /* memcpy stuff over. */
by the SYM_FIRST_ANOM check above, but also '"string"'
in 'char *p = "string"' is represented the same
with the type being VT_PTR and the symbol being an
anonymous one. That is, there's no difference in vtop
between '(void *){x}' and '&(void *){x}'. Ignore
pointer typed entities here. Hopefully no real code
will ever use compound literals with scalar type. */
(vtop->type.t & VT_BTYPE) != VT_PTR) {
/* These come from compound literals, memcpy stuff over. */
Section *ssec; Section *ssec;
ElfSym *esym; ElfSym *esym;
ElfW_Rel *rel; ElfW_Rel *rel;
@ -8072,6 +8078,8 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
} }
} }
} }
if (tok == ',' && !no_oblock) /* static const char s[] = { "123", }; */
next();
} else { } else {
do_init_array: do_init_array:
@ -8528,6 +8536,7 @@ static void gen_function(Sym *sym)
func_ind = ind; func_ind = ind;
func_vt = sym->type.ref->type; func_vt = sym->type.ref->type;
func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS; func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS;
func_old = sym->type.ref->f.func_type == FUNC_OLD;
/* NOTE: we patch the symbol size later */ /* NOTE: we patch the symbol size later */
put_extern_sym(sym, cur_text_section, ind, 0); put_extern_sym(sym, cur_text_section, ind, 0);

View File

@ -702,7 +702,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti)); goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
if (sym->st_shndx == SHN_UNDEF) if (sym->st_shndx == SHN_UNDEF)
tcc_error("undefined local symbo: '%s'", tcc_error("unresolved local reference to '%s'",
(char *) symtab_section->link->data + sym->st_name); (char *) symtab_section->link->data + sym->st_name);
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL; goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
} else { } else {
@ -859,7 +859,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti)); goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
if (sym->st_shndx == SHN_UNDEF) if (sym->st_shndx == SHN_UNDEF)
tcc_error("undefined local symbo: '%s'", tcc_error("unresolved local reference to '%s'",
(char *) symtab_section->link->data + sym->st_name); (char *) symtab_section->link->data + sym->st_name);
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL; goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
} else { } else {
@ -1042,7 +1042,7 @@ static int check_symbols(TCCState *s1, struct macho *mo)
sym->st_shndx = SHN_FROMDLL; sym->st_shndx = SHN_FROMDLL;
continue; continue;
} }
tcc_error_noabort("undefined symbol '%s'", name); tcc_error_noabort("unresolved reference to '%s'", name);
ret = -1; ret = -1;
} }
} }

30
tccpp.c
View File

@ -987,11 +987,7 @@ static inline int tok_size(const int *p)
case TOK_CULLONG: case TOK_CULLONG:
return 1 + 2; return 1 + 2;
case TOK_CLDOUBLE: case TOK_CLDOUBLE:
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE return 1 + LDOUBLE_WORDS;
return 1 + 8 / 4;
#else
return 1 + LDOUBLE_SIZE / 4;
#endif
default: default:
return 1 + 0; return 1 + 0;
} }
@ -1130,22 +1126,12 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
str[len++] = cv->tab[1]; str[len++] = cv->tab[1];
break; break;
case TOK_CLDOUBLE: case TOK_CLDOUBLE:
#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
#elif LDOUBLE_SIZE == 12
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
str[len++] = cv->tab[2];
#elif LDOUBLE_SIZE == 16
str[len++] = cv->tab[0]; str[len++] = cv->tab[0];
str[len++] = cv->tab[1]; str[len++] = cv->tab[1];
if (LDOUBLE_WORDS >= 3)
str[len++] = cv->tab[2]; str[len++] = cv->tab[2];
if (LDOUBLE_WORDS >= 4)
str[len++] = cv->tab[3]; str[len++] = cv->tab[3];
#else
#error add long double size support
#endif
break;
default: default:
break; break;
} }
@ -1219,15 +1205,7 @@ static inline void tok_get(int *t, const int **pp, CValue *cv)
n = 2; n = 2;
goto copy; goto copy;
case TOK_CLDOUBLE: case TOK_CLDOUBLE:
#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE n = LDOUBLE_WORDS;
n = 2;
#elif LDOUBLE_SIZE == 12
n = 3;
#elif LDOUBLE_SIZE == 16
n = 4;
#else
# error add long double size support
#endif
copy: copy:
do do
*tab++ = *p++; *tab++ = *p++;

View File

@ -1465,17 +1465,37 @@ static int tab_reinit[10];
static int tentative_ar[]; static int tentative_ar[];
static int tentative_ar[] = {1,2,3}; static int tentative_ar[] = {1,2,3};
//int cinit1; /* a global variable can be defined several times without error ! */ int cinit1; /* a global variable can be defined several times without error ! */
int cinit1;
int cinit1; int cinit1;
int cinit1 = 0; int cinit1 = 0;
int *cinit2 = (int []){3, 2, 1}; int *cinit2 = (int []){3, 2, 1};
uintptr_t cinit3 = (uintptr_t)"AA";
char const * const cinit8[] = { [0 ... 1] = "BB", [2 ... 4] = "CC" };
void *cinit52 = &(void*){ (void*) 52 };
#if __TINYC__ || __GNUC__ >= 6
int cinit4 = (int){44};
void *cinit51 = (void*){ (void*) 51 };
struct _c6 { int a,b; } cinit6 = (struct _c6){61,62}, *cinit7 = &(struct _c6){71,72};
#else
int cinit4 = 44;
void *cinit51 = (void*)51;
struct _c6 { int a,b; } cinit6 = { 61,62 }, cinit70 = {71,72}, *cinit7 = &cinit70;
#endif
void compound_literal_test(void) void compound_literal_test(void)
{ {
int *p, i; int *p, i;
char *q, *q3; char *q, *q3;
printf("cinit3 : %s\n", cinit3);
printf("cinit4 : %d\n", cinit4);
printf("cinit51 : %d\n", (int)cinit51);
printf("cinit52 : %d\n", *(int*)cinit52);
printf("cinit6 : %d %d\n", cinit6.a, cinit6.b);
printf("cinit7 : %d %d\n", cinit7->a, cinit7->b);
printf("cinit8 : %s %s %s %s %s\n", cinit8[0], cinit8[1], cinit8[2], cinit8[3], cinit8[4]);
p = (int []){1, 2, 3}; p = (int []){1, 2, 3};
for(i=0;i<3;i++) for(i=0;i<3;i++)
printf(" %d", p[i]); printf(" %d", p[i]);

View File

@ -421,7 +421,7 @@ int f() { return v(); }
#elif defined test_switch_W4 #elif defined test_switch_W4
#pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror") #pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror")
#endif #endif
void func() void func(void)
{ {
char *ccp = "123"; char *ccp = "123";
fink(); fink();

View File

@ -314,7 +314,7 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got)
} }
} else if ((r & VT_VALMASK) == VT_LOCAL) { } else if ((r & VT_VALMASK) == VT_LOCAL) {
/* currently, we use only ebp as base */ /* currently, we use only ebp as base */
if (c == (char)c) { if (c == (signed char)c) {
/* short reference */ /* short reference */
o(0x45 | op_reg); o(0x45 | op_reg);
g(c); g(c);
@ -436,8 +436,7 @@ void load(int r, SValue *sv)
b = 0xdb, r = 5; /* fldt */ b = 0xdb, r = 5; /* fldt */
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) { } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
b = 0xbe0f; /* movsbl */ b = 0xbe0f; /* movsbl */
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED) || } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
(ft & VT_TYPE) == (VT_BOOL | VT_UNSIGNED)) {
b = 0xb60f; /* movzbl */ b = 0xb60f; /* movzbl */
} else if ((ft & VT_TYPE) == VT_SHORT) { } else if ((ft & VT_TYPE) == VT_SHORT) {
b = 0xbf0f; /* movswl */ b = 0xbf0f; /* movswl */
@ -532,7 +531,6 @@ void load(int r, SValue *sv)
o(0x44 + REG_VALUE(r)*8); /* %xmmN */ o(0x44 + REG_VALUE(r)*8); /* %xmmN */
o(0xf024); o(0xf024);
} else { } else {
if (!nocode_wanted)
assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
if ((ft & VT_BTYPE) == VT_FLOAT) { if ((ft & VT_BTYPE) == VT_FLOAT) {
o(0x100ff3); o(0x100ff3);
@ -543,7 +541,6 @@ void load(int r, SValue *sv)
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8); o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
} }
} else if (r == TREG_ST0) { } else if (r == TREG_ST0) {
if (!nocode_wanted)
assert((v >= TREG_XMM0) && (v <= TREG_XMM7)); assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
/* gen_cvt_ftof(VT_LDOUBLE); */ /* gen_cvt_ftof(VT_LDOUBLE); */
/* movsd %xmmN,-0x10(%rsp) */ /* movsd %xmmN,-0x10(%rsp) */
@ -749,7 +746,7 @@ static int arg_prepare_reg(int idx) {
static void gen_offs_sp(int b, int r, int d) static void gen_offs_sp(int b, int r, int d)
{ {
orex(1,0,r & 0x100 ? 0 : r, b); orex(1,0,r & 0x100 ? 0 : r, b);
if (d == (char)d) { if (d == (signed char)d) {
o(0x2444 | (REG_VALUE(r) << 3)); o(0x2444 | (REG_VALUE(r) << 3));
g(d); g(d);
} else { } else {
@ -1052,7 +1049,7 @@ void gfunc_epilog(void)
static void gadd_sp(int val) static void gadd_sp(int val)
{ {
if (val == (char)val) { if (val == (signed char)val) {
o(0xc48348); o(0xc48348);
g(val); g(val);
} else { } else {
@ -1635,7 +1632,7 @@ void gjmp_addr(int a)
{ {
int r; int r;
r = a - ind - 2; r = a - ind - 2;
if (r == (char)r) { if (r == (signed char)r) {
g(0xeb); g(0xeb);
g(r); g(r);
} else { } else {
@ -1704,7 +1701,7 @@ void gen_opi(int op)
r = gv(RC_INT); r = gv(RC_INT);
vswap(); vswap();
c = vtop->c.i; c = vtop->c.i;
if (c == (char)c) { if (c == (signed char)c) {
/* XXX: generate inc and dec for smaller code ? */ /* XXX: generate inc and dec for smaller code ? */
orex(ll, r, 0, 0x83); orex(ll, r, 0, 0x83);
o(0xc0 | (opc << 3) | REG_VALUE(r)); o(0xc0 | (opc << 3) | REG_VALUE(r));