Reinstate attribute alias handling

commit 2a0167a merged alias and asm symbol renaming, but broke
semantics of aliases, see testcase.  Basically the difference between
the two is that an asm rename doesn't generate a new symbol, i.e. with

  int foo __asm__("bar");

all source reference to 'foo' will be to 'bar', nothing of the name
'foo' will remain in the object file, and for instance reference to
'foo' from other compilation units won't be resolved to this one.

Aliases OTOH create an additional symbol.  With:

  void target (void) { return; }
  void afunc (void) __attribute__((alias("target")));

reference to 'afunc' will remain 'afunc' in the object file.  It will
generate two symbols, 'afunc' and 'target' referring to the same entity.
This difference matters if other compilation units make references to
'afunc'.

A side requirement of this is that for alias to work that the target
symbol needs to be defined in the same unit.  For TCC we even require a
stricter variant: it must be defined before the alias is created.

Now, with this I merely re-instated the old flow of events before above
commit.  It didn't seem useful anymore to place both names in the
asm_label member of attributes, and the asm_label member of Sym now
again only needs the hold the __asm__ rename.

It also follows that tcc_predefs.h can't make use of attribute alias to
e.g. map __builtin_memcpy to __bound_memcpy (simply because the latter
isn't defined in all units), but rather must use __asm__ renaming, which
in turn means that the underscore handling needs to be done by hand.
This commit is contained in:
Michael Matz
2020-09-30 17:46:01 +02:00
parent 727e24cb0a
commit 352e1d0fc4
7 changed files with 80 additions and 10 deletions

View File

@@ -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;