From 977cdf5aa7f4f2183060c150041405abbc2410a9 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Mon, 8 Nov 2004 08:12:53 +0000 Subject: Fix support for PECOFF weak symbols --- gas/config/obj-coff.c | 196 ++++++++++++++++++++++++++++++++++++++------------ gas/config/obj-coff.h | 11 ++- gas/config/tc-i386.c | 15 ++-- 3 files changed, 166 insertions(+), 56 deletions(-) (limited to 'gas/config') 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 -- cgit v1.1