2012-09-18  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/14591
	* elf-bfd.h (_bfd_elf_merge_symbol): Add an argument to return 
	if the old symbol is weak.

	* elf32-sh-symbian.c (sh_symbian_relocate_section): Update
	_bfd_elf_merge_symbol call.

	* elflink.c (_bfd_elf_merge_symbol): Add an argument to return
	if the old symbol is weak.
	(_bfd_elf_add_default_symbol): Update _bfd_elf_merge_symbol
	call.
	(elf_link_add_object_symbols): Don't update symbol type from a
	weak definition.  Update symbol type from a common symbol when
	overriding a weak symbol.

	PR ld/14591
	* ld-ifunc/ifunc.exp (run_ld_link_exec_tests): New.
	* ld-ifunc/ifunc-17a-i386.d: Likewise.
	* ld-ifunc/ifunc-17a-x86-64.d: Likewise.
	* ld-ifunc/ifunc-17a.s: Likewise.
	* ld-ifunc/ifunc-17b-i386.d: Likewise.
	* ld-ifunc/ifunc-17b-x86-64.d: Likewise.
	* ld-ifunc/ifunc-17b.s: Likewise.
	* ld-ifunc/ifunc-common-1.out: Likewise.
	* ld-ifunc/ifunc-common-1a.c: Likewise.
	* ld-ifunc/ifunc-common-1b.c: Likewise.

===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.343.2.1
retrieving revision 1.343.2.2
diff -u -r1.343.2.1 -r1.343.2.2
--- src/bfd/elf-bfd.h	2012/08/16 09:21:36	1.343.2.1
+++ src/bfd/elf-bfd.h	2012/09/24 12:22:45	1.343.2.2
@@ -1967,7 +1967,7 @@
 
 extern bfd_boolean _bfd_elf_merge_symbol
   (bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
-   asection **, bfd_vma *, unsigned int *,
+   asection **, bfd_vma *, bfd_boolean *, unsigned int *,
    struct elf_link_hash_entry **, bfd_boolean *,
    bfd_boolean *, bfd_boolean *, bfd_boolean *);
 
