2 Commits

Author SHA1 Message Date
grischka
38ab5f65b3 tccgen: more of scope hacks
* case 1: local scope of 'ff'
  int main() {
    int ff = 123;
    {
      int ff(int):
      ff(456)
    }}

* case 2: linkage of a static extern symbol
  (older gcc did allow that)
  static int ff(int);
  int main() {
    int ff(int):
    ff(456)
  }

Also:
- cleanup enum, let sym_push() handle redefinition
- just mark incomplete array base types, unshare only
  when needed (in decl_initializer_alloc())
- fix sizeof empty array (= 0) : int ii[] = {};
- rename 'Sym' members used by __attribute__((cleanup(f)))
2025-09-08 17:23:18 +02:00
grischka
ce4de961af tccpe: add COFF symbol table for GDB
wanted by gdb to have global variables info on windows

Also:
tcc.h:
- move dwarf inline fns
- use dwarf as default for 64-bit platforms. GDB can't handle
  locals info from stabs on 64-bit correctly (also not from gcc).
tccpe.c:
- use 's1' instead of 'pe->s1'
tccdbg.c:
- fix locals info problem on Windows where (unsigned long) s->value
  is uint32_t and would not cast to long long correctly.
- tweak dwarf to have line info at begin of functions, otherwise
  "gdb b main, r, n" would say "no line number info, single step..."
  (see also objdump --dwarf=decodedline ...)
2025-09-08 17:22:21 +02:00
13 changed files with 472 additions and 277 deletions

8
configure vendored
View File

@@ -234,8 +234,8 @@ Advanced options (experts only):
Cross build options (experimental):
--cpu=CPU target CPU [$cpu]
--targetos=... target OS (Darwin,WIN32,Android/Termux) [$targetos]
--os-release=x.y.z target os release x.y.z [$os_release] (with BSD systems)
--cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]
--os-release=x.y.z use os release x.y.z [$os_release]
EOF
exit 1
}
@@ -260,6 +260,7 @@ fi
# OS specific
buildos=$(uname)
cpu_sys=$(uname -m)
default os_release "$(uname -r)"
case $buildos in
Windows_NT|MINGW*|MSYS*|CYGWIN*)
@@ -294,11 +295,6 @@ then
ar="${cross_prefix}${ar}"
fi
if test -z "$os_release"
then
os_release=$(uname -r)
fi
case "$cpu" in
x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386)
cpu="i386"

115
tcc.h
View File

