aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2004-11-08 08:12:53 +0000
committerNick Clifton <nickc@redhat.com>2004-11-08 08:12:53 +0000
commit977cdf5aa7f4f2183060c150041405abbc2410a9 (patch)
tree0cebac5641d1ecd4b8869005951d8d51ecfa973c /gas
parent998b0029709cba36a9e2da16a83bdcbb6e37b2ae (diff)
downloadgdb-977cdf5aa7f4f2183060c150041405abbc2410a9.zip
gdb-977cdf5aa7f4f2183060c150041405abbc2410a9.tar.gz
gdb-977cdf5aa7f4f2183060c150041405abbc2410a9.tar.bz2
Fix support for PECOFF weak symbols
Diffstat (limited to 'gas')
-rw-r--r--gas/ChangeLog24
-rw-r--r--gas/config/obj-coff.c196
-rw-r--r--gas/config/obj-coff.h11
-rw-r--r--gas/config/tc-i386.c15
-rw-r--r--gas/doc/as.texinfo21
-rw-r--r--gas/symbols.c21
-rw-r--r--gas/symbols.h4
-rw-r--r--gas/tc.h8
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 *);
diff --git a/gas/tc.h b/gas/tc.h
index 2f77c5f..6a06626 100644
--- a/gas/tc.h
+++ b/gas/tc.h
@@ -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