From 77db8e2e96ba37bb1915261d21f7287f15b67bf8 Mon Sep 17 00:00:00 2001
From: Nick Clifton <nickc@redhat.com>
Date: Thu, 29 Apr 2010 14:44:15 +0000
Subject: [PATCH]         * write.c (fixup_segment): Do not assume we know the
 section a         defined weak symbol is in.         * config/tc-arm.c
 (relax_adr, relax_branch, md_apply_fix): Treat         weak symbols as not
 known to be in the same section, even if they         are defined.

        * gas/arm/weakdef-1.s: New.
        * gas/arm/weakdef-1.d: New.
        * gas/arm/weakdef-2.s: New.
        * gas/arm/weakdef-2.d: New.
        * gas/arm/weakdef-2.l: New.
---
 gas/ChangeLog                     |  8 ++++
 gas/config/tc-arm.c               | 66 ++++++++++++++++---------------
 gas/testsuite/ChangeLog           |  8 ++++
 gas/testsuite/gas/arm/weakdef-1.d | 20 ++++++++++
 gas/testsuite/gas/arm/weakdef-1.s | 18 +++++++++
 gas/testsuite/gas/arm/weakdef-2.d |  5 +++
 gas/testsuite/gas/arm/weakdef-2.l |  3 ++
 gas/testsuite/gas/arm/weakdef-2.s | 10 +++++
 gas/write.c                       |  4 +-
 9 files changed, 110 insertions(+), 32 deletions(-)
 create mode 100644 gas/testsuite/gas/arm/weakdef-1.d
 create mode 100644 gas/testsuite/gas/arm/weakdef-1.s
 create mode 100644 gas/testsuite/gas/arm/weakdef-2.d
 create mode 100644 gas/testsuite/gas/arm/weakdef-2.l
 create mode 100644 gas/testsuite/gas/arm/weakdef-2.s

diff --git a/gas/ChangeLog b/gas/ChangeLog
index 961b716947..c2b3faab86 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,11 @@
+2010-04-29  Nathan Sidwell  <nathan@codesourcery.com>
+
+	* write.c (fixup_segment): Do not assume we know the section a
+	defined weak symbol is in.
+	* config/tc-arm.c (relax_adr, relax_branch, md_apply_fix): Treat
+	weak symbols as not known to be in the same section, even if they
+	are defined.
+
 2010-04-27  Joseph Myers  <joseph@codesourcery.com>
 
 	* config/tc-tic6x.h (tic6x_label_list): New.
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index b7ea21b69c..a50ac1d6c6 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -18530,7 +18530,8 @@ relax_adr (fragS *fragp, asection *sec, long stretch)
   /* Assume worst case for symbols not known to be in the same section.  */
   if (fragp->fr_symbol == NULL
       || !S_IS_DEFINED (fragp->fr_symbol)
-      || sec != S_GET_SEGMENT (fragp->fr_symbol))
+      || sec != S_GET_SEGMENT (fragp->fr_symbol)
+      || S_IS_WEAK (fragp->fr_symbol))
     return 4;
 
   val = relaxed_symbol_addr (fragp, stretch);
@@ -18573,7 +18574,8 @@ relax_branch (fragS *fragp, asection *sec, int bits, long stretch)
 
   /* Assume worst case for symbols not known to be in the same section.  */
   if (!S_IS_DEFINED (fragp->fr_symbol)
-      || sec != S_GET_SEGMENT (fragp->fr_symbol))
+      || sec != S_GET_SEGMENT (fragp->fr_symbol)
+      || S_IS_WEAK (fragp->fr_symbol))
     return 4;
 
 #ifdef OBJ_ELF
@@ -19784,22 +19786,23 @@ md_apply_fix (fixS *	fixP,
 	 not have a reloc for it, so tc_gen_reloc will reject it.  */
       fixP->fx_done = 1;
 
-      if (fixP->fx_addsy
-	  && ! S_IS_DEFINED (fixP->fx_addsy))
+      if (fixP->fx_addsy)
 	{
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("undefined symbol %s used as an immediate value"),
-			S_GET_NAME (fixP->fx_addsy));
-	  break;
-	}
+	  const char *msg = 0;
 
-      if (fixP->fx_addsy
-	  && S_GET_SEGMENT (fixP->fx_addsy) != seg)
-	{
-	  as_bad_where (fixP->fx_file, fixP->fx_line,
-			_("symbol %s is in a different section"),
-			S_GET_NAME (fixP->fx_addsy));
-	  break;
+	  if (! S_IS_DEFINED (fixP->fx_addsy))
+	    msg = _("undefined symbol %s used as an immediate value");
+	  else if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
+	    msg = _("symbol %s is in a different section");
+	  else if (S_IS_WEAK (fixP->fx_addsy))
+	    msg = _("symbol %s is weak and may be overridden later");
+
+	  if (msg)
+	    {
+	      as_bad_where (fixP->fx_file, fixP->fx_line,
+			    msg, S_GET_NAME (fixP->fx_addsy));
+	      break;
+	    }
 	}
 
       newimm = encode_arm_immediate (value);
