High adjust relocs mishandled on powerpc

Alan Modra amodra@bigpond.net.au
Tue Aug 22 12:52:00 GMT 2006


When adjusting HA relocs we test for undefined (weak) syms, and if the
sym is undefined, do no adjustment.  This is wrong for GOT and PLT
relocs because the relocation is really to a location in .got or .plt,
not to the symbol itself.  The problem was found when using xlc, which
allows code generation for larger than 64k .got.  GCC code never uses
these relocs.

	* elf32-ppc.c (ppc_elf_relocate_section): Correct GOT and PLT HA
	reloc handling.
	* elf64-ppc.c (ppc64_elf_relocate_section): Likewise.

Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.201
diff -u -p -r1.201 elf32-ppc.c
--- bfd/elf32-ppc.c	23 Jun 2006 02:58:00 -0000	1.201
+++ bfd/elf32-ppc.c	22 Aug 2006 11:13:14 -0000
@@ -6609,25 +6609,28 @@ ppc_elf_relocate_section (bfd *output_bf
 
 	case R_PPC_ADDR16_HA:
 	case R_PPC_REL16_HA:
-	case R_PPC_GOT16_HA:
-	case R_PPC_PLT16_HA:
 	case R_PPC_SECTOFF_HA:
 	case R_PPC_TPREL16_HA:
 	case R_PPC_DTPREL16_HA:
-	case R_PPC_GOT_TLSGD16_HA:
-	case R_PPC_GOT_TLSLD16_HA:
-	case R_PPC_GOT_TPREL16_HA:
-	case R_PPC_GOT_DTPREL16_HA:
 	case R_PPC_EMB_NADDR16_HA:
 	case R_PPC_EMB_RELST_HA:
 	  /* It's just possible that this symbol is a weak symbol
 	     that's not actually defined anywhere.  In that case,
 	     'sec' would be NULL, and we should leave the symbol
 	     alone (it will be set to zero elsewhere in the link).  */
-	  if (sec != NULL)
-	    /* Add 0x10000 if sign bit in 0:15 is set.
-	       Bits 0:15 are not used.  */
-	    addend += 0x8000;
+	  if (sec == NULL)
+	    break;
+	  /* Fall thru */
+
+	case R_PPC_PLT16_HA:
+	case R_PPC_GOT16_HA:
+	case R_PPC_GOT_TLSGD16_HA:
+	case R_PPC_GOT_TLSLD16_HA:
+	case R_PPC_GOT_TPREL16_HA:
+	case R_PPC_GOT_DTPREL16_HA:
+	  /* Add 0x10000 if sign bit in 0:15 is set.
+	     Bits 0:15 are not used.  */
+	  addend += 0x8000;
 	  break;
 	}
 
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.244
diff -u -p -r1.244 elf64-ppc.c
--- bfd/elf64-ppc.c	17 Aug 2006 08:21:06 -0000	1.244
+++ bfd/elf64-ppc.c	22 Aug 2006 12:04:39 -0000
@@ -10928,17 +10928,10 @@ ppc64_elf_relocate_section (bfd *output_
 	case R_PPC64_ADDR16_HA:
 	case R_PPC64_ADDR16_HIGHERA:
 	case R_PPC64_ADDR16_HIGHESTA:
-	case R_PPC64_GOT16_HA:
-	case R_PPC64_PLTGOT16_HA:
-	case R_PPC64_PLT16_HA:
 	case R_PPC64_TOC16_HA:
 	case R_PPC64_SECTOFF_HA:
 	case R_PPC64_TPREL16_HA:
 	case R_PPC64_DTPREL16_HA:
-	case R_PPC64_GOT_TLSGD16_HA:
-	case R_PPC64_GOT_TLSLD16_HA:
-	case R_PPC64_GOT_TPREL16_HA:
-	case R_PPC64_GOT_DTPREL16_HA:
 	case R_PPC64_TPREL16_HIGHER:
 	case R_PPC64_TPREL16_HIGHERA:
 	case R_PPC64_TPREL16_HIGHEST:
@@ -10951,10 +10944,20 @@ ppc64_elf_relocate_section (bfd *output_
 	     that's not actually defined anywhere. In that case,
 	     'sec' would be NULL, and we should leave the symbol
 	     alone (it will be set to zero elsewhere in the link).  */
-	  if (sec != NULL)
-	    /* Add 0x10000 if sign bit in 0:15 is set.
-	       Bits 0:15 are not used.  */
-	    addend += 0x8000;
+	  if (sec == NULL)
+	    break;
+	  /* Fall thru */
+
+	case R_PPC64_GOT16_HA:
+	case R_PPC64_PLTGOT16_HA:
+	case R_PPC64_PLT16_HA:
+	case R_PPC64_GOT_TLSGD16_HA:
+	case R_PPC64_GOT_TLSLD16_HA:
+	case R_PPC64_GOT_TPREL16_HA:
+	case R_PPC64_GOT_DTPREL16_HA:
+	  /* Add 0x10000 if sign bit in 0:15 is set.
+	     Bits 0:15 are not used.  */
+	  addend += 0x8000;
 	  break;
 
 	case R_PPC64_ADDR16_DS:

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre



More information about the Binutils mailing list