Introduce weakref support in the assembler, as described in http://people.redhat.com/aoliva/writeups/weakref/weakref.txt Index: gas/ChangeLog from 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. Index: gas/testsuite/ChangeLog from 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. Index: gas/read.c =================================================================== --- gas/read.c.orig 2005-10-21 10:56:04.000000000 -0200 +++ gas/read.c 2005-10-21 11:34:00.000000000 -0200 @@ -434,6 +434,7 @@ {"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 @@ 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 Index: gas/read.h =================================================================== --- gas/read.h.orig 2005-10-21 10:56:04.000000000 -0200 +++ gas/read.h 2005-10-21 11:00:49.000000000 -0200 @@ -185,3 +185,4 @@ extern void s_xstab (int what); extern void s_rva (int); extern void s_incbin (int); +extern void s_weakref (int); Index: gas/struc-symbol.h =================================================================== --- gas/struc-symbol.h.orig 2005-10-21 10:56:04.000000000 -0200 +++ gas/struc-symbol.h 2005-10-21 11:00:49.000000000 -0200 @@ -72,6 +72,15 @@ 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 Index: gas/symbols.c =================================================================== --- gas/symbols.c.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/symbols.c 2005-10-21 11:00:49.000000000 -0200 @@ -309,6 +309,7 @@ if ((symbolP = symbol_find (sym_name)) != 0) { + S_CLEAR_WEAKREFR (symbolP); #ifdef RESOLVE_SYMBOL_REDEFINITION if (RESOLVE_SYMBOL_REDEFINITION (symbolP)) return symbolP; @@ -651,18 +652,41 @@ 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 { char *copy; @@ -690,7 +714,7 @@ *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 @@ 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 @@ } resolved = symbol_resolved_p (add_symbol); + if (S_IS_WEAKREFR (symp)) + goto exit_dont_set_value; break; case O_uminus: @@ -1717,6 +1756,9 @@ 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->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,10 +1849,32 @@ { 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) { if (LOCAL_SYMBOL_CHECK (s)) @@ -2008,11 +2073,71 @@ { 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) { if (LOCAL_SYMBOL_CHECK (s)) @@ -2095,6 +2220,7 @@ 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 @@ return; } s->sy_frag = f; + S_CLEAR_WEAKREFR (s); } /* Return the frag of a symbol. */ @@ -2149,6 +2276,8 @@ 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 @@ 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)) { Index: gas/symbols.h =================================================================== --- gas/symbols.h.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/symbols.h 2005-10-21 11:00:49.000000000 -0200 @@ -37,7 +37,9 @@ 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 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_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 *); Index: gas/write.c =================================================================== --- gas/write.c.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/write.c 2005-10-21 11:00:49.000000000 -0200 @@ -678,13 +678,15 @@ /* 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 @@ /* 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 @@ 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); Index: gas/doc/as.texinfo =================================================================== --- gas/doc/as.texinfo.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/doc/as.texinfo 2005-10-21 11:00:49.000000000 -0200 @@ -3842,6 +3842,7 @@ * 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 @@ 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}} Index: gas/doc/internals.texi =================================================================== --- gas/doc/internals.texi.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/doc/internals.texi 2005-10-21 11:00:49.000000000 -0200 @@ -93,6 +93,13 @@ 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 @@ @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 @@ @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 @@ 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 Index: gas/testsuite/gas/all/gas.exp =================================================================== --- gas/testsuite/gas/all/gas.exp.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/testsuite/gas/all/gas.exp 2005-10-21 11:00:49.000000000 -0200 @@ -250,6 +250,14 @@ 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]] "" "" Index: gas/testsuite/gas/all/weakref1.d =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref1.d 2005-10-21 11:47:05.000000000 -0200 @@ -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]+)? Index: gas/testsuite/gas/all/weakref1.s =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref1.s 2005-10-21 11:02:52.000000000 -0200 @@ -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: Index: gas/testsuite/gas/all/weakref2.s =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref2.s 2005-10-21 11:00:49.000000000 -0200 @@ -0,0 +1,5 @@ +.weakref a,b +.weakref b,c +.weakref c,d +.weakref d,e +.weakref e,a Index: gas/testsuite/gas/all/weakref3.s =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref3.s 2005-10-21 11:00:49.000000000 -0200 @@ -0,0 +1,5 @@ +.weakref e,a +.weakref d,e +.weakref c,d +.weakref b,c +.weakref a,b Index: gas/config/obj-coff.c =================================================================== --- gas/config/obj-coff.c.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/config/obj-coff.c 2005-10-21 11:00:49.000000000 -0200 @@ -1055,6 +1055,39 @@ 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 @@ char *name; int c; symbolS *symbolP; -#ifdef TE_PE - symbolS *alternateP; -#endif do { @@ -1085,23 +1115,6 @@ 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 @@ { /* 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 @@ && !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 @@ 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) { Index: gas/config/obj-coff.h =================================================================== --- gas/config/obj-coff.h.orig 2005-10-21 10:56:05.000000000 -0200 +++ gas/config/obj-coff.h 2005-10-21 11:00:49.000000000 -0200 @@ -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_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); Index: gas/testsuite/gas/all/weakref1w.d =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref1w.d 2005-10-21 11:46:21.000000000 -0200 @@ -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 Index: gas/testsuite/gas/all/weakref1g.d =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref1g.d 2005-10-21 11:46:40.000000000 -0200 @@ -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 Index: gas/testsuite/gas/all/weakref1l.d =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref1l.d 2005-10-21 11:45:56.000000000 -0200 @@ -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 Index: gas/testsuite/gas/all/weakref1u.d =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gas/testsuite/gas/all/weakref1u.d 2005-10-21 11:45:50.000000000 -0200 @@ -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