@@ -19825,24 +19828,25 @@ md_apply_fix (fixS *	fixP,
 	unsigned int highpart = 0;
 	unsigned int newinsn  = 0xe1a00000; /* nop.  */
 
-	if (fixP->fx_addsy
-	    && ! S_IS_DEFINED (fixP->fx_addsy))
+	if (fixP->fx_addsy)
 	  {
-	    as_bad_where (fixP->fx_file, fixP->fx_line,
-			  _("undefined symbol %s used as an immediate value"),
-			  S_GET_NAME (fixP->fx_addsy));
-	    break;
-	  }
+	    const char *msg = 0;
 
-	if (fixP->fx_addsy
-	    && S_GET_SEGMENT (fixP->fx_addsy) != seg)
-	  {
-	    as_bad_where (fixP->fx_file, fixP->fx_line,
-			  _("symbol %s is in a different section"),
-			  S_GET_NAME (fixP->fx_addsy));
-	    break;
-	  }
+	    if (! S_IS_DEFINED (fixP->fx_addsy))
+	      msg = _("undefined symbol %s used as an immediate value");
+	    else if (S_GET_SEGMENT (fixP->fx_addsy) != seg)
+	      msg = _("symbol %s is in a different section");
+	    else if (S_IS_WEAK (fixP->fx_addsy))
+	      msg = _("symbol %s is weak and may be overridden later");
 
+	    if (msg)
+	      {
+		as_bad_where (fixP->fx_file, fixP->fx_line,
+			      msg, S_GET_NAME (fixP->fx_addsy));
+		break;
+	      }
+	  }
+	
 	newimm = encode_arm_immediate (value);
 	temp = md_chars_to_number (buf, INSN_SIZE);
 
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index f381115a4e..c9eae547f7 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2010-04-29  Nathan Sidwell  <nathan@codesourcery.com>
+
+	* gas/arm/weakdef-1.s: New.
+	* gas/arm/weakdef-1.d: New.
+	* gas/arm/weakdef-2.s: New.
+	* gas/arm/weakdef-2.d: New.
+	* gas/arm/weakdef-2.l: New.
+
 2010-04-27  Joseph Myers  <joseph@codesourcery.com>
 
 	* gas/tic6x/align-1-be.d, gas/tic6x/align-1.d,
diff --git a/gas/testsuite/gas/arm/weakdef-1.d b/gas/testsuite/gas/arm/weakdef-1.d
new file mode 100644
index 0000000000..8351fc23c4
--- /dev/null
+++ b/gas/testsuite/gas/arm/weakdef-1.d
@@ -0,0 +1,20 @@
+# name: Thumb branch to weak
+# as:
+# objdump: -dr
+# This test is only valid on ELF based ports.
+#not-target: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
+
+.*: +file format .*arm.*
+
+
+Disassembly of section .text:
+
+0+000 <Weak>:
+   0:	e7fe      	b.n	2 <Strong>
+			0: R_ARM_THM_JUMP11	Strong
+
+0+002 <Strong>:
+   2:	f7ff bffe 	b.w	0 <Random>
+			2: R_ARM_THM_JUMP24	Random
+   6:	f7ff bffe 	b.w	0 <Weak>
+			6: R_ARM_THM_JUMP24	Weak
diff --git a/gas/testsuite/gas/arm/weakdef-1.s b/gas/testsuite/gas/arm/weakdef-1.s
new file mode 100644
index 0000000000..4aa6bc46a4
--- /dev/null
+++ b/gas/testsuite/gas/arm/weakdef-1.s
@@ -0,0 +1,18 @@
+	.syntax unified
+	.text
+	.thumb
+
+	.globl	Weak
+	.weak	Weak
+	.thumb_func
+	.type	Weak, %function
+Weak:
+	b	Strong
+	.size	Weak, .-Weak
+	
+	.globl	Strong
+	.type	Strong, %function
+Strong:
+	b	Random
+	b	Weak
+	.size	Strong, .-Strong
diff --git a/gas/testsuite/gas/arm/weakdef-2.d b/gas/testsuite/gas/arm/weakdef-2.d
new file mode 100644
index 0000000000..e0ff272abb
--- /dev/null
+++ b/gas/testsuite/gas/arm/weakdef-2.d
@@ -0,0 +1,5 @@
+# name: adr of weak
+# as:
+# error-output: weakdef-2.l
+# This test is only valid on ELF based ports.
+#not-target: *-*-*coff *-*-pe *-*-wince *-*-*aout* *-*-netbsd *-*-riscix*
diff --git a/gas/testsuite/gas/arm/weakdef-2.l b/gas/testsuite/gas/arm/weakdef-2.l
new file mode 100644
index 0000000000..7aec5e1ffd
--- /dev/null
+++ b/gas/testsuite/gas/arm/weakdef-2.l
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+[^:]*:9: Error: symbol Weak is weak and may be overridden later
+[^:]*:10: Error: symbol Weak is weak and may be overridden later
diff --git a/gas/testsuite/gas/arm/weakdef-2.s b/gas/testsuite/gas/arm/weakdef-2.s
new file mode 100644
index 0000000000..08da196159
--- /dev/null
+++ b/gas/testsuite/gas/arm/weakdef-2.s
@@ -0,0 +1,10 @@
+	.syntax unified
+	.text
+	.globl	Strong
+Strong:	
+	adrl	r0,Strong
+	adr	r0,Strong
+	.globl	Weak
+	.weak	Weak
+Weak:	adrl	r0,Weak
+	adr	r0,Weak
diff --git a/gas/write.c b/gas/write.c
index a148b248d2..b50b0d491e 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -992,7 +992,9 @@ fixup_segment (fixS *fixP, segT this_segment)
 
       if (fixP->fx_addsy)
 	{
-	  if (add_symbol_segment == this_segment
+	  if (S_IS_WEAK (fixP->fx_addsy))
+	    ; // even if it is defined, it might be overridden later
+	  else if (add_symbol_segment == this_segment
 	      && !TC_FORCE_RELOCATION_LOCAL (fixP))
 	    {
 	      /* This fixup was made when the symbol's segment was
-- 
2.42.0