diff options
author | Nick Clifton <nickc@redhat.com> | 2004-11-08 08:12:53 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2004-11-08 08:12:53 +0000 |
commit | 977cdf5aa7f4f2183060c150041405abbc2410a9 (patch) | |
tree | 0cebac5641d1ecd4b8869005951d8d51ecfa973c /gas | |
parent | 998b0029709cba36a9e2da16a83bdcbb6e37b2ae (diff) | |
download | gdb-977cdf5aa7f4f2183060c150041405abbc2410a9.zip gdb-977cdf5aa7f4f2183060c150041405abbc2410a9.tar.gz gdb-977cdf5aa7f4f2183060c150041405abbc2410a9.tar.bz2 |
Fix support for PECOFF weak symbols
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 24 | ||||
-rw-r--r-- | gas/config/obj-coff.c | 196 | ||||
-rw-r--r-- | gas/config/obj-coff.h | 11 | ||||
-rw-r--r-- | gas/config/tc-i386.c | 15 | ||||
-rw-r--r-- | gas/doc/as.texinfo | 21 | ||||
-rw-r--r-- | gas/symbols.c | 21 | ||||
-rw-r--r-- | gas/symbols.h | 4 | ||||
-rw-r--r-- | gas/tc.h | 8 |
8 files changed, 223 insertions, 77 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 184a579..d5efcc7 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,27 @@ +2004-11-08 Aaron W. LaFramboise <aaron98wiridge9@aaronwl.com> + + * symbols.c (any_external_name): Define. + (resolve_symbol_value): Do not convert weak symbols. + (S_SET_EXTERNAL): Support any_external_name. + (S_SET_NAME): Qualify parameter const. + (symbol_equated_reloc_p): Don't equate weaks when relocating. + * symbols.h (S_SET_NAME): Qualfiy parameter const. + * tc.h (any_external_name): Declare. + * config/obj-coff.c ("coff/pe.h"): Include for BFD + assemblers also. + (weak_is_altname): Declare and define. + (weak_name2altname): Same. + (weak_altname2name): Same. + (weak_uniquify): Same. + (weak_altprefix): Define. + (obj_coff_weak): Change .weak syntax and handling. + (coff_frob_symbol): Fix PE weak symbol alternates. + * config/obj-coff.h (USE_UNIQUE): Define. + * config/tc-i386.c (md_apply_fix3): Assume weak symbols + are in another segment. + (tc_gen_reloc): Remove broken addend hack. + doc/as.texinfo: Update. + 2004-11-05 Sterling Augustine <sterling@tensilica.com> * config/tc-xtensa.c (total_frag_text_expansion): New. diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c index 1451d9d..96aac42 100644 --- a/gas/config/obj-coff.c +++ b/gas/config/obj-coff.c @@ -26,6 +26,10 @@ #include "obstack.h" #include "subsegs.h" +#ifdef TE_PE +#include "coff/pe.h" +#endif + /* I think this is probably always correct. */ #ifndef KEEP_RELOC_INFO #define KEEP_RELOC_INFO @@ -41,6 +45,10 @@ /* This is used to hold the symbol built by a sequence of pseudo-ops from .def and .endef. */ static symbolS *def_symbol_in_progress; +#ifdef TE_PE +/* PE weak alternate symbols begin with this string. */ +static const char weak_altprefix[] = ".weak."; +#endif /* TE_PE */ typedef struct { @@ -1096,14 +1104,84 @@ obj_coff_val (ignore) demand_empty_rest_of_line (); } +#ifdef TE_PE + +/* Return nonzero if name begins with weak alternate symbol prefix. */ + +static int +weak_is_altname (const char * name) +{ + return ! strncmp (name, weak_altprefix, sizeof (weak_altprefix) - 1); +} + +/* Return the name of the alternate symbol + name corresponding to a weak symbol's name. */ + +static const char * +weak_name2altname (const char * name) +{ + char *alt_name; + + alt_name = xmalloc (sizeof (weak_altprefix) + strlen (name)); + strcpy (alt_name, weak_altprefix); + return strcat (alt_name, name); +} + +/* Return the name of the weak symbol corresponding to an + alterate symbol. */ + +static const char * +weak_altname2name (const char * name) +{ + char * weak_name; + char * dot; + + assert (weak_is_altname (name)); + + weak_name = xstrdup (name + 6); + if ((dot = strchr (weak_name, '.'))) + *dot = 0; + return weak_name; +} + +/* Make a weak symbol name unique by + appending the name of an external symbol. */ + +static const char * +weak_uniquify (const char * name) +{ + char *ret; + const char * unique = ""; + +#ifdef USE_UNIQUE + if (an_external_name != NULL) + unique = an_external_name; +#endif + assert (weak_is_altname (name)); + + if (strchr (name + sizeof (weak_altprefix), '.')) + return name; + + ret = xmalloc (strlen (name) + strlen (unique) + 2); + strcpy (ret, name); + strcat (ret, "."); + strcat (ret, unique); + return ret; +} + +#endif /* TE_PE */ + /* Handle .weak. This is a GNU extension in formats other than PE. */ + static void -obj_coff_weak (ignore) - int ignore ATTRIBUTE_UNUSED; +obj_coff_weak (int ignore ATTRIBUTE_UNUSED) { char *name; int c; symbolS *symbolP; +#ifdef TE_PE + symbolS *alternateP; +#endif do { @@ -1115,6 +1193,7 @@ obj_coff_weak (ignore) ignore_rest_of_line (); return; } + c = 0; symbolP = symbol_find_or_make (name); *input_line_pointer = c; SKIP_WHITESPACE (); @@ -1125,42 +1204,20 @@ obj_coff_weak (ignore) #ifdef TE_PE /* See _Microsoft Portable Executable and Common Object - * File Format Specification_, section 5.5.3. - * Note that weak symbols without aux records are a GNU - * extension. - */ + 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_LIBRARY); - if (c == '=') - { - symbolS *alternateP; - long characteristics = 2; - ++input_line_pointer; - if (*input_line_pointer == '=') - { - characteristics = 1; - ++input_line_pointer; - } - - SKIP_WHITESPACE(); - name = input_line_pointer; - c = get_symbol_end(); - if (*name == 0) - { - as_warn (_("alternate name missing in .weak directive")); - ignore_rest_of_line (); - return; - } - alternateP = symbol_find_or_make (name); - *input_line_pointer = c; + alternateP = symbol_find_or_make (weak_name2altname (name)); + S_SET_EXTERNAL (alternateP); + S_SET_STORAGE_CLASS (alternateP, C_NT_WEAK); - S_SET_NUMBER_AUXILIARY (symbolP, 1); - SA_SET_SYM_TAGNDX (symbolP, alternateP); - SA_SET_SYM_FSIZE (symbolP, characteristics); - } -#else /* TE_PE */ - S_SET_STORAGE_CLASS (symbolP, C_WEAKEXT); -#endif /* TE_PE */ + SA_SET_SYM_TAGNDX (symbolP, alternateP); +#endif if (c == ',') { @@ -1214,14 +1271,67 @@ coff_frob_symbol (symp, punt) if (!block_stack) block_stack = stack_init (512, sizeof (symbolS*)); - if (S_IS_WEAK (symp)) - { #ifdef TE_PE - S_SET_STORAGE_CLASS (symp, C_NT_WEAK); -#else - S_SET_STORAGE_CLASS (symp, C_WEAKEXT); -#endif + if (S_GET_STORAGE_CLASS (symp) == C_NT_WEAK + && ! S_IS_WEAK (symp) + && weak_is_altname (S_GET_NAME (symp))) + { + /* 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))); + + assert (weakp); + assert (S_GET_NUMBER_AUXILIARY (weakp) == 1); + + if (symbol_equated_p (weakp)) + { + /* The weak symbol has an alternate specified; symp is unneeded. */ + S_SET_STORAGE_CLASS (weakp, C_NT_WEAK); + SA_SET_SYM_TAGNDX (weakp, + symbol_get_value_expression (weakp)->X_add_symbol); + + S_CLEAR_EXTERNAL (symp); + *punt = 1; + return; + } + else + { + /* The weak symbol has been assigned an alternate value. + Copy this value to symp, and set symp as weakp's alternate. */ + if (S_GET_STORAGE_CLASS (weakp) != C_NT_WEAK) + { + S_SET_STORAGE_CLASS (symp, S_GET_STORAGE_CLASS (weakp)); + S_SET_STORAGE_CLASS (weakp, C_NT_WEAK); + } + + if (S_IS_DEFINED (weakp)) + { + /* This is a defined weak symbol. Copy value information + from the weak symbol itself to the alternate symbol. */ + symbol_set_value_expression (symp, + symbol_get_value_expression (weakp)); + symbol_set_frag (symp, symbol_get_frag (weakp)); + S_SET_SEGMENT (symp, S_GET_SEGMENT (weakp)); + } + else + { + /* This is an undefined weak symbol. + Define the alternate symbol to zero. */ + S_SET_VALUE (symp, 0); + S_SET_SEGMENT (symp, absolute_section); + } + + S_SET_NAME (symp, weak_uniquify (S_GET_NAME (symp))); + S_SET_STORAGE_CLASS (symp, C_EXT); + + S_SET_VALUE (weakp, 0); + S_SET_SEGMENT (weakp, undefined_section); + } } +#else /* TE_PE */ + if (S_IS_WEAK (symp)) + S_SET_STORAGE_CLASS (symp, C_WEAKEXT); +#endif /* TE_PE */ if (!S_IS_DEFINED (symp) && !S_IS_WEAK (symp) @@ -1722,10 +1832,6 @@ symbol_dump () #include "libbfd.h" #include "libcoff.h" -#ifdef TE_PE -#include "coff/pe.h" -#endif - /* The NOP_OPCODE is for the alignment fill value. Fill with nop so that we can stick sections together without causing trouble. */ #ifndef NOP_OPCODE diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h index 5200552..90d7e99 100644 --- a/gas/config/obj-coff.h +++ b/gas/config/obj-coff.h @@ -1,6 +1,6 @@ /* coff object file format Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2002, 2003 + 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GAS. @@ -180,14 +180,19 @@ #endif #endif +#ifdef TE_PE +/* PE weak symbols need USE_UNIQUE. */ +#define USE_UNIQUE 1 +#endif + /* Targets may also set this. Also, if BFD_ASSEMBLER is defined, this will already have been defined. */ -#undef SYMBOLS_NEED_BACKPOINTERS +#undef SYMBOLS_NEED_BACKPOINTERS #define SYMBOLS_NEED_BACKPOINTERS 1 #ifndef OBJ_COFF_MAX_AUXENTRIES #define OBJ_COFF_MAX_AUXENTRIES 1 -#endif /* OBJ_COFF_MAX_AUXENTRIES */ +#endif extern void coff_obj_symbol_new_hook PARAMS ((symbolS *)); #define obj_symbol_new_hook coff_obj_symbol_new_hook diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 606d16b..aa2ec54 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -4801,9 +4801,13 @@ md_apply_fix3 (fixP, valP, seg) } #endif #if defined (OBJ_COFF) && defined (TE_PE) - /* For some reason, the PE format does not store a section - address offset for a PC relative symbol. */ - if (S_GET_SEGMENT (fixP->fx_addsy) != seg) + /* For some reason, the PE format does not store a + section address offset for a PC relative symbol. */ + if (S_GET_SEGMENT (fixP->fx_addsy) != seg +#if defined(BFD_ASSEMBLER) || defined(S_IS_WEAK) + || S_IS_WEAK (fixP->fx_addsy) +#endif + ) value += md_pcrel_from (fixP); #endif } @@ -5378,11 +5382,6 @@ tc_gen_reloc (section, fixp) rel->address = fixp->fx_frag->fr_address + fixp->fx_where; -#ifdef TE_PE - if (S_IS_WEAK (fixp->fx_addsy)) - rel->addend = rel->address - (*rel->sym_ptr_ptr)->value + 4; - else -#endif if (!use_rela_relocations) { /* HACK: Since i386 ELF uses Rel instead of Rela, encode the diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index a73edd7..3d4a5ab 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -5872,24 +5872,13 @@ parent name of @code{0} is treated as refering the @code{*ABS*} section. This directive sets the weak attribute on the comma separated list of symbol @code{names}. If the symbols do not already exist, they will be created. -Weak symbols are supported in COFF as a GNU extension. This directive -sets the weak attribute on the comma separated list of symbol +On COFF targets other than PE, weak symbols are a GNU extension. This +directive sets the weak attribute on the comma separated list of symbol @code{names}. If the symbols do not already exist, they will be created. -@smallexample -@code{.weak @var{name} [ < = | == > @var{alternate}] [, ...]} -@end smallexample - -On the PE target, weak aliases are supported natively. Weak aliases -(usually called "weak externals" in PE) are created when an alternate -name is specified. When a weak symbol is linked and the symbol is not -defined, the weak symbol becomes an alias for the alternate symbol. If -one equal sign is used, the linker searches for defined symbols within -other objects and libraries. This is the usual mode, historically -called "lazy externals." Otherwise, when two equal signs are used, -the linker searches for defined symbols only within other objects. - -Non-alias weak symbols are supported on PE as a GNU extension. +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 Word @section @code{.word @var{expressions}} diff --git a/gas/symbols.c b/gas/symbols.c index 0452416..135c7ef 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -59,6 +59,11 @@ symbolS abs_symbol; #define LOCAL_LABEL_CHAR '\002' struct obstack notes; +#ifdef USE_UNIQUE +/* The name of an external symbol which is + used to make weak PE symbol names unique. */ +const char * an_external_name; +#endif static char *save_symbol_name (const char *); static void fb_label_init (void); @@ -989,7 +994,11 @@ resolve_symbol_value (symbolS *symp) relocation to detect this case, and convert the relocation to be against the symbol to which this symbol is equated. */ - if (! S_IS_DEFINED (add_symbol) || S_IS_COMMON (add_symbol)) + if (! S_IS_DEFINED (add_symbol) +#if defined(BFD_ASSEMBLER) || defined(S_IS_WEAK) + || S_IS_WEAK (add_symbol) +#endif + || S_IS_COMMON (add_symbol)) { if (finalize_syms) { @@ -1905,6 +1914,11 @@ S_SET_EXTERNAL (symbolS *s) } s->bsym->flags |= BSF_GLOBAL; s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK); + +#ifdef USE_UNIQUE + if (! an_external_name && S_GET_NAME(s)[0] != '.') + an_external_name = S_GET_NAME (s); +#endif } void @@ -1949,7 +1963,7 @@ S_SET_THREAD_LOCAL (symbolS *s) } void -S_SET_NAME (symbolS *s, char *name) +S_SET_NAME (symbolS *s, const char *name) { if (LOCAL_SYMBOL_CHECK (s)) { @@ -2225,6 +2239,9 @@ symbol_equated_reloc_p (symbolS *s) resolve_symbol_value to flag expression syms that have been equated. */ return (s->sy_value.X_op == O_symbol +#if defined(BFD_ASSEMBLER) || defined(S_IS_WEAK) + && ! S_IS_WEAK (s) +#endif && ((s->sy_resolved && s->sy_value.X_op_symbol != NULL) || ! S_IS_DEFINED (s) || S_IS_COMMON (s))); diff --git a/gas/symbols.h b/gas/symbols.h index 15dc263..b95ec24 100644 --- a/gas/symbols.h +++ b/gas/symbols.h @@ -1,6 +1,6 @@ /* symbols.h - Copyright 1987, 1990, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001, - 2002, 2003 Free Software Foundation, Inc. + 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -105,7 +105,7 @@ extern const char *S_GET_NAME (symbolS *); extern segT S_GET_SEGMENT (symbolS *); extern void S_SET_SEGMENT (symbolS *, segT); extern void S_SET_EXTERNAL (symbolS *); -extern void S_SET_NAME (symbolS *, char *); +extern void S_SET_NAME (symbolS *, const char *); extern void S_CLEAR_EXTERNAL (symbolS *); extern void S_SET_WEAK (symbolS *); extern void S_SET_THREAD_LOCAL (symbolS *); @@ -1,6 +1,6 @@ /* tc.h - target cpu dependent - Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 2000, 2001, 2003 + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -59,6 +59,12 @@ extern int md_short_jump_size; extern int md_long_jump_size; #endif +#ifdef USE_UNIQUE +/* The name of an external symbol which is + used to make weak PE symbol names unique. */ +extern const char * an_external_name; +#endif + #ifndef md_create_long_jump void md_create_long_jump (char *, addressT, addressT, fragS *, symbolS *); #endif |