diff --git a/tcc.h b/tcc.h index 494460b2..ee919efc 100644 --- a/tcc.h +++ b/tcc.h @@ -643,6 +643,7 @@ typedef struct AttributeDef { struct FuncAttr f; struct Section *section; Sym *cleanup_func; + int alias_target; /* token */ int asm_label; /* associated asm label */ char attr_mode; /* __attribute__((__mode__(...))) */ } AttributeDef; diff --git a/tccgen.c b/tccgen.c index 5cecc19f..efdb8117 100644 --- a/tccgen.c +++ b/tccgen.c @@ -939,10 +939,8 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, #endif if (sym->asm_label) { - name = get_tok_str(sym->asm_label & ~SYM_FIELD, NULL); - /* with SYM_FIELD it was __attribute__((alias("..."))) actually */ - if (!(sym->asm_label & SYM_FIELD)) - can_add_underscore = 0; + name = get_tok_str(sym->asm_label, NULL); + can_add_underscore = 0; } if (tcc_state->leading_underscore && can_add_underscore) { @@ -1524,6 +1522,8 @@ static void merge_attr(AttributeDef *ad, AttributeDef *ad1) if (ad1->section) ad->section = ad1->section; + if (ad1->alias_target) + ad->alias_target = ad1->alias_target; if (ad1->asm_label) ad->asm_label = ad1->asm_label; if (ad1->attr_mode) @@ -4147,8 +4147,8 @@ redo: case TOK_ALIAS2: skip('('); parse_mult_str(&astr, "alias(\"target\")"); - ad->asm_label = /* save string as token, for later */ - tok_alloc((char*)astr.data, astr.size-1)->tok | SYM_FIELD; + ad->alias_target = /* save string as token, for later */ + tok_alloc((char*)astr.data, astr.size-1)->tok; skip(')'); cstr_free(&astr); break; @@ -8459,6 +8459,20 @@ found: /* external variable or function */ type.t |= VT_EXTERN; sym = external_sym(v, &type, r, &ad); + if (ad.alias_target) { + /* Aliases need to be emitted when their target + symbol is emitted, even if perhaps unreferenced. + We only support the case where the base is + already defined, otherwise we would need + deferring to emit the aliases until the end of + the compile unit. */ + Sym *alias_target = sym_find(ad.alias_target); + ElfSym *esym = elfsym(alias_target); + if (!esym) + tcc_error("unsupported forward __alias__ attribute"); + put_extern_sym2(sym, esym->st_shndx, + esym->st_value, esym->st_size, 0); + } } else { if (type.t & VT_STATIC) r |= VT_CONST; diff --git a/tccpp.c b/tccpp.c index daf5d92e..74ce9954 100644 --- a/tccpp.c +++ b/tccpp.c @@ -3673,16 +3673,21 @@ static void tcc_predefs(CString *cstr) "#ifndef __builtin_va_copy\n" "#define __builtin_va_copy(dest,src) (dest)=(src)\n" "#endif\n" + "#ifdef __leading_underscore\n" + "#define RENAME(X) __asm__(\"_\"X)\n" + "#else\n" + "#define RENAME(X) __asm__(X)\n" + "#endif\n" /* TCC BBUILTIN AND BOUNDS ALIASES */ "#ifdef __BOUNDS_CHECKING_ON\n" - "#define __BUILTINBC(ret,name,params) ret __builtin_##name params __attribute__((alias(\"__bound_\"#name)));\n" - "#define __BOUND(ret,name,params) ret name params __attribute__((alias(\"__bound_\"#name)));\n" + "#define __BUILTINBC(ret,name,params) ret __builtin_##name params RENAME(\"__bound_\"#name);\n" + "#define __BOUND(ret,name,params) ret name params RENAME(\"__bound_\"#name);\n" "#else\n" - "#define __BUILTINBC(ret,name,params) ret __builtin_##name params __attribute__((alias(#name)));\n" + "#define __BUILTINBC(ret,name,params) ret __builtin_##name params RENAME(#name);\n" "#define __BOUND(ret,name,params)\n" "#endif\n" "#define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params)\n" - "#define __BUILTIN(ret,name,params) ret __builtin_##name params __attribute__((alias(\"\"#name)));\n" + "#define __BUILTIN(ret,name,params) ret __builtin_##name params RENAME(#name);\n" "__BOTH(void*,memcpy,(void*,const void*,__SIZE_TYPE__))\n" "__BOTH(void*,memmove,(void*,const void*,__SIZE_TYPE__))\n" "__BOTH(void*,memset,(void*,int,__SIZE_TYPE__))\n" diff --git a/tests/tests2/120+_alias.c b/tests/tests2/120+_alias.c new file mode 100644 index 00000000..8f29d8d9 --- /dev/null +++ b/tests/tests2/120+_alias.c @@ -0,0 +1,15 @@ +extern int printf (const char *, ...); +extern void target(void); +extern void alias_for_target(void); +extern void asm_for_target(void); + +void inunit2(void); + +void inunit2(void) +{ + target(); + alias_for_target(); + /* This symbol is not supposed to be available in this unit: + asm_for_target(); + */ +} diff --git a/tests/tests2/120_alias.c b/tests/tests2/120_alias.c new file mode 100644 index 00000000..c9eb2985 --- /dev/null +++ b/tests/tests2/120_alias.c @@ -0,0 +1,25 @@ +/* Check semantics of various constructs to generate renamed symbols. */ +extern int printf (const char *, ...); +void target(void); +void target(void) { + printf("in target function\n"); +} + +void alias_for_target(void) __attribute__((alias("target"))); +void asm_for_target(void) __asm__("target"); + +/* This is not supposed to compile, alias targets must be defined in the + same unit. In TCC they even must be defined before the reference +void alias_for_undef(void) __attribute__((alias("undefined"))); +*/ + +extern void inunit2(void); + +int main(void) +{ + target(); + alias_for_target(); + asm_for_target(); + inunit2(); + return 0; +} diff --git a/tests/tests2/120_alias.expect b/tests/tests2/120_alias.expect new file mode 100644 index 00000000..021e3f06 --- /dev/null +++ b/tests/tests2/120_alias.expect @@ -0,0 +1,5 @@ +in target function +in target function +in target function +in target function +in target function diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index f7f47910..2403a121 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -74,6 +74,11 @@ GEN-ALWAYS = 104_inline.test : FLAGS += $(subst 104,104+,$1) 104_inline.test : GEN = $(GEN-TCC) +# this test needs two files, and we want to invoke the linker +120_alias.test : FLAGS += $(subst 120,120+,$1) +120_alias.test : GEN = $(GEN-TCC) +120_alias.test : NORUN = true + # this test needs pthread 106_pthread.test: FLAGS += -pthread 106_pthread.test: NORUN = true