From: Alexandre Oliva Date: Mon, 24 Oct 2005 17:51:42 +0000 (+0000) Subject: gas/ChangeLog: X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=06e77878ef2b6a57ef92c1691b3aeb668dc248ba;p=binutils-gdb.git gas/ChangeLog: * read.c (potable): Add weakref. (s_weakref): New. * read.h (s_weakref): Declare. * struc-symbol.h (struct symbol): Add sy_weakrefr and sy_weakrefd. * symbols.c (colon): Clear weakrefr. (symbol_find_exact): Rename to, and reimplement in terms of... (symbol_find_exact_noref): ... new function. (symbol_find): Likewise... (symbol_find_noref): ... ditto. (resolve_symbol_value): Resolve weakrefr without setting their values. (S_SET_WEAK): Call hook. (S_GET_VALUE): Follow weakref link. (S_SET_VALUE): Clear weakrefr. (S_IS_WEAK): Follow weakref link. (S_IS_WEAKREFR, S_SET_WEAKREFR, S_CLEAR_WEAKREFR): New. (S_IS_WEAKREFD, S_SET_WEAKREFD, S_CLEAR_WEAKREFD): New. (symbol_set_value_expression, symbol_set_frag): Clear weakrefr. (symbol_mark_used): Follow weakref link. (print_symbol_value_1): Print weak, weakrefr and weakrefd. * symbols.h (symbol_find_noref, symbol_find_exact_noref): Declare. (S_IS_WEAKREFR, S_SET_WEAKREFR, S_CLEAR_WEAKREFR): Declare. (S_IS_WEAKREFD, S_SET_WEAKREFD, S_CLEAR_WEAKREFD): Declare. * write.c (adust_reloc_syms): Follow weakref link. Do not complain if target is undefined. (write_object_file): Likewise. Remove weakrefr symbols. Drop unreferenced weakrefd symbols. * config/obj-coff.c (obj_frob_symbol): Do not force WEAKREFD symbols EXTERNAL. (pecoff_obj_set_weak_hook, pecoff_obj_clear_weak_hook): New. * config/obj-coff.h (obj_set_weak_hook, obj_clear_weak_hook): Define. * doc/as.texinfo: Document weakref. * doc/internals.texi: Document new struct members, internal functions and hooks. gas/testsuite/ChangeLog: * gas/all/weakref1.s, gas/all/weakref1.d: New test. * gas/all/weakref1g.d, gas/all/weakref1l.d: New tests. * gas/all/weakref1u.d, gas/all/weakref1w.d: New tests. * gas/all/weakref2.s, gas/all/weakref3.s: New tests. * gas/all/gas.exp: Run new tests. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index 9b52eacdcc9..440323f56fc 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,40 @@ +2005-10-24 Alexandre Oliva + + * read.c (potable): Add weakref. + (s_weakref): New. + * read.h (s_weakref): Declare. + * struc-symbol.h (struct symbol): Add sy_weakrefr and sy_weakrefd. + * symbols.c (colon): Clear weakrefr. + (symbol_find_exact): Rename to, and reimplement in terms of... + (symbol_find_exact_noref): ... new function. + (symbol_find): Likewise... + (symbol_find_noref): ... ditto. + (resolve_symbol_value): Resolve weakrefr without setting their + values. + (S_SET_WEAK): Call hook. + (S_GET_VALUE): Follow weakref link. + (S_SET_VALUE): Clear weakrefr. + (S_IS_WEAK): Follow weakref link. + (S_IS_WEAKREFR, S_SET_WEAKREFR, S_CLEAR_WEAKREFR): New. + (S_IS_WEAKREFD, S_SET_WEAKREFD, S_CLEAR_WEAKREFD): New. + (symbol_set_value_expression, symbol_set_frag): Clear weakrefr. + (symbol_mark_used): Follow weakref link. + (print_symbol_value_1): Print weak, weakrefr and weakrefd. + * symbols.h (symbol_find_noref, symbol_find_exact_noref): Declare. + (S_IS_WEAKREFR, S_SET_WEAKREFR, S_CLEAR_WEAKREFR): Declare. + (S_IS_WEAKREFD, S_SET_WEAKREFD, S_CLEAR_WEAKREFD): Declare. + * write.c (adust_reloc_syms): Follow weakref link. Do not + complain if target is undefined. + (write_object_file): Likewise. Remove weakrefr symbols. Drop + unreferenced weakrefd symbols. + * config/obj-coff.c (obj_frob_symbol): Do not force WEAKREFD + symbols EXTERNAL. + (pecoff_obj_set_weak_hook, pecoff_obj_clear_weak_hook): New. + * config/obj-coff.h (obj_set_weak_hook, obj_clear_weak_hook): Define. + * doc/as.texinfo: Document weakref. + * doc/internals.texi: Document new struct members, internal + functions and hooks. + 2005-10-24 Jie Zhang * Makefile.am (bfin-parse.h): Renamed from bfin-parse.tab.h. diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c index 4ea65be3923..f1446c02348 100644 --- a/gas/config/obj-coff.c +++ b/gas/config/obj-coff.c @@ -1055,6 +1055,39 @@ weak_uniquify (const char * name) return ret; } +void +pecoff_obj_set_weak_hook (symbolS *symbolP) +{ + symbolS *alternateP; + + /* See _Microsoft Portable Executable and Common Object + File Format Specification_, section 5.5.3. + Create a symbol representing the alternate value. + coff_frob_symbol will set the value of this symbol from + the value of the weak symbol itself. */ + S_SET_STORAGE_CLASS (symbolP, C_NT_WEAK); + S_SET_NUMBER_AUXILIARY (symbolP, 1); + SA_SET_SYM_FSIZE (symbolP, IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY); + + alternateP = symbol_find_or_make (weak_name2altname (S_GET_NAME (symbolP))); + S_SET_EXTERNAL (alternateP); + S_SET_STORAGE_CLASS (alternateP, C_NT_WEAK); + + SA_SET_SYM_TAGNDX (symbolP, alternateP); +} + +void +pecoff_obj_clear_weak_hook (symbolS *symbolP) +{ + symbolS *alternateP; + + S_SET_STORAGE_CLASS (symbolP, 0); + SA_SET_SYM_FSIZE (symbolP, 0); + + alternateP = symbol_find (weak_name2altname (S_GET_NAME (symbolP))); + S_CLEAR_EXTERNAL (alternateP); +} + #endif /* TE_PE */ /* Handle .weak. This is a GNU extension in formats other than PE. */ @@ -1065,9 +1098,6 @@ obj_coff_weak (int ignore ATTRIBUTE_UNUSED) char *name; int c; symbolS *symbolP; -#ifdef TE_PE - symbolS *alternateP; -#endif do { @@ -1085,23 +1115,6 @@ obj_coff_weak (int ignore ATTRIBUTE_UNUSED) SKIP_WHITESPACE (); S_SET_WEAK (symbolP); -#ifdef TE_PE - /* See _Microsoft Portable Executable and Common Object - File Format Specification_, section 5.5.3. - Create a symbol representing the alternate value. - coff_frob_symbol will set the value of this symbol from - the value of the weak symbol itself. */ - S_SET_STORAGE_CLASS (symbolP, C_NT_WEAK); - S_SET_NUMBER_AUXILIARY (symbolP, 1); - SA_SET_SYM_FSIZE (symbolP, IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY); - - alternateP = symbol_find_or_make (weak_name2altname (name)); - S_SET_EXTERNAL (alternateP); - S_SET_STORAGE_CLASS (alternateP, C_NT_WEAK); - - SA_SET_SYM_TAGNDX (symbolP, alternateP); -#endif - if (c == ',') { input_line_pointer++; @@ -1157,12 +1170,19 @@ coff_frob_symbol (symbolS *symp, int *punt) { /* This is a weak alternate symbol. All processing of PECOFFweak symbols is done here, through the alternate. */ - symbolS *weakp = symbol_find (weak_altname2name (S_GET_NAME (symp))); + symbolS *weakp = symbol_find_noref (weak_altname2name + (S_GET_NAME (symp)), 1); assert (weakp); assert (S_GET_NUMBER_AUXILIARY (weakp) == 1); - if (symbol_equated_p (weakp)) + if (! S_IS_WEAK (weakp)) + { + /* The symbol was turned from weak to strong. Discard altname. */ + *punt = 1; + return; + } + else if (symbol_equated_p (weakp)) { /* The weak symbol has an alternate specified; symp is unneeded. */ S_SET_STORAGE_CLASS (weakp, C_NT_WEAK); @@ -1225,7 +1245,7 @@ coff_frob_symbol (symbolS *symp, int *punt) && !SF_GET_STATICS (symp) && S_GET_STORAGE_CLASS (symp) != C_LABEL && symbol_constant_p (symp) - && (real = symbol_find (S_GET_NAME (symp))) + && (real = symbol_find_noref (S_GET_NAME (symp), 1)) && S_GET_STORAGE_CLASS (real) == C_NULL && real != symp) { @@ -1237,7 +1257,10 @@ coff_frob_symbol (symbolS *symp, int *punt) if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp)) { assert (S_GET_VALUE (symp) == 0); - S_SET_EXTERNAL (symp); + if (S_IS_WEAKREFD (symp)) + *punt = 1; + else + S_SET_EXTERNAL (symp); } else if (S_GET_STORAGE_CLASS (symp) == C_NULL) { diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h index c6b4e63e62f..81577c8d842 100644 --- a/gas/config/obj-coff.h +++ b/gas/config/obj-coff.h @@ -157,6 +157,9 @@ #ifdef TE_PE /* PE weak symbols need USE_UNIQUE. */ #define USE_UNIQUE 1 + +#define obj_set_weak_hook pecoff_obj_set_weak_hook +#define obj_clear_weak_hook pecoff_obj_clear_weak_hook #endif #ifndef OBJ_COFF_MAX_AUXENTRIES @@ -384,6 +387,10 @@ extern void coff_adjust_section_syms (bfd *, asection *, void *); extern void coff_frob_file_after_relocs (void); extern void coff_obj_symbol_new_hook (symbolS *); extern void coff_obj_read_begin_hook (void); +#ifdef TE_PE +extern void pecoff_obj_set_weak_hook (symbolS *); +extern void pecoff_obj_clear_weak_hook (symbolS *); +#endif extern void obj_coff_section (int); extern segT obj_coff_add_segment (const char *); extern void obj_coff_section (int); diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index c7c2ac7dbbf..4eefc42a673 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -3842,6 +3842,7 @@ Some machine configurations provide additional directives. * Warning:: @code{.warning @var{string}} * Weak:: @code{.weak @var{names}} +* Weakref:: @code{.weakref @var{alias}, @var{symbol}} * Word:: @code{.word @var{expressions}} * Deprecated:: Deprecated Directives @end menu @@ -5989,6 +5990,25 @@ On the PE target, weak symbols are supported natively as weak aliases. When a weak symbol is created that is not an alias, GAS creates an alternate symbol to hold the default value. +@node Weakref +@section @code{.weakref @var{alias}, @var{target}} + +@cindex @code{weakref} directive +This directive creates an alias to the target symbol that enables the symbol to +be referenced with weak-symbol semantics, but without actually making it weak. +If direct references or definitions of the symbol are present, then the symbol +will not be weak, but if all references to it are through weak references, the +symbol will be marked as weak in the symbol table. + +The effect is equivalent to moving all references to the alias to a separate +assembly source file, renaming the alias to the symbol in it, declaring the +symbol as weak there, and running a reloadable link to merge the object files +resulting from the assembly of the new source file and the old source file that +had the references to the alias removed. + +The alias itself never makes to the symbol table, and is entirely handled +within the assembler. + @node Word @section @code{.word @var{expressions}} diff --git a/gas/doc/internals.texi b/gas/doc/internals.texi index 8c8c66e1580..51b4061030f 100644 --- a/gas/doc/internals.texi +++ b/gas/doc/internals.texi @@ -93,6 +93,13 @@ responsible for setting it when a symbol is used in backend routines. Whether the symbol is an MRI common symbol created by the @code{COMMON} pseudo-op when assembling in MRI mode. +@item sy_weakrefr +Whether the symbol is a @code{weakref} alias to another symbol. + +@item sy_weakrefd +Whether the symbol is or was referenced by one or more @code{weakref} aliases, +and has not had any direct references. + @item bsym This points to the BFD @code{asymbol} that will be used in writing the object file. @@ -146,7 +153,17 @@ A synonym for @code{S_IS_EXTERNAL}. Don't use it. @item S_IS_WEAK @cindex S_IS_WEAK -Return non-zero if the symbol is weak. +Return non-zero if the symbol is weak, or if it is a @code{weakref} alias or +symbol that has not been strongly referenced. + +@item S_IS_WEAKREFR +@cindex S_IS_WEAKREFR +Return non-zero if the symbol is a @code{weakref} alias. + +@item S_IS_WEAKREFD +@cindex S_IS_WEAKREFD +Return non-zero if the symbol was aliased by a @code{weakref} alias and has not +had any strong references. @item S_IS_COMMON @cindex S_IS_COMMON @@ -182,6 +199,29 @@ Mark the symbol as not externally visible. @cindex S_SET_WEAK Mark the symbol as weak. +@item S_SET_WEAKREFR +@cindex S_SET_WEAKREFR +Mark the symbol as the referrer in a @code{weakref} directive. The symbol it +aliases must have been set to the value expression before this point. If the +alias has already been used, the symbol is marked as used too. + +@item S_CLEAR_WEAKREFR +@cindex S_CLEAR_WEAKREFR +Clear the @code{weakref} alias status of a symbol. This is implicitly called +whenever a symbol is defined or set to a new expression. + +@item S_SET_WEAKREFD +@cindex S_SET_WEAKREFD +Mark the symbol as the referred symbol in a @code{weakref} directive. +Implicitly marks the symbol as weak, but see below. It should only be called +if the referenced symbol has just been added to the symbol table. + +@item S_SET_WEAKREFD +@cindex S_SET_WEAKREFD +Clear the @code{weakref} aliased status of a symbol. This is implicitly called +whenever the symbol is looked up, as part of a direct reference or a +definition, but not as part of a @code{weakref} directive. + @item S_GET_TYPE @item S_GET_DESC @item S_GET_OTHER @@ -1533,6 +1573,16 @@ If you define this macro, GAS will call it for each symbol. You can indicate that the symbol should not be included in the object file by defining this macro to set its second argument to a non-zero value. +@item obj_set_weak_hook +@cindex obj_set_weak_hook +If you define this macro, @code{S_SET_WEAK} will call it before modifying the +symbol's flags. + +@item obj_clear_weak_hook +@cindex obj_clear_weak_hook +If you define this macro, @code{S_CLEAR_WEAKREFD} will call it after clearning +the @code{weakrefd} flag, but before modifying any other flags. + @item obj_frob_file @cindex obj_frob_file If you define this macro, GAS will call it after the symbol table has been diff --git a/gas/read.c b/gas/read.c index 00f676f223e..9381735e8dd 100644 --- a/gas/read.c +++ b/gas/read.c @@ -434,6 +434,7 @@ static const pseudo_typeS potable[] = { {"xref", s_ignore, 0}, {"xstabs", s_xstab, 's'}, {"warning", s_errwarn, 0}, + {"weakref", s_weakref, 0}, {"word", cons, 2}, {"zero", s_space, 0}, {NULL, NULL, 0} /* End sentinel. */ @@ -3150,6 +3151,124 @@ s_text (int ignore ATTRIBUTE_UNUSED) const_flag &= ~IN_DEFAULT_SECTION; #endif } + +/* .weakref x, y sets x as an alias to y that, as long as y is not + referenced directly, will cause y to become a weak symbol. */ +void +s_weakref (int ignore ATTRIBUTE_UNUSED) +{ + char *name; + char delim; + char *end_name; + symbolS *symbolP; + symbolS *symbolP2; + expressionS exp; + + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + + if (name == end_name) + { + as_bad (_("expected symbol name")); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + symbolP = symbol_find_or_make (name); + + *end_name = delim; + + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *end_name = 0; + as_bad (_("expected comma after \"%s\""), name); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + + if (name == end_name) + { + as_bad (_("expected symbol name")); + ignore_rest_of_line (); + return; + } + + if ((symbolP2 = symbol_find_noref (name, 1)) == NULL + && (symbolP2 = md_undefined_symbol (name)) == NULL) + { + symbolP2 = symbol_find_or_make (name); + S_SET_WEAKREFD (symbolP2); + } + else + { + symbolS *symp = symbolP2; + + while (S_IS_WEAKREFR (symp) && symp != symbolP) + { + expressionS *expP = symbol_get_value_expression (symp); + + assert (expP->X_op == O_symbol + && expP->X_add_number == 0); + symp = expP->X_add_symbol; + } + if (symp == symbolP) + { + char *loop; + + loop = concat (S_GET_NAME (symbolP), + " => ", S_GET_NAME (symbolP2), NULL); + + symp = symbolP2; + while (symp != symbolP) + { + char *old_loop = loop; + symp = symbol_get_value_expression (symp)->X_add_symbol; + loop = concat (loop, " => ", S_GET_NAME (symp), NULL); + free (old_loop); + } + + as_bad (_("%s: would close weakref loop: %s"), + S_GET_NAME (symbolP), loop); + + free (loop); + + *end_name = delim; + ignore_rest_of_line (); + return; + } + + /* Short-circuiting instead of just checking here might speed + things up a tiny little bit, but loop error messages would + miss intermediate links. */ + /* symbolP2 = symp; */ + } + + *end_name = delim; + + memset (&exp, 0, sizeof (exp)); + exp.X_op = O_symbol; + exp.X_add_symbol = symbolP2; + + S_SET_SEGMENT (symbolP, undefined_section); + symbol_set_value_expression (symbolP, &exp); + symbol_set_frag (symbolP, &zero_address_frag); + S_SET_WEAKREFR (symbolP); + + demand_empty_rest_of_line (); +} /* Verify that we are at the end of a line. If not, issue an error and diff --git a/gas/read.h b/gas/read.h index 87070aff2bc..a18272d8882 100644 --- a/gas/read.h +++ b/gas/read.h @@ -185,3 +185,4 @@ extern void stringer (int append_zero); extern void s_xstab (int what); extern void s_rva (int); extern void s_incbin (int); +extern void s_weakref (int); diff --git a/gas/struc-symbol.h b/gas/struc-symbol.h index 2326ee4f06f..75e22076ca8 100644 --- a/gas/struc-symbol.h +++ b/gas/struc-symbol.h @@ -72,6 +72,15 @@ struct symbol routines. */ unsigned int sy_mri_common : 1; + /* This is set if the symbol is set with a .weakref directive. */ + unsigned int sy_weakrefr : 1; + + /* This is set when the symbol is referenced as part of a .weakref + directive, but only if the symbol was not in the symbol table + before. It is cleared as soon as any direct reference to the + symbol is present. */ + unsigned int sy_weakrefd : 1; + #ifdef OBJ_SYMFIELD_TYPE OBJ_SYMFIELD_TYPE sy_obj; #endif diff --git a/gas/symbols.c b/gas/symbols.c index 78ec954f9b5..0110f4204d9 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -309,6 +309,7 @@ colon (/* Just seen "x:" - rattle symbols & frags. */ if ((symbolP = symbol_find (sym_name)) != 0) { + S_CLEAR_WEAKREFR (symbolP); #ifdef RESOLVE_SYMBOL_REDEFINITION if (RESOLVE_SYMBOL_REDEFINITION (symbolP)) return symbolP; @@ -650,18 +651,41 @@ symbol_temp_make (void) symbolS * symbol_find_exact (const char *name) +{ + return symbol_find_exact_noref (name, 0); +} + +symbolS * +symbol_find_exact_noref (const char *name, int noref) { struct local_symbol *locsym; + symbolS* sym; locsym = (struct local_symbol *) hash_find (local_hash, name); if (locsym != NULL) return (symbolS *) locsym; - return ((symbolS *) hash_find (sy_hash, name)); + sym = ((symbolS *) hash_find (sy_hash, name)); + + /* Any references to the symbol, except for the reference in + .weakref, must clear this flag, such that the symbol does not + turn into a weak symbol. Note that we don't have to handle the + local_symbol case, since a weakrefd is always promoted out of the + local_symbol table when it is turned into a weak symbol. */ + if (sym && ! noref) + S_CLEAR_WEAKREFD (sym); + + return sym; } symbolS * symbol_find (const char *name) +{ + return symbol_find_noref (name, 0); +} + +symbolS * +symbol_find_noref (const char *name, int noref) { #ifdef tc_canonicalize_symbol_name { @@ -690,7 +714,7 @@ symbol_find (const char *name) *copy = '\0'; } - return symbol_find_exact (name); + return symbol_find_exact_noref (name, noref); } /* Once upon a time, symbols were kept in a singly linked list. At @@ -970,6 +994,19 @@ resolve_symbol_value (symbolS *symp) symp->sy_value.X_op_symbol = NULL; do_symbol: + if (S_IS_WEAKREFR (symp)) + { + assert (final_val == 0); + if (S_IS_WEAKREFR (add_symbol)) + { + assert (add_symbol->sy_value.X_op == O_symbol + && add_symbol->sy_value.X_add_number == 0); + add_symbol = add_symbol->sy_value.X_add_symbol; + assert (! S_IS_WEAKREFR (add_symbol)); + symp->sy_value.X_add_symbol = add_symbol; + } + } + if (symp->sy_mri_common) { /* This is a symbol inside an MRI common section. The @@ -1039,6 +1076,8 @@ resolve_symbol_value (symbolS *symp) } resolved = symbol_resolved_p (add_symbol); + if (S_IS_WEAKREFR (symp)) + goto exit_dont_set_value; break; case O_uminus: @@ -1717,6 +1756,9 @@ S_GET_VALUE (symbolS *s) if (!finalize_syms) return val; } + if (S_IS_WEAKREFR (s)) + return S_GET_VALUE (s->sy_value.X_add_symbol); + if (s->sy_value.X_op != O_constant) { static symbolS *recur; @@ -1751,6 +1793,7 @@ S_SET_VALUE (symbolS *s, valueT val) s->sy_value.X_op = O_constant; s->sy_value.X_add_number = (offsetT) val; s->sy_value.X_unsigned = 0; + S_CLEAR_WEAKREFR (s); } void @@ -1806,9 +1849,31 @@ S_IS_WEAK (symbolS *s) { if (LOCAL_SYMBOL_CHECK (s)) return 0; + /* Conceptually, a weakrefr is weak if the referenced symbol is. We + could probably handle a WEAKREFR as always weak though. E.g., if + the referenced symbol has lost its weak status, there's no reason + to keep handling the weakrefr as if it was weak. */ + if (S_IS_WEAKREFR (s)) + return S_IS_WEAK (s->sy_value.X_add_symbol); return (s->bsym->flags & BSF_WEAK) != 0; } +int +S_IS_WEAKREFR (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return s->sy_weakrefr != 0; +} + +int +S_IS_WEAKREFD (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return s->sy_weakrefd != 0; +} + int S_IS_COMMON (symbolS *s) { @@ -2008,10 +2073,70 @@ S_SET_WEAK (symbolS *s) { if (LOCAL_SYMBOL_CHECK (s)) s = local_symbol_convert ((struct local_symbol *) s); +#ifdef obj_set_weak_hook + obj_set_weak_hook (s); +#endif s->bsym->flags |= BSF_WEAK; s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL); } +void +S_SET_WEAKREFR (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_weakrefr = 1; + /* If the alias was already used, make sure we mark the target as + used as well, otherwise it might be dropped from the symbol + table. This may have unintended side effects if the alias is + later redirected to another symbol, such as keeping the unused + previous target in the symbol table. Since it will be weak, it's + not a big deal. */ + if (s->sy_used) + symbol_mark_used (s->sy_value.X_add_symbol); +} + +void +S_CLEAR_WEAKREFR (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + s->sy_weakrefr = 0; +} + +void +S_SET_WEAKREFD (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_weakrefd = 1; + S_SET_WEAK (s); +} + +void +S_CLEAR_WEAKREFD (symbolS *s) +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + if (s->sy_weakrefd) + { + s->sy_weakrefd = 0; + /* If a weakref target symbol is weak, then it was never + referenced directly before, not even in a .global directive, + so decay it to local. If it remains undefined, it will be + later turned into a global, like any other undefined + symbol. */ + if (s->bsym->flags & BSF_WEAK) + { +#ifdef obj_clear_weak_hook + obj_clear_weak_hook (s); +#endif + s->bsym->flags &= ~BSF_WEAK; + s->bsym->flags |= BSF_LOCAL; + } + } +} + void S_SET_THREAD_LOCAL (symbolS *s) { @@ -2095,6 +2220,7 @@ symbol_set_value_expression (symbolS *s, const expressionS *exp) if (LOCAL_SYMBOL_CHECK (s)) s = local_symbol_convert ((struct local_symbol *) s); s->sy_value = *exp; + S_CLEAR_WEAKREFR (s); } /* Return a pointer to the X_add_number component of a symbol. */ @@ -2129,6 +2255,7 @@ symbol_set_frag (symbolS *s, fragS *f) return; } s->sy_frag = f; + S_CLEAR_WEAKREFR (s); } /* Return the frag of a symbol. */ @@ -2149,6 +2276,8 @@ symbol_mark_used (symbolS *s) if (LOCAL_SYMBOL_CHECK (s)) return; s->sy_used = 1; + if (S_IS_WEAKREFR (s)) + symbol_mark_used (s->sy_value.X_add_symbol); } /* Clear the mark of whether a symbol has been used. */ @@ -2472,11 +2601,17 @@ print_symbol_value_1 (FILE *file, symbolS *sym) fprintf (file, " local"); if (S_IS_EXTERNAL (sym)) fprintf (file, " extern"); + if (S_IS_WEAK (sym)) + fprintf (file, " weak"); if (S_IS_DEBUG (sym)) fprintf (file, " debug"); if (S_IS_DEFINED (sym)) fprintf (file, " defined"); } + if (S_IS_WEAKREFR (sym)) + fprintf (file, " weakrefr"); + if (S_IS_WEAKREFD (sym)) + fprintf (file, " weakrefd"); fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym))); if (symbol_resolved_p (sym)) { diff --git a/gas/symbols.h b/gas/symbols.h index c20f4d73302..99fa3c3c47d 100644 --- a/gas/symbols.h +++ b/gas/symbols.h @@ -37,7 +37,9 @@ extern int symbols_case_sensitive; char *decode_local_label_name (char *s); symbolS *symbol_find (const char *name); +symbolS *symbol_find_noref (const char *name, int noref); symbolS *symbol_find_exact (const char *name); +symbolS *symbol_find_exact_noref (const char *name, int noref); symbolS *symbol_find_or_make (const char *name); symbolS *symbol_make (const char *name); symbolS *symbol_new (const char *name, segT segment, valueT value, @@ -83,6 +85,8 @@ extern void S_SET_VALUE (symbolS *, valueT); extern int S_IS_FUNCTION (symbolS *); extern int S_IS_EXTERNAL (symbolS *); extern int S_IS_WEAK (symbolS *); +extern int S_IS_WEAKREFR (symbolS *); +extern int S_IS_WEAKREFD (symbolS *); extern int S_IS_COMMON (symbolS *); extern int S_IS_DEFINED (symbolS *); extern int S_FORCE_RELOC (symbolS *, int); @@ -98,6 +102,10 @@ extern void S_SET_EXTERNAL (symbolS *); extern void S_SET_NAME (symbolS *, const char *); extern void S_CLEAR_EXTERNAL (symbolS *); extern void S_SET_WEAK (symbolS *); +extern void S_SET_WEAKREFR (symbolS *); +extern void S_CLEAR_WEAKREFR (symbolS *); +extern void S_SET_WEAKREFD (symbolS *); +extern void S_CLEAR_WEAKREFD (symbolS *); extern void S_SET_THREAD_LOCAL (symbolS *); extern void S_SET_VOLATILE (symbolS *); extern void S_SET_FORWARD_REF (symbolS *); diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index dd4a8910980..7d0cfa8d89c 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2005-10-24 Alexandre Oliva + + * gas/all/weakref1.s, gas/all/weakref1.d: New test. + * gas/all/weakref1g.d, gas/all/weakref1l.d: New tests. + * gas/all/weakref1u.d, gas/all/weakref1w.d: New tests. + * gas/all/weakref2.s, gas/all/weakref3.s: New tests. + * gas/all/gas.exp: Run new tests. + 2005-10-24 Jan Beulich * gas/ia64/index.[sl]: New. diff --git a/gas/testsuite/gas/all/gas.exp b/gas/testsuite/gas/all/gas.exp index a5a8f4b1b3d..155a67e8e9f 100644 --- a/gas/testsuite/gas/all/gas.exp +++ b/gas/testsuite/gas/all/gas.exp @@ -250,6 +250,14 @@ if { ![istarget "i960-*-*"] } { run_dump_test quad } +run_dump_test weakref1 +run_dump_test weakref1g +run_dump_test weakref1l +run_dump_test weakref1u +run_dump_test weakref1w +gas_test_error "weakref2.s" "" "e: would close weakref loop: e => a => b => c => d => e" +gas_test_error "weakref3.s" "" "a: would close weakref loop: a => b => c => d => e => a" + load_lib gas-dg.exp dg-init dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/err-*.s $srcdir/$subdir/warn-*.s]] "" "" diff --git a/gas/testsuite/gas/all/weakref1.d b/gas/testsuite/gas/all/weakref1.d new file mode 100644 index 00000000000..7520b861f5d --- /dev/null +++ b/gas/testsuite/gas/all/weakref1.d @@ -0,0 +1,112 @@ +#objdump: -r +#name: weakref tests, relocations +# ecoff (OSF/alpha) lacks .weak support +# pdp11 lacks .long +# the following must be present in all weakref1*.d +#not-target: alpha*-*-osf* *-*-ecoff pdp11-*-aout + +#... +RELOCATION RECORDS FOR \[\.text\]: +OFFSET +TYPE +VALUE * +# the rest of this file is generated with the following script: +# # script begin +# echo \#... +# sed -n 's:^\.weakref .*, \(\(u\|\(w\)\).*\)$:.*( \3 |\(sec 0\)).* \1:p' weakref1.s | uniq | while read line; do echo "$line"; echo "#..."; done + +# sed -n 's:^\.long \(W\|\)\(.*[^a-z]\)[a-z]*\(\| - .*\)$:\2:p' weakref1.s | sed -e 's,^[lg].*,(&|\\.text)(\\+0x[0-9a-f]+)?,' | sed 's,^,[0-9a-f]+ [^ ]* +,' +# # script output: +#... +[0-9a-f]+ [^ ]* +wa1 +[0-9a-f]+ [^ ]* +ua2 +[0-9a-f]+ [^ ]* +ua3 +[0-9a-f]+ [^ ]* +ua3 +[0-9a-f]+ [^ ]* +ua4 +[0-9a-f]+ [^ ]* +ua4 +[0-9a-f]+ [^ ]* +wb1 +[0-9a-f]+ [^ ]* +ub2 +[0-9a-f]+ [^ ]* +ub3 +[0-9a-f]+ [^ ]* +ub3 +[0-9a-f]+ [^ ]* +ub4 +[0-9a-f]+ [^ ]* +ub4 +[0-9a-f]+ [^ ]* +wc1 +[0-9a-f]+ [^ ]* +wc1 +[0-9a-f]+ [^ ]* +uc2 +[0-9a-f]+ [^ ]* +uc2 +[0-9a-f]+ [^ ]* +uc3 +[0-9a-f]+ [^ ]* +uc3 +[0-9a-f]+ [^ ]* +uc3 +[0-9a-f]+ [^ ]* +uc3 +[0-9a-f]+ [^ ]* +uc4 +[0-9a-f]+ [^ ]* +uc4 +[0-9a-f]+ [^ ]* +uc4 +[0-9a-f]+ [^ ]* +uc4 +[0-9a-f]+ [^ ]* +uc5 +[0-9a-f]+ [^ ]* +uc5 +[0-9a-f]+ [^ ]* +uc5 +[0-9a-f]+ [^ ]* +uc5 +[0-9a-f]+ [^ ]* +uc6 +[0-9a-f]+ [^ ]* +uc6 +[0-9a-f]+ [^ ]* +uc6 +[0-9a-f]+ [^ ]* +uc6 +[0-9a-f]+ [^ ]* +uc7 +[0-9a-f]+ [^ ]* +uc7 +[0-9a-f]+ [^ ]* +uc8 +[0-9a-f]+ [^ ]* +uc8 +[0-9a-f]+ [^ ]* +uc9 +[0-9a-f]+ [^ ]* +uc9 +[0-9a-f]+ [^ ]* +uc9 +[0-9a-f]+ [^ ]* +ww1 +[0-9a-f]+ [^ ]* +ww2 +[0-9a-f]+ [^ ]* +ww3 +[0-9a-f]+ [^ ]* +ww3 +[0-9a-f]+ [^ ]* +ww4 +[0-9a-f]+ [^ ]* +ww4 +[0-9a-f]+ [^ ]* +ww5 +[0-9a-f]+ [^ ]* +ww5 +[0-9a-f]+ [^ ]* +ww6 +[0-9a-f]+ [^ ]* +ww7 +[0-9a-f]+ [^ ]* +ww8 +[0-9a-f]+ [^ ]* +ww8 +[0-9a-f]+ [^ ]* +ww9 +[0-9a-f]+ [^ ]* +ww9 +[0-9a-f]+ [^ ]* +ww10 +[0-9a-f]+ [^ ]* +ww10 +[0-9a-f]+ [^ ]* +um2 +[0-9a-f]+ [^ ]* +wm3 +[0-9a-f]+ [^ ]* +um5 +[0-9a-f]+ [^ ]* +wm6 +[0-9a-f]+ [^ ]* +wm7 +[0-9a-f]+ [^ ]* +wm8 +[0-9a-f]+ [^ ]* +wh2 +[0-9a-f]+ [^ ]* +wh3 +[0-9a-f]+ [^ ]* +wh4 +[0-9a-f]+ [^ ]* +wh5 +[0-9a-f]+ [^ ]* +wh6 +[0-9a-f]+ [^ ]* +wh7 +[0-9a-f]+ [^ ]* +uh8 +[0-9a-f]+ [^ ]* +uh8 +[0-9a-f]+ [^ ]* +uh9 +[0-9a-f]+ [^ ]* +uh9 +[0-9a-f]+ [^ ]* +(lr1|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(lr1|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(lr2|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(lr2|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +wr3 +[0-9a-f]+ [^ ]* +wr3 +[0-9a-f]+ [^ ]* +wr4 +[0-9a-f]+ [^ ]* +wr5 +[0-9a-f]+ [^ ]* +(lr6|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +ur6 +[0-9a-f]+ [^ ]* +(lr7|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(lr7|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld1|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld2|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld3|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld4|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +ud5 +[0-9a-f]+ [^ ]* +(gd6|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(gd7|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld8|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld8|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld9|\.text)(\+0x[0-9a-f]+)? +[0-9a-f]+ [^ ]* +(ld9|\.text)(\+0x[0-9a-f]+)? diff --git a/gas/testsuite/gas/all/weakref1.s b/gas/testsuite/gas/all/weakref1.s new file mode 100644 index 00000000000..e95e4f4d002 --- /dev/null +++ b/gas/testsuite/gas/all/weakref1.s @@ -0,0 +1,277 @@ + .text +l: +/* a# test references after weakref. */ + .weakref Wwa1, wa1 + .long Wwa1 + + .weakref Wua2, ua2 + .long ua2 + + .weakref Wua3, ua3 + .long Wua3 + .long ua3 + + .weakref Wua4, ua4 + .long ua4 + .long Wua4 + + .weakref Wna5, na5 + +/* b# test references before weakref. */ + .long Wwb1 + .weakref Wwb1, wb1 + + .long ub2 + .weakref Wub2, ub2 + + .long Wub3 + .long ub3 + .weakref Wub3, ub3 + + .long ub4 + .long Wub4 + .weakref Wub4, ub4 + +/* c# test combinations of references before and after weakref. */ + .long Wwc1 + .weakref Wwc1, wc1 + .long Wwc1 + + .long uc2 + .weakref Wuc2, uc2 + .long uc2 + + .long Wuc3 + .long uc3 + .weakref Wuc3, uc3 + .long Wuc3 + .long uc3 + + .long uc4 + .long Wuc4 + .weakref Wuc4, uc4 + .long uc4 + .long Wuc4 + + .long Wuc5 + .long uc5 + .weakref Wuc5, uc5 + .long uc5 + .long Wuc5 + + .long uc6 + .long Wuc6 + .weakref Wuc6, uc6 + .long uc6 + .long Wuc6 + + .long uc7 + .weakref Wuc7, uc7 + .long Wuc7 + + .long Wuc8 + .weakref Wuc8, uc8 + .long uc8 + + .long Wuc9 + .weakref Wuc9, uc9 + .long Wuc9 + .long uc9 + +/* w# test that explicitly weak target don't lose the weak status */ + .weakref Www1, ww1 + .weak ww1 + .long ww1 + + .weak ww2 + .weakref Www2, ww2 + .long ww2 + + .weak ww3 + .long ww3 + .weakref Www3, ww3 + .long ww3 + + .long ww4 + .weakref Www4, ww4 + .weak ww4 + .long ww4 + + .long ww5 + .weakref Www5, ww5 + .long ww5 + .weak ww5 + + .weakref Www6, ww6 + .weak ww6 + .long Www6 + + .weak ww7 + .weakref Www7, ww7 + .long Www7 + + .weak ww8 + .long Www8 + .weakref Www8, ww8 + .long Www8 + + .long Www9 + .weakref Www9, ww9 + .weak ww9 + .long Www9 + + .long Www10 + .weakref Www10, ww10 + .long Www10 + .weak ww10 + +/* m# test multiple weakrefs */ + .weakref Wnm1, nm1 + .weakref Wnm1, nm1 + + .weakref Wum2, um2 + .weakref Wum2, um2 + .long um2 + + .weakref Wwm3, wm3 + .weakref Wwm3, wm3 + .long Wwm3 + + .weakref Wnm4a, nm4 + .weakref Wnm4b, nm4 + + .weakref Wum5a, um5 + .weakref Wum5b, um5 + .long um5 + + .weakref Wwm6a, wm6 + .weakref Wwm6b, wm6 + .long Wwm6a + + .weakref Wwm7a, wm7 + .weakref Wwm7b, wm7 + .long Wwm7b + + .weakref Wwm8a, wm8 + .long Wwm8b + .weakref Wwm8b, wm8 + +/* h# test weakref chain */ + .weakref Wnh1a, nh1 + .weakref Wnh1b, Wnh1a + .weakref Wnh1c, Wnh1b + + .weakref Wwh2a, wh2 + .weakref Wwh2b, Wwh2a + .long Wwh2b + + .weakref Wwh3a, wh3 + .weakref Wwh3b, Wwh3a + .long Wwh3a + + .weakref Wwh4b, Wwh4a + .weakref Wwh4a, wh4 + .long Wwh4b + + .long Wwh5b + .weakref Wwh5a, wh5 + .weakref Wwh5b, Wwh5a + + .long Wwh6b + .weakref Wwh6b, Wwh6a + .weakref Wwh6a, wh6 + + .weakref Wwh7b, Wwh7a + .long Wwh7b + .weakref Wwh7a, wh7 + + .long Wuh8c + .weakref Wuh8a, uh8 + .weakref Wuh8b, Wuh8a + .weakref Wuh8c, Wuh8b + .long uh8 + + .long Wuh9c + .weakref Wuh9c, Wuh9b + .weakref Wuh9b, Wuh9a + .weakref Wuh9a, uh9 + .long uh9 + +/* r# weakref redefinitions, to and from */ + .weakref lr1, nr1 + .long lr1 + .set lr1, l + .long lr1 + + .long lr2 + .weakref lr2, nr2 + .set lr2, l + .long lr2 + + .set Wwr3, l + .long Wwr3 + .weakref Wwr3, wr3 + .long Wwr3 + + .set Wwr4, l + .weakref Wwr4, wr4 + .long Wwr4 + + .set Wwr5, l + .long Wwr5 + .weakref Wwr5, wr5 + + .weakref lr6, ur6 + .long lr6 + .set lr6, l + .long ur6 + + .weakref lr7, nr7 + .long lr7 +lr7: + .long lr7 + +/* d# target symbol definitions */ + .weakref Wld1, ld1 + .long Wld1 + .set ld1, l + + .weakref Wld2, ld2 + .long Wld2 +ld2: + +ld3: + .weakref Wld3, ld3 + .long Wld3 + +ld4: + .long Wld4 + .weakref Wld4, ld4 + + .global ud5 + .weakref Wud5, ud5 + .long Wud5 + + .global gd6 + .weakref Wgd6, gd6 + .long Wgd6 +gd6: + + .weakref Wgd7, gd7 + .long Wgd7 + .global gd7 +gd7: + + .long Wld8c + .weakref Wld8a, ld8 + .weakref Wld8b, Wld8a + .weakref Wld8c, Wld8b + .long ld8 +ld8: + + .long Wld9c + .weakref Wld9c, Wld9b + .weakref Wld9b, Wld9a + .weakref Wld9a, ld9 + .long ld9 +ld9: diff --git a/gas/testsuite/gas/all/weakref1g.d b/gas/testsuite/gas/all/weakref1g.d new file mode 100644 index 00000000000..999a3fc390a --- /dev/null +++ b/gas/testsuite/gas/all/weakref1g.d @@ -0,0 +1,18 @@ +#nm: --defined-only --extern-only --no-sort +#name: weakref tests, global syms +#source: weakref1.s +# see weakref1.d for comments on the not-targets +# ecoff (OSF/alpha) lacks .weak support +# pdp11 lacks .long +#not-target: alpha*-*-osf* *-*-ecoff pdp11-*-aout + +# the rest of this file is generated with the following script: +# # script begin +# echo \#... +# sed -n 's,^[ ]*\.global \(g.*\),.* T \1,p' weakref1.s | uniq +# echo \#pass +# # script output: +#... +.* T gd6 +.* T gd7 +#pass diff --git a/gas/testsuite/gas/all/weakref1l.d b/gas/testsuite/gas/all/weakref1l.d new file mode 100644 index 00000000000..177d1f7889a --- /dev/null +++ b/gas/testsuite/gas/all/weakref1l.d @@ -0,0 +1,35 @@ +#nm: --defined-only --no-sort +#name: weakref tests, local syms +#source: weakref1.s +# aix drops local symbols +# see weakref1.d for comments on the other not-targets +#not-target: *-*-aix* alpha*-*-osf* *-*-ecoff pdp11-*-aout + +# the rest of this file is generated with the following script: +# # script begin +# sed -n 's,^\(l[^ ]*\)[ ]*:.*,.* t \1,p;s:^[ ]*\.set[ ][ ]*\(l[^ ]*\)[ ]*,.*:.* t \1:p' weakref1.s | uniq | while read line; do echo "#..."; echo "$line"; done +# echo \#pass +# # script output: +#... +.* t l +#... +.* t lr1 +#... +.* t lr2 +#... +.* t lr6 +#... +.* t lr7 +#... +.* t ld1 +#... +.* t ld2 +#... +.* t ld3 +#... +.* t ld4 +#... +.* t ld8 +#... +.* t ld9 +#pass diff --git a/gas/testsuite/gas/all/weakref1u.d b/gas/testsuite/gas/all/weakref1u.d new file mode 100644 index 00000000000..f88f73a41ea --- /dev/null +++ b/gas/testsuite/gas/all/weakref1u.d @@ -0,0 +1,53 @@ +#nm: --undefined-only --no-sort +#name: weakref tests, strong undefined syms +#source: weakref1.s +# aout turns undefined into *ABS* symbols. +# see weakref1.d for comments on the other not-targets +#not-target: *-*-aout ns32k-*-netbsd alpha*-*-osf* *-*-ecoff pdp11-*-aout + +# the rest of this file is generated with the following script: +# # script begin +# sed -n 's:^[ ]*\.weakref .*, \(u.*\)$:.* U \1:p' weakref1.s | uniq | while read line; do echo "#..."; echo "$line"; done +# echo \#pass +# # script output: +#... +.* U ua2 +#... +.* U ua3 +#... +.* U ua4 +#... +.* U ub2 +#... +.* U ub3 +#... +.* U ub4 +#... +.* U uc2 +#... +.* U uc3 +#... +.* U uc4 +#... +.* U uc5 +#... +.* U uc6 +#... +.* U uc7 +#... +.* U uc8 +#... +.* U uc9 +#... +.* U um2 +#... +.* U um5 +#... +.* U uh8 +#... +.* U uh9 +#... +.* U ur6 +#... +.* U ud5 +#pass diff --git a/gas/testsuite/gas/all/weakref1w.d b/gas/testsuite/gas/all/weakref1w.d new file mode 100644 index 00000000000..196e6a265ed --- /dev/null +++ b/gas/testsuite/gas/all/weakref1w.d @@ -0,0 +1,64 @@ +#nm: --undefined-only --no-sort +#name: weakref tests, weak undefined syms +#source: weakref1.s +# see weakref1.d for comments on the not-targets +#not-target: alpha*-*-osf* *-*-ecoff pdp11-*-aout + +# the rest of this file is generated with the following script: +# # script begin +# sed -n 's:^[ ]*\.weakref .*, \(w.*\)$:.* w \1:p' weakref1.s | uniq | while read line; do echo "#..."; echo "$line"; done +# echo \#pass +# # script output: +#... +.* w wa1 +#... +.* w wb1 +#... +.* w wc1 +#... +.* w ww1 +#... +.* w ww2 +#... +.* w ww3 +#... +.* w ww4 +#... +.* w ww5 +#... +.* w ww6 +#... +.* w ww7 +#... +.* w ww8 +#... +.* w ww9 +#... +.* w ww10 +#... +.* w wm3 +#... +.* w wm6 +#... +.* w wm7 +#... +.* w wm8 +#... +.* w wh2 +#... +.* w wh3 +#... +.* w wh4 +#... +.* w wh5 +#... +.* w wh6 +#... +.* w wh7 +#... +.* w wr3 +#... +.* w wr4 +#... +.* w wr5 +#pass diff --git a/gas/testsuite/gas/all/weakref2.s b/gas/testsuite/gas/all/weakref2.s new file mode 100644 index 00000000000..0f9cdc701ae --- /dev/null +++ b/gas/testsuite/gas/all/weakref2.s @@ -0,0 +1,5 @@ +.weakref a,b +.weakref b,c +.weakref c,d +.weakref d,e +.weakref e,a diff --git a/gas/testsuite/gas/all/weakref3.s b/gas/testsuite/gas/all/weakref3.s new file mode 100644 index 00000000000..9e5219ad18c --- /dev/null +++ b/gas/testsuite/gas/all/weakref3.s @@ -0,0 +1,5 @@ +.weakref e,a +.weakref d,e +.weakref c,d +.weakref b,c +.weakref a,b diff --git a/gas/write.c b/gas/write.c index a90ee9df444..5546b6849ec 100644 --- a/gas/write.c +++ b/gas/write.c @@ -678,13 +678,15 @@ adjust_reloc_syms (bfd *abfd ATTRIBUTE_UNUSED, /* If this symbol is equated to an undefined or common symbol, convert the fixup to being against that symbol. */ - if (symbol_equated_reloc_p (sym)) + if (symbol_equated_reloc_p (sym) + || S_IS_WEAKREFR (sym)) { symbolS *new_sym = symbol_get_value_expression (sym)->X_add_symbol; const char *name = S_GET_NAME (sym); if (!S_IS_COMMON (new_sym) && !TC_FAKE_LABEL (name) + && !S_IS_WEAKREFR (sym) && (!S_IS_EXTERNAL (sym) || S_IS_LOCAL (sym))) as_bad (_("Local symbol `%s' can't be equated to undefined symbol `%s'"), name, S_GET_NAME (new_sym)); @@ -1483,11 +1485,13 @@ write_object_file (void) /* Skip symbols which were equated to undefined or common symbols. */ - if (symbol_equated_reloc_p (symp)) + if (symbol_equated_reloc_p (symp) + || S_IS_WEAKREFR (symp)) { const char *name = S_GET_NAME (symp); if (S_IS_COMMON (symp) && !TC_FAKE_LABEL (name) + && !S_IS_WEAKREFR (symp) && (!S_IS_EXTERNAL (symp) || S_IS_LOCAL (symp))) { expressionS *e = symbol_get_value_expression (symp); @@ -1524,7 +1528,7 @@ write_object_file (void) opposites. Sometimes the former checks flags and the latter examines the name... */ || (!S_IS_EXTERNAL (symp) - && (punt || S_IS_LOCAL (symp)) + && (punt || S_IS_LOCAL (symp) || S_IS_WEAKREFD (symp)) && ! symbol_used_in_reloc_p (symp))) { symbol_remove (symp, &symbol_rootP, &symbol_lastP);