@@ -552,13 +552,17 @@ typedef struct Sym {
CType type; /* associated type */
union {
struct Sym *next; /* next related symbol (for fields and anoms) */
int *e; /* expanded token stream */
int *e; /* expanded token stream with preprocessor macros */
int asm_label; /* associated asm label */
struct Sym *cleanupstate; /* in defined labels */
int *vla_array_str; /* vla array code */
};
struct Sym *prev; /* prev symbol in stack */
struct Sym *prev_tok; /* previous symbol for this token */
union {
struct Sym *prev_tok; /* previous symbol for this token */
struct Sym *cleanup_sym; /* symbol from __attribute__((cleanup())) */
struct Sym *cleanup_label; /* label in 'pending_gotos' chain */
};
} Sym;
/* section definition */
@@ -1074,7 +1078,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 (4 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */
#define VT_ENUM_VAL (3 << 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)
@@ -1087,9 +1091,13 @@ struct filespec {
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
/* symbol was created by tccasm.c first */
#define VT_ASM (VT_VOID | 1 << VT_STRUCT_SHIFT)
#define VT_ASM_FUNC (VT_ASM | 2 << VT_STRUCT_SHIFT)
#define IS_ASM_SYM(sym) (((sym)->type.t & (VT_BTYPE | VT_ASM)) == VT_ASM)
#define VT_ASM (VT_VOID | 4 << VT_STRUCT_SHIFT)
#define VT_ASM_FUNC (VT_VOID | 5 << VT_STRUCT_SHIFT)
#define IS_ASM_SYM(sym) (((sym)->type.t & ((VT_BTYPE|VT_STRUCT_MASK) & ~(1<<VT_STRUCT_SHIFT))) == VT_ASM)
#define IS_ASM_FUNC(t) ((t & (VT_BTYPE|VT_STRUCT_MASK)) == VT_ASM_FUNC)
/* base type is array (from typedef/typeof) */
#define VT_BT_ARRAY (6 << VT_STRUCT_SHIFT)
/* general: set/get the pseudo-bitfield value for bit-mask M */
#define BFVAL(M,N) ((unsigned)((M) & ~((M) << 1)) * (N))
@@ -1656,54 +1664,6 @@ static inline void write64le(unsigned char *p, uint64_t x) {
static inline void add64le(unsigned char *p, int64_t x) {
write64le(p, read64le(p) + x);
}
#define DWARF_MAX_128 ((8 * sizeof (int64_t) + 6) / 7)
#define dwarf_read_1(ln,end) \
((ln) < (end) ? *(ln)++ : 0)
#define dwarf_read_2(ln,end) \
((ln) + 1 < (end) ? (ln) += 2, read16le((ln) - 2) : 0)
#define dwarf_read_4(ln,end) \
((ln) + 3 < (end) ? (ln) += 4, read32le((ln) - 4) : 0)
#define dwarf_read_8(ln,end) \
((ln) + 7 < (end) ? (ln) += 8, read64le((ln) - 8) : 0)
static inline uint64_t
dwarf_read_uleb128(unsigned char **ln, unsigned char *end)
{
unsigned char *cp = *ln;
uint64_t retval = 0;
int i;
for (i = 0; i < DWARF_MAX_128; i++) {
uint64_t byte = dwarf_read_1(cp, end);
retval |= (byte & 0x7f) << (i * 7);
if ((byte & 0x80) == 0)
break;
}
*ln = cp;
return retval;
}
static inline int64_t
dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
{
unsigned char *cp = *ln;
int64_t retval = 0;
int i;
for (i = 0; i < DWARF_MAX_128; i++) {
uint64_t byte = dwarf_read_1(cp, end);
retval |= (byte & 0x7f) << (i * 7);
if ((byte & 0x80) == 0) {
if ((byte & 0x40) && (i + 1) * 7 < 64)
retval |= (uint64_t)-1LL << ((i + 1) * 7);
break;
}
}
*ln = cp;
return retval;
}
/* ------------ i386-gen.c ------------ */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM
ST_FUNC void g(int c);
@@ -1892,6 +1852,49 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
#define dwarf_str_section s1->dwarf_str_section
#define dwarf_line_str_section s1->dwarf_line_str_section
#define DWARF_MAX_128 ((8 * sizeof (int64_t) + 6) / 7)
#define dwarf_read_1(ln,end) \
((ln) < (end) ? *(ln)++ : 0)
#define dwarf_read_2(ln,end) \
((ln) + 1 < (end) ? read16le(((ln)+=2) - 2) : 0)
#define dwarf_read_4(ln,end) \
((ln) + 3 < (end) ? read32le(((ln)+=4) - 4) : 0)
#define dwarf_read_8(ln,end) \
((ln) + 7 < (end) ? read64le(((ln)+=8) - 8) : 0)
static inline uint64_t
dwarf_read_uleb128(unsigned char **ln, unsigned char *end)
{
unsigned char *cp = *ln;
uint64_t retval = 0;
int i;
for (i = 0; i < DWARF_MAX_128; i++) {
uint64_t byte = dwarf_read_1(cp, end);
retval |= (byte & 0x7f) << (i * 7);
if ((byte & 0x80) == 0)
break;
}
*ln = cp;
return retval;
}
static inline int64_t
dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
{
unsigned char *cp = *ln;
int64_t retval = 0;
int i;
for (i = 0; i < DWARF_MAX_128; i++) {
uint64_t byte = dwarf_read_1(cp, end);
retval |= (byte & 0x7f) << (i * 7);
if ((byte & 0x80) == 0) {
if ((byte & 0x40) && (i + 1) * 7 < 64)
retval |= (uint64_t)-1LL << ((i + 1) * 7);
break;
}
}
*ln = cp;
return retval;
}
/* default dwarf version for "-gdwarf" */
#ifdef TCC_TARGET_MACHO
# define DEFAULT_DWARF_VERSION 2
@@ -1904,9 +1907,7 @@ ST_FUNC void tcc_tcov_reset_ind(TCCState *s1);
# define CONFIG_DWARF_VERSION 0
#endif
#if defined TCC_TARGET_PE
# define R_DATA_32DW 'Z' /* fake code to avoid DLL relocs */
#elif defined TCC_TARGET_X86_64
#if defined TCC_TARGET_X86_64
# define R_DATA_32DW R_X86_64_32
#else
# define R_DATA_32DW R_DATA_32

View File

@@ -842,7 +842,7 @@ static void asm_parse_directive(TCCState *s1, int global)
if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
if (IS_ASM_SYM(sym))
sym->type.t = (sym->type.t & ~VT_ASM) | VT_ASM_FUNC;
sym->type.t |= VT_ASM_FUNC;
st_type = STT_FUNC;
set_st_type:
if (sym->c) {

View File

@@ -1500,6 +1500,8 @@ ST_FUNC void tcc_debug_line(TCCState *s1)
else {
dwarf_line_op(s1, DW_LNS_advance_line);
dwarf_sleb128_op(s1, len_line);
/* advance by nothing */
dwarf_line_op(s1, DWARF_OPCODE_BASE - DWARF_LINE_BASE);
}
}
}
@@ -2209,9 +2211,9 @@ static void tcc_debug_finish (TCCState *s1, struct _debug_info *cur)
}
else {
/* param/local */
dwarf_data1(dwarf_info_section, dwarf_sleb128_size(s->value) + 1);
dwarf_data1(dwarf_info_section, dwarf_sleb128_size((long)s->value) + 1);
dwarf_data1(dwarf_info_section, DW_OP_fbreg);
dwarf_sleb128(dwarf_info_section, s->value);
dwarf_sleb128(dwarf_info_section, (long)s->value);
}
tcc_free (s->str);
}

255
tccgen.c
View File