===================================================================
RCS file: /cvs/src/src/bfd/elf32-sh-symbian.c,v
retrieving revision 1.15
retrieving revision 1.15.12.1
diff -u -r1.15 -r1.15.12.1
--- src/bfd/elf32-sh-symbian.c	2011/03/14 15:54:58	1.15
+++ src/bfd/elf32-sh-symbian.c	2012/09/24 12:22:45	1.15.12.1
@@ -497,7 +497,7 @@
 	      if (! _bfd_elf_merge_symbol (input_bfd, info,
 					   ptr->new_name, & new_sym,
 					   & psec, & new_value, NULL,
-					   & new_hash, & skip,
+					   NULL, & new_hash, & skip,
 					   & override, & type_change_ok,
 					   & size_change_ok))
 		{
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.450.4.1
retrieving revision 1.450.4.2
diff -u -r1.450.4.1 -r1.450.4.2
--- src/bfd/elflink.c	2012/09/04 14:37:52	1.450.4.1
+++ src/bfd/elflink.c	2012/09/24 12:22:45	1.450.4.2
@@ -938,6 +938,7 @@
 		       Elf_Internal_Sym *sym,
 		       asection **psec,
 		       bfd_vma *pvalue,
+		       bfd_boolean *pold_weak,
 		       unsigned int *pold_alignment,
 		       struct elf_link_hash_entry **sym_hash,
 		       bfd_boolean *skip,
@@ -1040,6 +1041,8 @@
   newweak = bind == STB_WEAK;
   oldweak = (h->root.type == bfd_link_hash_defweak
 	     || h->root.type == bfd_link_hash_undefweak);
+  if (pold_weak)
+    *pold_weak = oldweak;
 
   /* In cases involving weak versioned symbols, we may wind up trying
      to merge a symbol with itself.  Catch that here, to avoid the
@@ -1662,7 +1665,7 @@
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-			      NULL, &hi, &skip, &override,
+			      NULL, NULL, &hi, &skip, &override,
 			      &type_change_ok, &size_change_ok))
     return FALSE;
 
@@ -1771,7 +1774,7 @@
   size_change_ok = FALSE;
   sec = *psec;
   if (!_bfd_elf_merge_symbol (abfd, info, shortname, sym, &sec, value,
-			      NULL, &hi, &skip, &override,
+			      NULL, NULL, &hi, &skip, &override,
 			      &type_change_ok, &size_change_ok))
     return FALSE;
 
@@ -3865,6 +3868,8 @@
       bfd_boolean size_change_ok;
       bfd_boolean type_change_ok;
       bfd_boolean new_weakdef;
+      bfd_boolean new_weak;
+      bfd_boolean old_weak;
       bfd_boolean override;
       bfd_boolean common;
       unsigned int old_alignment;
@@ -3997,6 +4002,7 @@
 
       size_change_ok = FALSE;
       type_change_ok = bed->type_change_ok;
+      old_weak = FALSE;
       old_alignment = 0;
       old_bfd = NULL;
       new_sec = sec;
@@ -4142,7 +4148,7 @@
 	    }
 
 	  if (!_bfd_elf_merge_symbol (abfd, info, name, isym, &sec,
-				      &value, &old_alignment,
+				      &value, &old_weak, &old_alignment,
 				      sym_hash, &skip, &override,
 				      &type_change_ok, &size_change_ok))
 	    goto error_free_vers;
@@ -4204,10 +4210,11 @@
       if (is_elf_hash_table (htab))
 	h->unique_global = (flags & BSF_GNU_UNIQUE) != 0;
 
+      new_weak = (flags & BSF_WEAK) != 0;
       new_weakdef = FALSE;
       if (dynamic
 	  && definition
-	  && (flags & BSF_WEAK) != 0
+	  && new_weak
 	  && !bed->is_function_type (ELF_ST_TYPE (isym->st_info))
 	  && is_elf_hash_table (htab)
 	  && h->u.weakdef == NULL)
@@ -4336,7 +4343,9 @@
 	    h->size = h->root.u.c.size;
 
 	  if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE
-	      && (definition || h->type == STT_NOTYPE))
+	      && ((definition && !new_weak)
+		  || (old_weak && h->root.type == bfd_link_hash_common)
+		  || h->type == STT_NOTYPE))
 	    {
 	      unsigned int type = ELF_ST_TYPE (isym->st_info);
 
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-17a-i386.d,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-17a-i386.d
+++ -	2012-09-28 07:57:07.532241000 +0000
@@ -0,0 +1,10 @@
+#source: ifunc-17a.s
+#source: ifunc-17b.s
+#ld: -static -m elf_i386
+#as: --32
+#readelf: -s --wide
+#target: x86_64-*-* i?86-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-17a-x86-64.d,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-17a-x86-64.d
+++ -	2012-09-28 07:57:14.532213000 +0000
@@ -0,0 +1,10 @@
+#source: ifunc-17a.s
+#source: ifunc-17b.s
+#ld: -static -m elf_x86_64
+#as: --64
+#readelf: -s --wide
+#target: x86_64-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-17a.s,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-17a.s
+++ -	2012-09-28 07:57:21.611511000 +0000
@@ -0,0 +1,11 @@
+	.globl main
+	.globl start
+	.globl _start
+	.globl __start
+	.text
+main:
+start:
+_start:
+__start:
+	.byte 0
+	.common	foo,4,4
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-17b-i386.d,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-17b-i386.d
+++ -	2012-09-28 07:57:30.498534000 +0000
@@ -0,0 +1,10 @@
+#source: ifunc-17b.s
+#source: ifunc-17a.s
+#ld: -static -m elf_i386
+#as: --32
+#readelf: -s --wide
+#target: x86_64-*-* i?86-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-17b-x86-64.d,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-17b-x86-64.d
+++ -	2012-09-28 07:57:37.873057000 +0000
@@ -0,0 +1,10 @@
+#source: ifunc-17b.s
+#source: ifunc-17a.s
+#ld: -static -m elf_x86_64
+#as: --64
+#readelf: -s --wide
+#target: x86_64-*-*
+
+#...
+ +[0-9]+: +[0-9a-f]+ +4 +OBJECT +GLOBAL +DEFAULT +[1-9] foo
+#pass
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-17b.s,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-17b.s
+++ -	2012-09-28 07:57:46.042556000 +0000
@@ -0,0 +1,6 @@
+	.weak	foo
+	.type foo, %gnu_indirect_function
+	.size	foo,1
+	.text
+foo:
+	.byte	1
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-common-1.out,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-common-1.out
+++ -	2012-09-28 07:57:54.613639000 +0000
@@ -0,0 +1 @@
+PASSED: 0
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-common-1a.c,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-common-1a.c
+++ -	2012-09-28 07:58:03.286806000 +0000
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int foo;
+int
+main ()
+{
+  printf ("PASSED: %d\n", foo);
+  return 0;
+}
/cvs/src/src/ld/testsuite/ld-ifunc/ifunc-common-1b.c,v  -->  standard output
revision 1.1.2.1
--- src/ld/testsuite/ld-ifunc/ifunc-common-1b.c
+++ -	2012-09-28 07:58:11.504734000 +0000
@@ -0,0 +1,12 @@
+void alt (void) { }
+
+void foo (void);
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+__asm__(".weak foo");
+
+void *
+foo_ifunc (void)
+{
+  return alt;
+}
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-ifunc/ifunc.exp,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -u -r1.13 -r1.13.2.1
--- src/ld/testsuite/ld-ifunc/ifunc.exp	2012/04/03 16:01:37	1.13
+++ src/ld/testsuite/ld-ifunc/ifunc.exp	2012/09/24 12:22:49	1.13.2.1
@@ -347,6 +347,27 @@
     remote_file host delete "tmpdir/static_nonifunc_prog"
 }
 
+run_ld_link_exec_tests [] [list \
+    [list \
+	"Common symbol override ifunc test 1a" \
+	"-static" \
+	"" \
+	{ ifunc-common-1a.c ifunc-common-1b.c } \
+	"ifunc-common-1a" \
+	"ifunc-common-1.out" \
+	"-g" \
+    ] \
+    [list \
+	"Common symbol override ifunc test 1b" \
+	"-static" \
+	"" \
+	{ ifunc-common-1b.c ifunc-common-1a.c } \
+	"ifunc-common-1b" \
+	"ifunc-common-1.out" \
+	"-g" \
+    ] \
+]
+
 set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
 foreach t $test_list {
     # We need to strip the ".d", but can leave the dirname.
