mirror of
https://github.com/TinyCC/tinycc.git
synced 2026-02-04 21:01:36 +00:00
tccgen.c: fix two scope problems
... see tests Also: - tccgen.c: cleanup _Generic a little - libtcc.c: cleanup mem-debug a little - arm-link.c: read/write only once - tcc.h: another fix for clang offsetof - tccdbg.c: * stabs: handle forward struct/enum decls * stabs: fix anonymous struct members (must not have a .L123 name) * avoid strncpy()
This commit is contained in:
17
arm-link.c
17
arm-link.c
@@ -194,17 +194,18 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
case R_ARM_PLT32:
|
||||
{
|
||||
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
|
||||
x = read32le(ptr) & 0xffffff;
|
||||
unsigned code = read32le(ptr);
|
||||
x = code & 0x00ffffff;
|
||||
#ifdef DEBUG_RELOC
|
||||
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
|
||||
#endif
|
||||
write32le(ptr, read32le(ptr) & 0xff000000);
|
||||
if (x & 0x800000)
|
||||
x -= 0x1000000;
|
||||
x = (unsigned) x << 2;
|
||||
code &= 0xff000000;
|
||||
x <<= 2;
|
||||
if (x & 0x2000000)
|
||||
x -= 0x4000000;
|
||||
blx_avail = (CONFIG_TCC_CPUVER >= 5);
|
||||
is_thumb = val & 1;
|
||||
is_bl = read32le(ptr) >> 24 == 0xeb;
|
||||
is_bl = code == 0xeb000000;
|
||||
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
|
||||
x += val - addr;
|
||||
#ifdef DEBUG_RELOC
|
||||
@@ -220,9 +221,9 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
/* Only reached if blx is avail and it is a call */
|
||||
if (is_thumb) {
|
||||
x |= h << 24;
|
||||
write32le(ptr, 0xfa << 24); /* bl -> blx */
|
||||
code = 0xfa000000; /* bl -> blx */
|
||||
}
|
||||
write32le(ptr, read32le(ptr) | x);
|
||||
write32le(ptr, code | x);
|
||||
}
|
||||
return;
|
||||
/* Since these relocations only concern Thumb-2 and blx instruction was
|
||||
|
||||
7
libtcc.c
7
libtcc.c
@@ -326,7 +326,7 @@ struct mem_debug_header {
|
||||
struct mem_debug_header *prev;
|
||||
struct mem_debug_header *next;
|
||||
int line_num;
|
||||
char file_name[MEM_DEBUG_FILE_LEN + 1];
|
||||
char file_name[MEM_DEBUG_FILE_LEN];
|
||||
unsigned magic2;
|
||||
ALIGNED(16) unsigned char magic3[4];
|
||||
};
|
||||
@@ -367,9 +367,8 @@ PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line)
|
||||
header->size = size;
|
||||
write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3);
|
||||
header->line_num = line;
|
||||
ofs = strlen(file) - MEM_DEBUG_FILE_LEN;
|
||||
strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN);
|
||||
header->file_name[MEM_DEBUG_FILE_LEN] = 0;
|
||||
ofs = strlen(file) + 1 - MEM_DEBUG_FILE_LEN;
|
||||
strcpy(header->file_name, file + (ofs > 0 ? ofs : 0));
|
||||
WAIT_SEM(&mem_sem);
|
||||
header->next = mem_debug_chain;
|
||||
header->prev = NULL;
|
||||
|
||||
5
tcc.c
5
tcc.c
@@ -323,13 +323,12 @@ redo:
|
||||
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||
print_search_dirs(s);
|
||||
}
|
||||
if (opt < 0) err:
|
||||
ret = 1, opt = -1;
|
||||
if (opt) {
|
||||
if (opt < 0) err:
|
||||
ret = 1;
|
||||
tcc_delete(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (s->nb_files == 0) {
|
||||
tcc_error_noabort("no input files");
|
||||
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
|
||||
8
tcc.h
8
tcc.h
@@ -95,13 +95,13 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
# define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef offsetof
|
||||
#ifdef __clang__ // clang -fsanitize compains about: NULL+value
|
||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
||||
#endif
|
||||
|
||||
#ifndef offsetof
|
||||
#else
|
||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef countof
|
||||
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
|
||||
@@ -1074,7 +1074,7 @@ struct filespec {
|
||||
|
||||
#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT)
|
||||
#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */
|
||||
#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */
|
||||
#define VT_ENUM_VAL (4 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */
|
||||
|
||||
#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM)
|
||||
#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL)
|
||||
|
||||
93
tccdbg.c
93
tccdbg.c
@@ -1675,16 +1675,20 @@ static void tcc_debug_check_forw(TCCState *s1, Sym *t, int debug_type)
|
||||
}
|
||||
}
|
||||
|
||||
static void stabs_struct_complete(TCCState *s1, CType *t);
|
||||
|
||||
ST_FUNC void tcc_debug_fix_forw(TCCState *s1, CType *t)
|
||||
{
|
||||
if (!(s1->do_debug & 2))
|
||||
return;
|
||||
|
||||
if (0 == s1->dwarf) {
|
||||
stabs_struct_complete(s1, t);
|
||||
return;
|
||||
}
|
||||
if ((t->t & VT_BTYPE) == VT_STRUCT && t->ref->c != -1) {
|
||||
int i, j, debug_type, g = check_global(t->ref);
|
||||
int *n_forw_hash;
|
||||
struct _debug_forw_hash **forw_hash;
|
||||
|
||||
forw_hash = g ? &debug_forw_hash_global : &debug_forw_hash_local;
|
||||
n_forw_hash = g ? &n_debug_forw_hash_global : &n_debug_forw_hash_local;
|
||||
for (i = 0; i < *n_forw_hash; i++)
|
||||
@@ -1722,14 +1726,46 @@ static int tcc_debug_add(TCCState *s1, Sym *t, int dwarf)
|
||||
return offset;
|
||||
}
|
||||
|
||||
#define STRUCT_NODEBUG(s) \
|
||||
(s->a.nodebug || \
|
||||
((s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM && \
|
||||
((s->type.t & VT_BTYPE) == VT_BYTE || \
|
||||
(s->type.t & VT_BTYPE) == VT_BOOL || \
|
||||
(s->type.t & VT_BTYPE) == VT_SHORT || \
|
||||
(s->type.t & VT_BTYPE) == VT_INT || \
|
||||
(s->type.t & VT_BTYPE) == VT_LLONG)))
|
||||
static int STRUCT_NODEBUG(Sym *s)
|
||||
{
|
||||
return
|
||||
(s->a.nodebug ||
|
||||
((s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM &&
|
||||
((s->type.t & VT_BTYPE) == VT_BYTE ||
|
||||
(s->type.t & VT_BTYPE) == VT_BOOL ||
|
||||
(s->type.t & VT_BTYPE) == VT_SHORT ||
|
||||
(s->type.t & VT_BTYPE) == VT_INT ||
|
||||
(s->type.t & VT_BTYPE) == VT_LLONG)));
|
||||
}
|
||||
|
||||
static int stabs_struct_find(TCCState *s1, Sym *t, int *p_id)
|
||||
{
|
||||
/* A struct/enum has a ref to its type but that type has no ref.
|
||||
So we can (ab)use it for some info. Here:
|
||||
s->c : stabs type id
|
||||
s->r : already defined in stabs */
|
||||
Sym *s = t->type.ref;
|
||||
/*
|
||||
if (s && s->v != (SYM_FIELD|0x00DEBBED)) {
|
||||
tcc_error_noabort("tccdbg: internal error: %s", get_tok_str(t->v, 0));
|
||||
if (p_id)
|
||||
*p_id = 0;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
if (NULL == p_id)
|
||||
return s && !s->r && t->c >= 0;
|
||||
if (NULL == s) {
|
||||
/* just use global_stack always */
|
||||
s = sym_push2(&global_stack, SYM_FIELD|0x00DEBBED, 0, ++debug_next_type);
|
||||
t->type.ref = s;
|
||||
}
|
||||
*p_id = s->c;
|
||||
if (s->r || t->c < 0) /* already defined or still incomplete */
|
||||
return 0;
|
||||
s->r = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
{
|
||||
@@ -1750,9 +1786,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
}
|
||||
if ((type & VT_BTYPE) == VT_STRUCT) {
|
||||
t = t->type.ref;
|
||||
debug_type = tcc_debug_find(s1, t, 0);
|
||||
if (debug_type == -1) {
|
||||
debug_type = tcc_debug_add(s1, t, 0);
|
||||
if (stabs_struct_find(s1, t, &debug_type)) {
|
||||
cstr_new (&str);
|
||||
cstr_printf (&str, "%s:T%d=%c%d",
|
||||
(t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM
|
||||
@@ -1760,15 +1794,16 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
debug_type,
|
||||
IS_UNION (t->type.t) ? 'u' : 's',
|
||||
t->c);
|
||||
|
||||
while (t->next) {
|
||||
int pos, size, align;
|
||||
|
||||
t = t->next;
|
||||
if (STRUCT_NODEBUG(t))
|
||||
continue;
|
||||
tcc_debug_check_forw(s1, t, -1);
|
||||
cstr_printf (&str, "%s:",
|
||||
get_tok_str(t->v, NULL));
|
||||
(t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM
|
||||
? "" : get_tok_str(t->v, NULL)
|
||||
);
|
||||
tcc_get_debug_info (s1, t, &str);
|
||||
if (t->type.t & VT_BITFIELD) {
|
||||
pos = t->c * 8 + BIT_POS(t->type.t);
|
||||
@@ -1787,10 +1822,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
}
|
||||
else if (IS_ENUM(type)) {
|
||||
Sym *e = t = t->type.ref;
|
||||
|
||||
debug_type = tcc_debug_find(s1, t, 0);
|
||||
if (debug_type == -1) {
|
||||
debug_type = tcc_debug_add(s1, t, 0);
|
||||
if (stabs_struct_find(s1, t, &debug_type)) {
|
||||
cstr_new (&str);
|
||||
cstr_printf (&str, "%s:T%d=e",
|
||||
(t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM
|
||||
@@ -1817,6 +1849,10 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
if (debug_type > N_DEFAULT_DEBUG)
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == result) /* from stabs_struct_complete() */
|
||||
return;
|
||||
|
||||
if (n > 0)
|
||||
cstr_printf (result, "%d=", ++debug_next_type);
|
||||
t = s;
|
||||
@@ -1836,12 +1872,19 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
|
||||
}
|
||||
else
|
||||
break;
|
||||
tcc_debug_check_forw(s1, t, -1);
|
||||
t = t->type.ref;
|
||||
}
|
||||
cstr_printf (result, "%d", debug_type);
|
||||
}
|
||||
|
||||
static void stabs_struct_complete(TCCState *s1, CType *t)
|
||||
{
|
||||
if (stabs_struct_find(s1, t->ref, NULL)) {
|
||||
Sym s = {0}; s.type = *t;
|
||||
tcc_get_debug_info(s1, &s, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
|
||||
{
|
||||
int type;
|
||||
@@ -1993,7 +2036,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
|
||||
dwarf_data1(dwarf_info_section, DWARF_ABBREV_BASE_TYPE);
|
||||
dwarf_uleb128(dwarf_info_section, default_debug[i - 1].size);
|
||||
dwarf_data1(dwarf_info_section, default_debug[i - 1].encoding);
|
||||
strncpy(name, default_debug[i - 1].name, sizeof(name) -1);
|
||||
pstrcpy(name, sizeof name, default_debug[i - 1].name);
|
||||
*strchr(name, ':') = 0;
|
||||
dwarf_strp(dwarf_info_section, name);
|
||||
dwarf_info.base_type_used[i - 1] = debug_type;
|
||||
@@ -2404,7 +2447,6 @@ ST_FUNC void tcc_debug_extern_sym(TCCState *s1, Sym *sym, int sh_num, int sym_bi
|
||||
sym_bind == STB_GLOBAL ? 'G' : func_ind != -1 ? 'V' : 'S'
|
||||
);
|
||||
tcc_get_debug_info(s1, sym, &str);
|
||||
tcc_debug_check_forw(s1, sym, -1);
|
||||
if (sym_bind == STB_GLOBAL)
|
||||
tcc_debug_stabs(s1, str.data, N_GSYM, 0, NULL, 0, 0);
|
||||
else
|
||||
@@ -2437,11 +2479,8 @@ ST_FUNC void tcc_debug_typedef(TCCState *s1, Sym *sym)
|
||||
{
|
||||
CString str;
|
||||
cstr_new (&str);
|
||||
cstr_printf (&str, "%s:t",
|
||||
(sym->v & ~SYM_FIELD) >= SYM_FIRST_ANOM
|
||||
? "" : get_tok_str(sym->v, NULL));
|
||||
cstr_printf (&str, "%s:t", get_tok_str(sym->v, NULL));
|
||||
tcc_get_debug_info(s1, sym, &str);
|
||||
tcc_debug_check_forw(s1, sym, -1);
|
||||
tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0, 0);
|
||||
cstr_free (&str);
|
||||
}
|
||||
|
||||
22
tccgen.c
22
tccgen.c
@@ -1294,16 +1294,21 @@ static Sym *sym_copy(Sym *s0, Sym **ps)
|
||||
Sym *s;
|
||||
s = sym_malloc(), *s = *s0;
|
||||
s->prev = *ps, *ps = s;
|
||||
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
|
||||
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM && ps == &local_stack)
|
||||
sym_link(s, 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* copy s->type.ref to stack 'ps' for VT_FUNC and VT_PTR */
|
||||
/* Symbol 's' was locally declared 'extern' (or as function), and
|
||||
is on global_stack. Now must copy its 'ref' to global_stack too */
|
||||
static void sym_copy_ref(Sym *s, Sym **ps)
|
||||
{
|
||||
int bt = s->type.t & VT_BTYPE;
|
||||
if (bt == VT_FUNC || bt == VT_PTR || (bt == VT_STRUCT && s->sym_scope)) {
|
||||
if (bt == VT_PTR
|
||||
|| bt == VT_FUNC
|
||||
|| ((bt == VT_STRUCT || IS_ENUM(s->type.t))
|
||||
&& s->type.ref
|
||||
&& s->type.ref->sym_scope)) {
|
||||
Sym **sp = &s->type.ref;
|
||||
for (s = *sp, *sp = NULL; s; s = s->next) {
|
||||
Sym *s2 = sym_copy(s, ps);
|
||||
@@ -5962,13 +5967,10 @@ ST_FUNC void unary(void)
|
||||
learn = 1;
|
||||
next();
|
||||
} else {
|
||||
AttributeDef ad_tmp;
|
||||
int itmp;
|
||||
CType cur_type;
|
||||
|
||||
parse_btype(&cur_type, &ad_tmp, 0);
|
||||
type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT);
|
||||
if (compare_types(&controlling_type, &cur_type, 0)) {
|
||||
int v;
|
||||
parse_btype(&type, &ad, 0);
|
||||
type_decl(&type, &ad, &v, TYPE_ABSTRACT);
|
||||
if (compare_types(&controlling_type, &type, 0)) {
|
||||
if (has_match) {
|
||||
tcc_error("type match twice");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
#include <stdio.h>
|
||||
int printf(const char*, ...);
|
||||
|
||||
#define myassert(x) \
|
||||
printf("%s:%d: %s : \"%s\"\n", __FILE__,__LINE__,(x)?"ok":"error",#x)
|
||||
|
||||
enum{ in = 0};
|
||||
#define myassert(X) do{ if(!X) printf("%d: assertion failed\n", __LINE__); }while(0)
|
||||
int main(){
|
||||
|
||||
int main_1(){
|
||||
{
|
||||
myassert(!in);
|
||||
if(sizeof(enum{in=1})) myassert(in);
|
||||
@@ -38,6 +42,45 @@ int main(){
|
||||
for(;sizeof(enum{in=1});){ myassert(in); break; }
|
||||
myassert(!in); //OK
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
int main_2()
|
||||
{
|
||||
char c = 'a';
|
||||
void func1(char c); /* param 'c' must not shadow local 'c' */
|
||||
func1(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void func1(char c)
|
||||
{
|
||||
myassert(c == 'a');
|
||||
}
|
||||
|
||||
struct st { int a; };
|
||||
|
||||
/* --------------------------------------------- */
|
||||
int main_3()
|
||||
{
|
||||
struct st func(void);
|
||||
struct st st = func(); /* not an 'incompatible redefinition' */
|
||||
myassert(st.a == 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct st func(void)
|
||||
{
|
||||
struct st st = { 10 };
|
||||
return st;
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
int main()
|
||||
{
|
||||
main_1();
|
||||
main_2();
|
||||
main_3();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
129_scopes.c:10: ok : "!in"
|
||||
129_scopes.c:11: ok : "in"
|
||||
129_scopes.c:12: ok : "!in"
|
||||
129_scopes.c:15: ok : "!in"
|
||||
129_scopes.c:16: ok : "in"
|
||||
129_scopes.c:17: ok : "!in"
|
||||
129_scopes.c:20: ok : "!in"
|
||||
129_scopes.c:21: ok : "in"
|
||||
129_scopes.c:22: ok : "!in"
|
||||
129_scopes.c:25: ok : "!in"
|
||||
129_scopes.c:26: ok : "!in"
|
||||
129_scopes.c:27: ok : "!in"
|
||||
129_scopes.c:31: ok : "!in"
|
||||
129_scopes.c:32: ok : "in"
|
||||
129_scopes.c:33: ok : "!in"
|
||||
129_scopes.c:36: ok : "!in"
|
||||
129_scopes.c:37: ok : "in"
|
||||
129_scopes.c:38: ok : "!in"
|
||||
129_scopes.c:41: ok : "!in"
|
||||
129_scopes.c:42: ok : "in"
|
||||
129_scopes.c:43: ok : "!in"
|
||||
129_scopes.c:59: ok : "c == 'a'"
|
||||
129_scopes.c:69: ok : "st.a == 10"
|
||||
|
||||
Reference in New Issue
Block a user