@@ -341,8 +341,8 @@ ST_FUNC void check_vstack(void)
(int)(vtop - vstack + 1));
}
/* vstack debugging aid */
#if 0
/* dump 'b' vstack entries starting with 'a' */
void pv (const char *lbl, int a, int b)
{
int i;
@@ -352,6 +352,27 @@ void pv (const char *lbl, int a, int b)
lbl, i, p->type.t, p->r, p->r2, (int)p->c.i);
}
}
/* dump 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;
}
}
static void type_to_str(char *buf, int buf_size, CType *type, const char *varstr);
/* print type */
static void ptype(CType *type, int v)
{
char buf[500];
type_to_str(buf, sizeof(buf), type, get_tok_str(v, NULL));
printf("type = '%s'\n", buf);
}
#endif
/* ------------------------------------------------------------------------- */
@@ -506,7 +527,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
sym_type = STT_FUNC;
} else if ((t & VT_BTYPE) == VT_VOID) {
sym_type = STT_NOTYPE;
if ((t & (VT_BTYPE|VT_ASM_FUNC)) == VT_ASM_FUNC)
if (IS_ASM_FUNC(t))
sym_type = STT_FUNC;
} else {
sym_type = STT_OBJECT;
@@ -575,8 +596,18 @@ ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type,
return;
if (sym) {
if (0 == sym->c)
if (0 == sym->c) {
put_extern_sym(sym, NULL, 0, 0);
if (sym->sym_scope
&& (sym->type.t & (VT_STATIC|VT_EXTERN)) == (VT_STATIC|VT_EXTERN)) {
/* when a local function declaraion redeclares a global static one
then tccelf would not resolve them to the same symbol. */
Sym *s = sym;
while (s->prev_tok)
s = s->prev_tok;
s->c = sym->c;
}
}
c = sym->c;
}
@@ -683,6 +714,13 @@ ST_INLN Sym *sym_find(int v)
return table_ident[v]->sym_identifier;
}
static int sym_scope_e(Sym *s)
{
return IS_ENUM_VAL (s->type.t)
? s->type.ref->sym_scope
: s->sym_scope;
}
/* make sym in-/visible to the parser */
static inline void sym_link(Sym *s, int yes)
{
@@ -692,10 +730,14 @@ static inline void sym_link(Sym *s, int yes)
ps = &ts->sym_struct;
else
ps = &ts->sym_identifier;
if (yes)
if (yes) {
if (*ps && sym_scope_e(*ps) == local_scope)
tcc_error("redeclaration of '%s'", get_tok_str(s->v, NULL));
s->prev_tok = *ps, *ps = s;
else
s->sym_scope = local_scope;
} else {
*ps = s->prev_tok;
}
}
/* push a given symbol on the symbol stack */
@@ -710,18 +752,9 @@ ST_FUNC Sym *sym_push(int v, CType *type, int r, int c)
s->type.ref = type->ref;
s->r = r;
/* don't record fields or anonymous symbols */
/* XXX: simplify */
if ((v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
/* record symbol in token array */
sym_link(s, 1);
s->sym_scope = local_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));
}
return s;
}
@@ -824,19 +857,6 @@ 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)
{
@@ -1294,27 +1314,47 @@ 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 && ps == &local_stack)
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
sym_link(s, 1);
return s;
}
/* 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)
/* 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 move_ref_to_global(Sym *s)
{
int bt = s->type.t & VT_BTYPE;
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);
sp = &(*sp = s2)->next;
sym_copy_ref(s2, ps);
Sym *l, **lp;
int n, bt;
bt = s->type.t & VT_BTYPE;
if (!(bt == VT_PTR
|| bt == VT_FUNC
|| bt == VT_STRUCT
|| (IS_ENUM(s->type.t)) && (bt = VT_ENUM,1)))
return;
for (s = s->type.ref, n = 0; s; s = s->next) {
for (lp = &local_stack; !!(l = *lp); lp = &l->prev) {
if (l == s) {
*lp = s->prev;
s->prev = global_stack, global_stack = s;
if (n || bt == VT_PTR) {
move_ref_to_global(s);
} else {
if ((bt == VT_STRUCT || bt == VT_ENUM)
&& (s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM) {
/* copy struct/enum tag to local scope */
s->v |= SYM_FIELD;
l = sym_copy(s, lp);
l->v &= ~SYM_FIELD;
}
n = 1;
}
break;
}
}
if (n == 0) /* no next (VT_PTR) or ref not on local_stack */
break;
}
}
@@ -1335,15 +1375,15 @@ static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
s->a = ad->a;
s->asm_label = ad->asm_label;
s->type.ref = type->ref;
/* copy type to the global stack */
if (local_stack)
sym_copy_ref(s, &global_stack);
} else {
patch_storage(s, ad, type);
}
/* push variables on local_stack if any */
if (local_stack && (s->type.t & VT_BTYPE) != VT_FUNC)
if (local_stack) {
/* make sure that type->ref is on global stack */
move_ref_to_global(s);
/* put into local scope */
s = sym_copy(s, &local_stack);
}
return s;
}
@@ -3457,8 +3497,8 @@ ST_FUNC int type_size(CType *type, int *a)
int ts;
s = type->ref;
ts = type_size(&s->type, a);
if (ts < 0 && s->c < 0)
ts = -ts;
if (s->c < 0)
return s->c;
return ts * s->c;
} else {
*a = PTR_SIZE;
@@ -4367,6 +4407,15 @@ static void struct_layout(CType *type, AttributeDef *ad)
}
}
/* Does 'n' fit into integer type 't' ? */
static int in_range(long long n, int t)
{
unsigned long long m = (1ULL << (btype_size(t & VT_BTYPE) * 8 - 1)) - 1;
if (t & VT_UNSIGNED)
return n <= (m << 1) + 1;
return n >= -(long long)m - 1 && n <= (long long)m;
}
/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */
static void struct_decl(CType *type, int u)
{
@@ -4431,36 +4480,26 @@ do_decl:
/* non empty enums are not allowed */
ps = &s->next;
if (u == VT_ENUM) {
long long ll = 0, pl = 0, nl = 0, ni = 0, pi = 0;
unsigned long long mu = 0;
long long ll = 0, pl = 0, nl = 0;
CType t;
t.ref = s;
s->sym_scope = local_scope; /* anonymous symbol won't have set */
/* enum symbols have static storage */
t.t = VT_INT|VT_STATIC|VT_ENUM_VAL;
if (bt) {
if (bt)
t.t = bt|VT_STATIC|VT_ENUM_VAL;
mu = 1llu << (type_size(&t, &align) * 8 - 1);
pi = mu - 1;
ni = -mu;
mu = (mu << 1) - 1u;
}
for(;;) {
v = tok;
if (v < TOK_UIDENT)
expect("identifier");
ss = sym_find(v);
if (ss && !local_stack)
tcc_error("redefinition of enumerator '%s'",
get_tok_str(v, NULL));
next();
if (tok == '=') {
next();
ll = expr_const64();
}
if (bt && (t.t & VT_UNSIGNED ? (unsigned long long)ll > mu
: ll < ni || ll > pi))
tcc_error("enumerator value outside the range of underlying type '%s'",
get_tok_str(v, NULL));
if (bt && !in_range(ll, t.t))
tcc_error("enumerator '%s' out of range of its type",
get_tok_str(v, NULL));
ss = sym_push(v, &t, VT_CONST, 0);
ss->enum_val = ll;
*ps = ss, ps = &ss->next;
@@ -4626,9 +4665,9 @@ do_decl:
check_fields(type, 1);
check_fields(type, 0);
struct_layout(type, &ad);
if (debug_modes)
tcc_debug_fix_forw(tcc_state, type);
}
if (debug_modes)
tcc_debug_fix_forw(tcc_state, type);
}
}
@@ -4860,8 +4899,11 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
parse_expr_type(&type1);
/* remove all storage modifiers except typedef */
type1.t &= ~(VT_STORAGE&~VT_TYPEDEF);
if (type1.ref)
if (type1.ref) {
sym_to_attr(ad, type1.ref);
if (type1.t & VT_ARRAY)
type1.t |= VT_BT_ARRAY;
}
goto basic_type2;
case TOK_THREAD_LOCAL:
tcc_error("_Thread_local is not implemented");
@@ -4886,12 +4928,12 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
if (t)
parse_btype_qualify(type, t);
t = type->t;
if (t & VT_ARRAY)
t |= VT_BT_ARRAY;
/* get attributes from typedef */
sym_to_attr(ad, s);
typespec_found = 1;
st = bt = -2;
if (type->ref && (t & VT_ARRAY) && type->ref->c < 0)
type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c);
break;
}
type_found = 1;
@@ -4994,15 +5036,15 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT | TYPE_PARAM);
if ((pt.t & VT_BTYPE) == VT_VOID)
tcc_error("parameter declared as void");
if (local_scope > 1 || n == 0)
n = SYM_FIELD;
if (n == 0 || (td & TYPE_PARAM))
n |= SYM_FIELD;
} else {
n = tok;
pt.t = VT_INT | VT_EXTERN; /* default type */
pt.ref = NULL;
next();
}
if (local_scope == 1 && n < TOK_UIDENT)
if (n < TOK_UIDENT)
expect("identifier");
convert_parameter_type(&pt);
arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE;
@@ -5026,7 +5068,6 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
/* if no parameters, then old type prototype */
l = FUNC_OLD;
skip(')');
--local_scope;
/* NOTE: const is ignored in returned type as it has a special
meaning in gcc / C++ */
type->t &= ~VT_CONSTANT;
@@ -5046,10 +5087,9 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td)
s->next = first;
type->t = VT_FUNC;
type->ref = s;
/* unlink symbols from the token table, keep on stack */
/* unlink parameter symbols from the token table, keep on stack */
sym_pop(ps, sr, 1);
//psyms("---", *ps, sr);
--local_scope;
} else if (tok == '[') {
int saved_nocode_wanted = nocode_wanted;
@@ -6901,7 +6941,7 @@ static void try_call_scope_cleanup(Sym *stop)
Sym *cls = cur_scope->cl.s;
for (; cls != stop; cls = cls->next) {
Sym *fs = cls->cleanup_func;
Sym *vs = cls->prev_tok;
Sym *vs = cls->cleanup_sym;
save_lvalues();
vpushsym(&fs->type, fs);
vset(&vs->type, vs->r, vs->c);
@@ -6912,6 +6952,7 @@ static void try_call_scope_cleanup(Sym *stop)
}
}
static void try_call_cleanup_goto(Sym *cleanupstate)
{
Sym *oc, *cc;
@@ -6938,7 +6979,7 @@ static void block_cleanup(struct scope *o)
int jmp = 0;
Sym *g, **pg;
for (pg = &pending_gotos; (g = *pg) && g->c > o->cl.n;) {
if (g->prev_tok->r & LABEL_FORWARD) {
if (g->cleanup_label->r & LABEL_FORWARD) {
Sym *pcl = g->next;
if (!jmp)
jmp = gjmp(0);
@@ -7360,7 +7401,7 @@ again:
/* start new goto chain for cleanups, linked via label->next */
if (cur_scope->cl.s && !nocode_wanted) {
sym_push2(&pending_gotos, SYM_FIELD, 0, cur_scope->cl.n);
pending_gotos->prev_tok = s;
pending_gotos->cleanup_label = s;
s = sym_push2(&s->next, SYM_FIELD, 0, 0);
pending_gotos->next = s;
}
@@ -7570,7 +7611,7 @@ static void decl_design_flex(init_params *p, Sym *ref, int index)
if (ref == p->flex_array_ref) {
if (index >= ref->c)
ref->c = index + 1;
} else if (ref->c < 0)
} else if (ref->c < 0 && index >= 0)
tcc_error("flexible array has zero size in this context");
}
@@ -8029,7 +8070,7 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
/* GNU extension: if the initializer is empty for a flex array,
it's size is zero. We won't enter the loop, so set the size
now. */
decl_design_flex(p, s, len);
decl_design_flex(p, s, len - 1);
while (tok != '}' || (flags & DIF_HAVE_ELEM)) {
len = decl_designator(p, type, c, &f, flags, len);
flags &= ~DIF_HAVE_ELEM;
@@ -8165,6 +8206,13 @@ 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. */
if (type->t & VT_BT_ARRAY)
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) {
@@ -8182,8 +8230,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (size < 0) {
/* If unknown size, do a dry-run 1st pass */
if (!has_init)
tcc_error("unknown type size");
if (!has_init)
goto err_size;
if (has_init == 2) {
/* only get strings */
init_str = tok_str_alloc();
@@ -8206,7 +8254,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
/* if still unknown size, error */
size = type_size(type, &align);
if (size < 0)
if (size < 0)
err_size:
tcc_error("unknown type size");
/* If there's a flex member and it was used in the initializer
@@ -8258,7 +8307,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (ad->cleanup_func) {
Sym *cls = sym_push2(&all_cleanups,
SYM_FIELD | ++cur_scope->cl.n, 0, 0);
cls->prev_tok = sym;
cls->cleanup_sym = sym;
cls->cleanup_func = ad->cleanup_func;
cls->next = cur_scope->cl.s;
cur_scope->cl.s = cls;
@@ -8423,19 +8472,21 @@ ST_FUNC Sym *gfunc_set_param(Sym *s, int c, int byref)
return NULL;
s->c = c;
if (byref)
s->r = VT_LLOCAL | VT_LVAL;
s->r = VT_LLOCAL | VT_LVAL; /* otherwise VT_LOCAL */
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)
Sym *s = ref;
while (s->next)
s = s->next;
while (s != ref) {
if ((s->v & ~SYM_STRUCT) < SYM_FIRST_ANOM)
sym_copy(s, &local_stack);
s = s->prev;
}
}
/* parse a function defined by symbol 'sym' and generate its code in
@@ -8473,8 +8524,8 @@ static void gen_function(Sym *sym)
/* push a dummy symbol to enable local sym storage */
sym_push2(&local_stack, SYM_FIELD, 0, 0);
/* push parameters */
local_scope = 1;
sym_push_params(sym->type.ref);
//psyms(funcname, local_stack, 0);
local_scope = 0;
rsym = 0;
@@ -8608,7 +8659,7 @@ static int decl(int l)
{
int v, has_init, r, oldint;
CType type, btype;
Sym *sym;
Sym *sym, *sa;
AttributeDef ad, adbase;
ElfSym *esym;
@@ -8663,22 +8714,8 @@ static int decl(int l)
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
{
char buf[500];
type_to_str(buf, sizeof(buf), &type, get_tok_str(v, NULL));
printf("type = '%s'\n", buf);
}
#endif
if ((type.t & VT_BTYPE) == VT_FUNC) {
if ((type.t & VT_STATIC) && (l != VT_CONST))
tcc_error("function without file scope cannot be static");
@@ -8722,8 +8759,6 @@ static int decl(int l)
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)

206
tccpe.c
View File

@@ -347,6 +347,8 @@ struct pe_info {
TCCState *s1;
Section *reloc;
Section *thunk;
Section *coffsym;
Section *coffstr;
const char *filename;
int type;
DWORD sizeofheaders;
@@ -366,6 +368,10 @@ struct pe_info {
int sec_count;
struct pe_import_info **imp_info;
int imp_count;
/* output */
FILE *op;
DWORD sum;
unsigned pos;
};
#define PE_NUL 0
@@ -427,71 +433,110 @@ static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD siz
hdr->opthdr.DataDirectory[dir].Size = size;
}
struct pe_file {
FILE *op;
DWORD sum;
unsigned pos;
};
static int pe_fwrite(const void *data, int len, struct pe_file *pf)
static int pe_fwrite(struct pe_info *pe, const void *data, int len)
{
const WORD *p = data;
DWORD sum;
int ret, i;
pf->pos += (ret = fwrite(data, 1, len, pf->op));
sum = pf->sum;
pe->pos += (ret = fwrite(data, 1, len, pe->op));
sum = pe->sum;
for (i = len; i > 0; i -= 2) {
sum += (i >= 2) ? *p++ : *(BYTE*)p;
sum = (sum + (sum >> 16)) & 0xFFFF;
}
pf->sum = sum;
pe->sum = sum;
return len == ret ? 0 : -1;
}
static void pe_fpad(struct pe_file *pf, DWORD new_pos)
static void pe_fpad(struct pe_info *pe, DWORD new_pos)
{
char buf[256];
int n, diff = new_pos - pf->pos;
int n, diff = new_pos - pe->pos;
memset(buf, 0, sizeof buf);
while (diff > 0) {
diff -= n = umin(diff, sizeof buf);
fwrite(buf, n, 1, pf->op);
fwrite(buf, n, 1, pe->op);
}
pf->pos = new_pos;
pe->pos = new_pos;
}
/*----------------------------------------------------------------------------*/
/* PE-DWARF/COFF support
does not work with a mingw-gdb really but works with cv2pdb
(https://github.com/rainers/cv2pdb) */
/* some DWARF support with COFF symbol/string table for gdb */
#define N_COFF_SYMS 0
static const char dwarf_secs[] =
#pragma pack(push, 1)
struct syment
{
".debug_info\0"
".debug_abbrev\0"
".debug_line\0"
".debug_aranges\0"
".debug_str\0"
".debug_line_str\0"
union {
char n_name[8]; /* old COFF version */
struct {
int32_t n_zeroes; /* new == 0 */
int32_t n_offset; /* offset into string table */
};
};
int32_t n_value; /* value of symbol */
short n_scnum; /* section number */
unsigned short n_type; /* type and derived type */
char n_sclass; /* storage class */
char n_numaux; /* number of aux. entries */
};
#pragma pack(pop)
static const unsigned coff_strtab_size = 4 + sizeof dwarf_secs - 1;
#define SHF_PRIVATE 0x80000000
static int pe_put_long_secname(char *secname, const char *name)
static void pe_add_coffsym(struct pe_info *pe)
{
const char *d = dwarf_secs;
do {
if (0 == strcmp(d, name)) {
snprintf(secname, 8, "/%d", (int)(d - dwarf_secs + 4));
return 1;
TCCState *s1 = pe->s1;
ElfSym *esym;
struct syment *se;
int n;
if (NULL == pe->coffsym) {
pe->coffsym = new_section(s1, ".coffsym", SHT_PROGBITS, SHF_PRIVATE);
pe->coffstr = new_section(s1, ".coffstr", SHT_PROGBITS, SHF_PRIVATE);
section_ptr_add(pe->coffstr, 4); /* coff string table size */
return;
}
#if 0
se = section_ptr_add(pe->coffsym, sizeof *se);
strcpy(se->n_name, ".file");
se->n_scnum = -2;
se->n_sclass = 0x67;
se->n_numaux = 1;
se = section_ptr_add(pe->coffsym, sizeof *se);
strcpy((char*)se, "no-file");
#endif
#if 1
esym = (ElfSym*)s1->symtab->data;
for (n = s1->symtab->data_offset / sizeof *esym; ++esym, --n;) {
int sym_bind = ELFW(ST_BIND)(esym->st_info);
if (sym_bind == STB_GLOBAL) {
char *name = esym->st_name + (char*)s1->symtab->link->data;
int nl = strlen(name);
addr_t value = esym->st_value;
int shnum = esym->st_shndx;
if (shnum != SHN_UNDEF && shnum < s1->nb_sections) {
Section *s = s1->sections[shnum];
shnum = s->sh_info;
value = value - s->sh_addr;
}
se = section_ptr_add(pe->coffsym, sizeof *se);
se->n_value = value;
se->n_scnum = shnum;
se->n_sclass = 2; // C_EXT
if (nl <= 8)
memcpy(se->n_name, name, nl);
else
se->n_offset = put_elf_str(pe->coffstr, name);
}
d = strchr(d, 0) + 1;
} while (*d);
return 0;
}
#endif
write32le(pe->coffstr->data, pe->coffstr->data_offset); /* coff string table size */
}
/* Run cv2pdb, available at https://github.com/rainers/cv2pdb. It reads
and strips the dwarf info and creates a <exename>.pdb file instead */
static void pe_create_pdb(TCCState *s1, const char *exename)
{
char buf[300]; int r;
@@ -614,15 +659,16 @@ static int pe_write(struct pe_info *pe)
struct pe_header pe_header = pe_template;
int i;
struct pe_file pf = {0};
DWORD file_offset;
struct section_info *si;
IMAGE_SECTION_HEADER *psh;
TCCState *s1 = pe->s1;
int need_strtab = 0;
pf.op = fopen(pe->filename, "wb");
if (NULL == pf.op)
if (s1->do_debug)
pe_add_coffsym(pe);
pe->op = fopen(pe->filename, "wb");
if (NULL == pe->op)
return tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
pe->sizeofheaders = pe_file_align(pe,
@@ -632,7 +678,7 @@ static int pe_write(struct pe_info *pe)
file_offset = pe->sizeofheaders;
if (2 == pe->s1->verbose)
if (2 == s1->verbose)
printf("-------------------------------"
"\n virt file size section" "\n");
for (i = 0; i < pe->sec_count; ++i) {
@@ -645,7 +691,7 @@ static int pe_write(struct pe_info *pe)
size = si->sh_size;
psh = &si->ish;
if (2 == pe->s1->verbose)
if (2 == s1->verbose)
printf("%6x %6x %6x %s\n",
(unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name);
@@ -690,8 +736,10 @@ static int pe_write(struct pe_info *pe)
}
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
if (si->cls == sec_debug)
need_strtab += pe_put_long_secname((char*)psh->Name, sh_name);
if (pe->coffstr && strlen(sh_name) > 8) {
/* long section name, for example ".debug_info" */
snprintf((char*)psh->Name, 8, "/%d", put_elf_str(pe->coffstr, sh_name));
}
psh->Characteristics = si->pe_flags;
psh->VirtualAddress = addr;
@@ -716,18 +764,22 @@ static int pe_write(struct pe_info *pe)
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
pe_header.opthdr.ImageBase = pe->imagebase;
pe_header.opthdr.Subsystem = pe->subsystem;
if (pe->s1->pe_stack_size)
pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size;
if (s1->pe_stack_size)
pe_header.opthdr.SizeOfStackReserve = s1->pe_stack_size;
if (PE_DLL == pe->type)
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
if (need_strtab) {
pe_header.filehdr.Characteristics |= s1->pe_characteristics;
if (pe->coffsym) {
pe_add_coffsym(pe);
pe_header.filehdr.PointerToSymbolTable = file_offset;
pe_header.filehdr.NumberOfSymbols = N_COFF_SYMS;
pe_header.filehdr.NumberOfSymbols
= pe->coffsym->data_offset / sizeof (struct syment);
}
pe_fwrite(&pe_header, sizeof pe_header, &pf);
pe_fwrite(pe, &pe_header, sizeof pe_header);
for (i = 0; i < pe->sec_count; ++i)
pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
pe_fwrite(pe, &pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER));
file_offset = pe->sizeofheaders;
for (i = 0; i < pe->sec_count; ++i) {
@@ -736,34 +788,33 @@ static int pe_write(struct pe_info *pe)
if (!si->data_size)
continue;
for (s = si->sec; s; s = s->prev) {
pe_fpad(&pf, file_offset);
pe_fwrite(s->data, s->data_offset, &pf);
pe_fpad(pe, file_offset);
pe_fwrite(pe, s->data, s->data_offset);
if (s->prev)
file_offset += s->prev->sh_addr - s->sh_addr;
}
file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
pe_fpad(&pf, file_offset);
pe_fpad(pe, file_offset);
}
if (need_strtab) {
/* create a tiny COFF string table with the long section names */
pe_fwrite(&coff_strtab_size, sizeof coff_strtab_size, &pf);
pe_fwrite(dwarf_secs, sizeof dwarf_secs - 1, &pf);
file_offset = pf.pos;
if (pe->coffsym) {
pe_fwrite(pe, pe->coffsym->data, pe->coffsym->data_offset);
pe_fwrite(pe, pe->coffstr->data, pe->coffstr->data_offset);
file_offset = pe->pos;
}
pf.sum += file_offset;
fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
pe->sum += file_offset;
fseek(pe->op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(pe, &pe->sum, sizeof (DWORD));
fclose (pf.op);
fclose (pe->op);
#ifndef _WIN32
chmod(pe->filename, 0777);
#endif
if (2 == pe->s1->verbose)
if (2 == s1->verbose)
printf("-------------------------------\n");
if (pe->s1->verbose)
if (s1->verbose)
printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset);
if (s1->do_debug & 16)
@@ -848,7 +899,7 @@ static void pe_build_imports(struct pe_info *pe)
dllindex = p->dll_index;
if (dllindex)
name = tcc_basename((dllref = pe->s1->loaded_dlls[dllindex-1])->name);
name = tcc_basename((dllref = s1->loaded_dlls[dllindex-1])->name);
else
name = "", dllref = NULL;
@@ -863,8 +914,8 @@ static void pe_build_imports(struct pe_info *pe)
if (k < n) {
int iat_index = p->symbols[k]->iat_index;
int sym_index = p->symbols[k]->sym_index;
ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index;
const char *name = (char*)pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
ElfW(Sym) *imp_sym = (ElfW(Sym) *)s1->dynsymtab_section->data + sym_index;
const char *name = (char*)s1->dynsymtab_section->link->data + imp_sym->st_name;
int ordinal;
/* patch symbol (and possibly its underscored alias) */
@@ -948,7 +999,7 @@ static void pe_build_exports(struct pe_info *pe)
sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
for (sym_index = 1; sym_index < sym_end; ++sym_index) {
sym = (ElfW(Sym)*)symtab_section->data + sym_index;
name = pe_export_name(pe->s1, sym);
name = pe_export_name(s1, sym);
if (sym->st_other & ST_PE_EXPORT) {
p = tcc_malloc(sizeof *p);
p->index = sym_index;
@@ -997,7 +1048,7 @@ static void pe_build_exports(struct pe_info *pe)
tcc_error_noabort("could not create '%s': %s", buf, strerror(errno));
} else {
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
if (pe->s1->verbose)
if (s1->verbose)
printf("<- %s (%d symbol%s)\n", buf, sym_count, &"s"[sym_count < 2]);
}
#endif
@@ -1035,6 +1086,8 @@ static void pe_build_reloc (struct pe_info *pe)
ElfW_Rel *rel, *rel_end;
Section *s = NULL, *sr;
struct pe_reloc_header *hdr;
TCCState *s1 = pe->s1;
int dwarf = 0, n;
sh_addr = offset = block_ptr = count = i = 0;
rel = rel_end = NULL;
@@ -1046,6 +1099,11 @@ static void pe_build_reloc (struct pe_info *pe)
++ rel;
if (type != REL_TYPE_DIRECT)
continue;
if (dwarf) { /* don't runtime-relocate dwarf-to-dwarf */
n = ((ElfSym *)s1->symtab->data + ELFW(R_SYM)(rel[-1].r_info))->st_shndx;
if (n >= s1->dwlo && n < s1->dwhi)
continue;
}
if (count == 0) { /* new block */
block_ptr = pe->reloc->data_offset;
section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header));
@@ -1065,6 +1123,7 @@ static void pe_build_reloc (struct pe_info *pe)
rel = (ElfW_Rel *)sr->data;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
sh_addr = s->sh_addr;
dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
}
s = s->prev;
continue;
@@ -1133,8 +1192,8 @@ static int pe_assign_addresses (struct pe_info *pe)
TCCState *s1 = pe->s1;
if (PE_DLL == pe->type)
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
//pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
pe->reloc = new_section(s1, ".reloc", SHT_PROGBITS, 0);
//pe->thunk = new_section(s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
nbs = s1->nb_sections;
sec_order = tcc_mallocz(2 * sizeof (int) * nbs);
@@ -1200,6 +1259,7 @@ static int pe_assign_addresses (struct pe_info *pe)
si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
add_section:
s->sh_info = pe->sec_count; /* section number for coff syms */
addr += s->data_offset;
si->sh_size = addr - si->sh_addr;
if (s->sh_type != SHT_NOBITS) {
@@ -1345,7 +1405,7 @@ static int pe_check_symbols(struct pe_info *pe)
is->iat_index = sym_index;
}
} else if (pe->s1->rdynamic
} else if (s1->rdynamic
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
/* if -rdynamic option, then export all non local symbols */
sym->st_other |= ST_PE_EXPORT;

View File

@@ -77,40 +77,101 @@ struct st func(void)
}
/* --------------------------------------------- */
static void func2(char *(*md)(char *md))
/* func* 'md' must not be shadowed by param 'md' */
static void f4(char *(*md)(char *md))
{
(*md)("test");
}
static char *a(char *a)
static char *a4(char *a)
{
printf("%s\n", a);
int strcmp();
myassert(!strcmp(a, "test"));
return a;
}
int main_4(void)
int main_4()
{
func2(a);
f4(a4);
return 0;
}
/* --------------------------------------------- */
int b[3];
int f(void);
int main_5(void)
int a5[3], b5[];
int f5(void);
int main_5()
{
extern int b[3];
b[2]=10;
printf("%d\n", f());
extern int a5[3], b5[3];
a5[2]=10, b5[2]=4;
myassert(f5() == 10 + 4);
return 0;
}
int f5(void)
{
return a5[2]+b5[2];
}
int b5[3];
/* --------------------------------------------- */
static int f6(int);
int i6 = 11;
int main_6()
{
{
int i6 = 33, f6 = 44;
myassert(i6 == 33 && f6 == 44);
{
int f6(int);
extern int i6;
myassert(i6 == 11 && f6(22) == 22);
}
myassert(i6 == 33 && f6 == 44);
}
myassert(i6 == 11 && f6(22) == 22);
return 0;
}
int f(void)
int f6(int x)
{
return b[2]==10 ? 1 : 0;
return x;
}
/* --------------------------------------------- */
#if defined __TINYC__ \
? !defined __leading_underscore \
: !(defined __APPLE__ || defined _WIN32)
# define _
#else
# define _ "_"
#endif
struct xx7 { int a, b; };
void f7()
{
struct xx7 { int c; } x;
{
extern struct xx7 { int a, b; } x __asm__(_"z7");
x.a = 12;
struct xx7 y = { 0,0 };
}
struct xx7 y = { 90 };
x.c = 78;
printf("xx7 (1) : %d %d\n", x.c, y.c);
}
int main_7()
{
f7();
extern struct xx7 y __asm__(_"z7");
printf("xx7 (2) : %d %d\n", y.a, y.b);
return 0;
}
struct xx7 z7 = { 0, 34 };
/* --------------------------------------------- */
int main()
{
@@ -119,5 +180,7 @@ int main()
main_3();
main_4();
main_5();
main_6();
main_7();
return 0;
}

View File

@@ -21,5 +21,11 @@
129_scopes.c:43: ok : "!in"
129_scopes.c:59: ok : "c == 'a'"
129_scopes.c:69: ok : "st.a == 10"
test
1
129_scopes.c:88: ok : "!strcmp(a, "test")"
129_scopes.c:105: ok : "f5() == 10 + 4"
129_scopes.c:122: ok : "i6 == 33 && f6 == 44"
129_scopes.c:126: ok : "i6 == 11 && f6(22) == 22"
129_scopes.c:128: ok : "i6 == 33 && f6 == 44"
129_scopes.c:130: ok : "i6 == 11 && f6(22) == 22"
xx7 (1) : 78 90
xx7 (2) : 12 34

View File

@@ -1,14 +1,30 @@
#include <stdio.h>
int printf(const char*, ...);
int main()
{
char a;
short b;
char a;
short b;
printf("%d %d\n", sizeof(char), sizeof(a));
printf("%d %d\n", sizeof(short), sizeof(b));
printf("sizeof a : %d %d\n", sizeof(char), sizeof(a));
printf("sizeof b : %d %d\n", sizeof(short), sizeof(b));
return 0;
int ii[] = {}; /* gnu extension, size = 0 */
printf("sizeof ii : %d\n", sizeof ii);
int kk[] = { 1 };
printf("sizeof kk : %d\n", sizeof kk);
char cc[] = "12";
printf("sizeof cc : %d\n", sizeof cc);
__WCHAR_TYPE__ ll[] = L"12345";
printf("len-of ll : %d\n", sizeof ll / sizeof ll[0]);
static struct {
int a,b,c;
int d[];
} ss[] = {{ 1, 2, 3, {} }};
printf("sizeof ss : %d\n", sizeof ss);
return 0;
}
/* vim: set expandtab ts=4 sw=3 sts=3 tw=80 :*/

View File

@@ -1,2 +1,7 @@
1 1
2 2
sizeof a : 1 1
sizeof b : 2 2
sizeof ii : 0
sizeof kk : 4
sizeof cc : 3
len-of ll : 6
sizeof ss : 12

View File

@@ -13,6 +13,7 @@ typedef struct FunStruct MyFunStruct;
typedef MyFunStruct *MoreFunThanEver;
typedef int t[];
int tints[];
int main()
{
@@ -36,6 +37,14 @@ int main()
printf("%d\n", (int)sizeof((t){1,2,3}));
printf("%d\n", (int)sizeof((t){1,2,3,4}));
/* two arrays derived from same base type */
t t3 = { 1,2,3 }, t4 = { 4,5,6,7 };
for (p = t3, i = 0; i < 3 ; i++) printf("%d ", *p++);
for (p = t4, i = 0; i < 4 ; i++) printf("%d ", *p++); printf("\n");
typeof(tints) t5 = { 1,2,3 }, t6 = { 4,5,6,7 };
for (p = t5, i = 0; i < 3 ; i++) printf("%d ", *p++);
for (p = t6, i = 0; i < 4 ; i++) printf("%d ", *p++); printf("\n");
return 0;
}

View File

@@ -5,3 +5,5 @@
1 2 3 4
12
16
1 2 3 4 5 6 7
1 2 3 4 5 6 7

View File

@@ -17,7 +17,7 @@
60_errors_and_warnings.c:21: error: struct/union/enum already defined
[test_62_enumerator_redefinition]
60_errors_and_warnings.c:26: error: redefinition of enumerator 'RED'
60_errors_and_warnings.c:26: error: redeclaration of 'RED'
[test_63_local_enumerator_redefinition]
[returns 1]