2c2fa1
commit 86c9573369616e7437481b6e5533aef3a435cdcf
2c2fa1
Author: Alan Modra <amodra@gmail.com>
2c2fa1
Date:   Sat Mar 8 13:05:06 2014 +1030
2c2fa1
2c2fa1
    Better overflow checking for powerpc32 relocations
2c2fa1
    
2c2fa1
    Similar to the powerpc64 patch, this improves overflow checking in
2c2fa1
    elf32-ppc.c.  Many reloc "howto" entries needed fixes, some just
2c2fa1
    cosmetic.
2c2fa1
    
2c2fa1
    The patch also fixes the R_PPC_VLE_SDA21 reloc application code, which
2c2fa1
    was horribly broken.  In fact, it may still be broken since Power ISA
2c2fa1
    2.07 says e_li behaves as
2c2fa1
       RT <- EXTS(li20 1:4 || li20 5:8 || li20 0 || li20 9:19)
2c2fa1
    where li20 is a field taken from bits 17..20, 11..15, 21..31 of the
2c2fa1
    instruction.  Freescale VLEPEM says differently, and I assume
2c2fa1
    correctly, that
2c2fa1
       RT <- EXTS(li20 0:3 || li20 4:8 || li20 9:19)
2c2fa1
    The VLE_SDA21 relocation description matches this too.
2c2fa1
    
2c2fa1
    Now the VLE_SDA21 relocation specifies in the case where e_addi16 is
2c2fa1
    converted to e_li for symbols in .PPC.EMB.sdata0 or .PPC.EMB.sbss0
2c2fa1
    (no base register), that the field is restricted to 16 bits, with the
2c2fa1
    sign bit being propagated to the top 4 bits.  I don't see the sense in
2c2fa1
    restricting the value like this, so have allowed the full 20 bit
2c2fa1
    signed value.  This of course is compatible with the reloc description
2c2fa1
    in that values in the 16 bit signed range will result in exactly the
2c2fa1
    same insn field as when the reloc description is followed to the
2c2fa1
    letter.
2c2fa1
    
2c2fa1
            * elf32-ppc.c (ppc_elf_howto_raw): Correct overflow check for
2c2fa1
            many relocations.  Correct bitsize and rightshift too for a number
2c2fa1
            of VLE relocs.  Describe R_PPC_VLE_SDA21 and R_PPC_VLE_SDA21_LO.
2c2fa1
            Correct dst_mask on R_PPC_VLE_SDA21_LO.
2c2fa1
            (ppc_elf_vle_split16): Tidy, delete unnecessary prototype.
2c2fa1
            (ppc_elf_relocate_section): Modify overflow test for 16-bit
2c2fa1
            fields in instructions to signed/unsigned according to whether
2c2fa1
            the field takes a signed or unsigned value.  Tidy vle split16 code.
2c2fa1
            Correct R_PPC_VLE_SDA21 and R_PPC_VLE_SDA21_LO handling.
2c2fa1
2c2fa1
### a/bfd/ChangeLog
2c2fa1
### b/bfd/ChangeLog
2c2fa1
## -1,5 +1,17 @@
2c2fa1
 2014-03-08  Alan Modra  <amodra@gmail.com>
2c2fa1
 
2c2fa1
+	* elf32-ppc.c (ppc_elf_howto_raw): Correct overflow check for
2c2fa1
+	many relocations.  Correct bitsize and rightshift too for a number
2c2fa1
+	of VLE relocs.  Describe R_PPC_VLE_SDA21 and R_PPC_VLE_SDA21_LO.
2c2fa1
+	Correct dst_mask on R_PPC_VLE_SDA21_LO.
2c2fa1
+	(ppc_elf_vle_split16): Tidy, delete unnecessary prototype.
2c2fa1
+	(ppc_elf_relocate_section): Modify overflow test for 16-bit
2c2fa1
+	fields in instructions to signed/unsigned according to whether
2c2fa1
+	the field takes a signed or unsigned value.  Tidy vle split16 code.
2c2fa1
+	Correct R_PPC_VLE_SDA21 and R_PPC_VLE_SDA21_LO handling.
2c2fa1
+
2c2fa1
+2014-03-08  Alan Modra  <amodra@gmail.com>
2c2fa1
+
2c2fa1
 	* elf64-ppc.c (ppc64_elf_howto_raw): Use complain_overflow_signed
2c2fa1
 	for R_PPC64_ADDR14, R_PPC64_ADDR14_BRTAKEN, R_PPC64_ADDR14_BRNTAKEN,
2c2fa1
 	R_PPC64_SECTOFF, R_PPC64_ADDR16_DS, R_PPC64_SECTOFF_DS,
2c2fa1
--- a/bfd/elf32-ppc.c
2c2fa1
+++ b/bfd/elf32-ppc.c
2c2fa1
@@ -50,8 +50,6 @@ static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
2c2fa1
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
2c2fa1
 static bfd_reloc_status_type ppc_elf_unhandled_reloc
2c2fa1
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
2c2fa1
-static void ppc_elf_vle_split16
2c2fa1
-  (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type);
2c2fa1
 
2c2fa1
 /* Branch prediction bit for branch taken relocs.  */
2c2fa1
 #define BRANCH_PREDICT_BIT 0x200000
2c2fa1
@@ -192,7 +190,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_NONE",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -207,7 +205,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_ADDR32",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -223,7 +221,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 26,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_ADDR24",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -300,7 +298,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_ADDR14",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -317,7 +315,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_ADDR14_BRTAKEN",/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -334,7 +332,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_ADDR14_BRNTAKEN",/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -446,7 +444,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_GOT16_HI",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -462,7 +460,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 ppc_elf_addr16_ha_reloc, /* special_function */
2c2fa1
 	 "R_PPC_GOT16_HA",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -497,7 +495,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_COPY",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -513,7 +511,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_GLOB_DAT",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -528,7 +526,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_JMP_SLOT",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -545,7 +543,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_RELATIVE",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -577,7 +575,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_UADDR32",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -607,7 +605,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 TRUE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_REL32",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -623,7 +621,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_PLT32",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -639,7 +637,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 TRUE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_PLTREL32",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -671,7 +669,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_PLT16_HI",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -687,7 +685,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 ppc_elf_addr16_ha_reloc, /* special_function */
2c2fa1
 	 "R_PPC_PLT16_HA",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -718,7 +716,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_SECTOFF",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -748,7 +746,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_SECTOFF_HI",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -763,7 +761,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 ppc_elf_addr16_ha_reloc, /* special_function */
2c2fa1
 	 "R_PPC_SECTOFF_HA",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1239,7 +1237,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_EMB_NADDR32",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1254,7 +1252,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_EMB_NADDR16",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1449,10 +1447,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
   HOWTO (R_PPC_VLE_LO16A,	/* type */
2c2fa1
 	 0,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_LO16A",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1464,10 +1462,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
   HOWTO (R_PPC_VLE_LO16D,	/* type */
2c2fa1
 	 0,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_LO16D",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1477,12 +1475,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 split16a format.  */
2c2fa1
   HOWTO (R_PPC_VLE_HI16A,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_HI16A",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1492,12 +1490,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 split16d format.  */
2c2fa1
   HOWTO (R_PPC_VLE_HI16D,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_HI16D",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1507,12 +1505,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 (High Adjusted) in split16a format.  */
2c2fa1
   HOWTO (R_PPC_VLE_HA16A,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_HA16A",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1522,12 +1520,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 (High Adjusted) in split16d format.  */
2c2fa1
   HOWTO (R_PPC_VLE_HA16D,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_HA16D",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1535,14 +1533,16 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 0x1f07ff,		/* dst_mask */
2c2fa1
 	 FALSE),		/* pcrel_offset */
2c2fa1
 
2c2fa1
-  /* This reloc does nothing.  */
2c2fa1
-  HOWTO (R_PPC_VLE_SDA21,		/* type */
2c2fa1
+  /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
2c2fa1
+     instructions.  If the register base is 0 then the linker changes
2c2fa1
+     the e_add16i to an e_li instruction.  */
2c2fa1
+  HOWTO (R_PPC_VLE_SDA21,	/* type */
2c2fa1
 	 0,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_VLE_SDA21",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1550,29 +1550,29 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 0xffff,		/* dst_mask */
2c2fa1
 	 FALSE),		/* pcrel_offset */
2c2fa1
 
2c2fa1
-  /* This reloc does nothing.  */
2c2fa1
+  /* Like R_PPC_VLE_SDA21 but ignore overflow.  */
2c2fa1
   HOWTO (R_PPC_VLE_SDA21_LO,	/* type */
2c2fa1
 	 0,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_VLE_SDA21_LO",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
 	 0,			/* src_mask */
2c2fa1
-	 0,			/* dst_mask */
2c2fa1
+	 0xffff,		/* dst_mask */
2c2fa1
 	 FALSE),		/* pcrel_offset */
2c2fa1
 
2c2fa1
   /* The 16 LSBS relative to _SDA_BASE_ in split16a format.  */
2c2fa1
   HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */
2c2fa1
 	 0,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield,	/* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont,	/* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_SDAREL_LO16A",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1581,14 +1581,13 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 FALSE),		/* pcrel_offset */
2c2fa1
 
2c2fa1
   /* The 16 LSBS relative to _SDA_BASE_ in split16d format.  */
2c2fa1
-  /* This reloc does nothing.  */
2c2fa1
   HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
2c2fa1
 	 0,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield,	/* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont,	/* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_SDAREL_LO16D",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1598,12 +1597,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 relative to _SDA_BASE_ in split16a format.  */
2c2fa1
   HOWTO (R_PPC_VLE_SDAREL_HI16A,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield,	/* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont,	/* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_SDAREL_HI16A",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1613,12 +1612,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 relative to _SDA_BASE_ in split16d format.  */
2c2fa1
   HOWTO (R_PPC_VLE_SDAREL_HI16D,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield,	/* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont,	/* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_SDAREL_HI16D",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1628,12 +1627,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 (HA) relative to _SDA_BASE split16a format.  */
2c2fa1
   HOWTO (R_PPC_VLE_SDAREL_HA16A,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield,	/* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont,	/* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_SDAREL_HA16A",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1643,12 +1642,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 
2c2fa1
   /* Bits 16-31 (HA) relative to _SDA_BASE split16d format.  */
2c2fa1
   HOWTO (R_PPC_VLE_SDAREL_HA16D,	/* type */
2c2fa1
-	 0,			/* rightshift */
2c2fa1
+	 16,			/* rightshift */
2c2fa1
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
2c2fa1
-	 32,			/* bitsize */
2c2fa1
+	 16,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield,	/* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont,	/* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_VLE_SDAREL_HA16D",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1662,7 +1661,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 32,			/* bitsize */
2c2fa1
 	 FALSE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_dont, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	 /* special_function */
2c2fa1
 	 "R_PPC_IRELATIVE",	/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -1677,7 +1676,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
2c2fa1
 	 16,			/* bitsize */
2c2fa1
 	 TRUE,			/* pc_relative */
2c2fa1
 	 0,			/* bitpos */
2c2fa1
-	 complain_overflow_bitfield, /* complain_on_overflow */
2c2fa1
+	 complain_overflow_signed, /* complain_on_overflow */
2c2fa1
 	 bfd_elf_generic_reloc,	/* special_function */
2c2fa1
 	 "R_PPC_REL16",		/* name */
2c2fa1
 	 FALSE,			/* partial_inplace */
2c2fa1
@@ -4790,20 +4789,19 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
2c2fa1
 }
2c2fa1
 
2c2fa1
 static void
2c2fa1
-ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents,
2c2fa1
-                 bfd_vma offset, bfd_vma relocation,
2c2fa1
-		 split16_format_type split16_format)
2c2fa1
+ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc,
2c2fa1
+		     bfd_vma value,
2c2fa1
+		     split16_format_type split16_format)
2c2fa1
 
2c2fa1
 {
2c2fa1
-  bfd_vma insn, top5, bottom11;
2c2fa1
+  unsigned int insn, top5;
2c2fa1
 
2c2fa1
-  insn = bfd_get_32 (output_bfd, contents + offset);
2c2fa1
-  top5 = relocation >> 11;
2c2fa1
-  top5 = top5 << (split16_format == split16a_type ? 20 : 16);
2c2fa1
-  bottom11 = relocation & 0x7ff;
2c2fa1
+  insn = bfd_get_32 (output_bfd, loc);
2c2fa1
+  top5 = value & 0xf800;
2c2fa1
+  top5 = top5 << (split16_format == split16a_type ? 9 : 5);
2c2fa1
   insn |= top5;
2c2fa1
-  insn |= bottom11;
2c2fa1
-  bfd_put_32 (output_bfd, insn, contents + offset);
2c2fa1
+  insn |= value & 0x7ff;
2c2fa1
+  bfd_put_32 (output_bfd, insn, loc);
2c2fa1
 }
2c2fa1
 
2c2fa1
 
2c2fa1
@@ -7570,6 +7568,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
2c2fa1
       bfd_boolean warned;
2c2fa1
       unsigned int tls_type, tls_mask, tls_gd;
2c2fa1
       struct plt_entry **ifunc;
2c2fa1
+      struct reloc_howto_struct alt_howto;
2c2fa1
 
2c2fa1
       r_type = ELF32_R_TYPE (rel->r_info);
2c2fa1
       sym = NULL;
2c2fa1
@@ -8252,9 +8251,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
2c2fa1
 		 howto->name,
2c2fa1
 		 sym_name);
2c2fa1
 	  }
2c2fa1
-	break;
2c2fa1
+	  break;
2c2fa1
 
2c2fa1
-	/* Relocations that need no special processing.  */
2c2fa1
+	  /* Relocations that need no special processing.  */
2c2fa1
 	case R_PPC_LOCAL24PC:
2c2fa1
 	  /* It makes no sense to point a local relocation
2c2fa1
 	     at a symbol not in this object.  */
2c2fa1
@@ -8743,45 +8742,39 @@ ppc_elf_relocate_section (bfd *output_bfd,
2c2fa1
 	  break;
2c2fa1
 
2c2fa1
 	case R_PPC_VLE_LO16A:
2c2fa1
-	  relocation = (relocation + addend) & 0xffff;
2c2fa1
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                               relocation, split16a_type);
2c2fa1
+	  relocation = relocation + addend;
2c2fa1
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+			       relocation, split16a_type);
2c2fa1
 	  continue;
2c2fa1
 
2c2fa1
 	case R_PPC_VLE_LO16D:
2c2fa1
-	  relocation = (relocation + addend) & 0xffff;
2c2fa1
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                               relocation, split16d_type);
2c2fa1
+	  relocation = relocation + addend;
2c2fa1
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+			       relocation, split16d_type);
2c2fa1
 	  continue;
2c2fa1
 
2c2fa1
 	case R_PPC_VLE_HI16A:
2c2fa1
-	  relocation = ((relocation + addend) >> 16) & 0xffff;
2c2fa1
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                               relocation, split16a_type);
2c2fa1
+	  relocation = (relocation + addend) >> 16;
2c2fa1
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+			       relocation, split16a_type);
2c2fa1
 	  continue;
2c2fa1
 
2c2fa1
 	case R_PPC_VLE_HI16D:
2c2fa1
-	  relocation = ((relocation + addend) >> 16) & 0xffff;
2c2fa1
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                               relocation, split16d_type);
2c2fa1
+	  relocation = (relocation + addend) >> 16;
2c2fa1
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+			       relocation, split16d_type);
2c2fa1
 	  continue;
2c2fa1
 
2c2fa1
 	case R_PPC_VLE_HA16A:
2c2fa1
-	  {
2c2fa1
-	    bfd_vma value = relocation + addend;
2c2fa1
-	    value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
2c2fa1
-	    ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                 value, split16a_type);
2c2fa1
-	  }
2c2fa1
+	  relocation = (relocation + addend + 0x8000) >> 16;
2c2fa1
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+			       relocation, split16a_type);
2c2fa1
 	  continue;
2c2fa1
 
2c2fa1
 	case R_PPC_VLE_HA16D:
2c2fa1
-	  {
2c2fa1
-	    bfd_vma value = relocation + addend;
2c2fa1
-	    value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
2c2fa1
-	    ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                 value, split16d_type);
2c2fa1
-	  }
2c2fa1
+	  relocation = (relocation + addend + 0x8000) >> 16;
2c2fa1
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+			       relocation, split16d_type);
2c2fa1
 	  continue;
2c2fa1
 
2c2fa1
 	  /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0.  */
2c2fa1
@@ -8792,6 +8785,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
2c2fa1
 	  {
2c2fa1
 	    const char *name;
2c2fa1
 	    int reg;
2c2fa1
+	    unsigned int insn;
2c2fa1
 	    struct elf_link_hash_entry *sda = NULL;
2c2fa1
 
2c2fa1
 	    if (sec == NULL || sec->output_section == NULL)
2c2fa1
@@ -8845,32 +8839,40 @@ ppc_elf_relocate_section (bfd *output_bfd,
2c2fa1
 		addend -= SYM_VAL (sda);
2c2fa1
 	      }
2c2fa1
 
2c2fa1
+	    insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
2c2fa1
 	    if (reg == 0
2c2fa1
 		&& (r_type == R_PPC_VLE_SDA21
2c2fa1
 		    || r_type == R_PPC_VLE_SDA21_LO))
2c2fa1
 	      {
2c2fa1
-		/* Use the split20 format.  */
2c2fa1
-		bfd_vma insn, bits12to15, bits21to31;
2c2fa1
-		bfd_vma value  = (relocation + rel->r_offset) & 0xffff;
2c2fa1
-		/* Propagate sign bit, if necessary.  */
2c2fa1
-		insn = (value & 0x8000) ? 0x70107800 : 0x70000000;
2c2fa1
-		bits12to15 = value & 0x700;
2c2fa1
-		bits21to31 = value & 0x7ff;
2c2fa1
-		insn |= bits12to15;
2c2fa1
-		insn |= bits21to31;
2c2fa1
-  		bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
2c2fa1
-		continue;
2c2fa1
+		relocation = relocation + addend;
2c2fa1
+		addend = 0;
2c2fa1
+
2c2fa1
+		/* Force e_li insn, keeping RT from original insn.  */
2c2fa1
+		insn &= 0x1f << 21;
2c2fa1
+		insn |= 28u << 26;
2c2fa1
+
2c2fa1
+		/* We have an li20 field, bits 17..20, 11..15, 21..31.  */
2c2fa1
+		/* Top 4 bits of value to 17..20.  */
2c2fa1
+		insn |= (relocation & 0xf0000) >> 5;
2c2fa1
+		/* Next 5 bits of the value to 11..15.  */
2c2fa1
+		insn |= (relocation & 0xf800) << 5;
2c2fa1
+		/* And the final 11 bits of the value to bits 21 to 31.  */
2c2fa1
+		insn |= relocation & 0x7ff;
2c2fa1
+
2c2fa1
+		/* Use _bfd_final_link_relocate to report overflow,
2c2fa1
+		   but do so with a value that won't modify the insn.  */
2c2fa1
+		if (relocation + 0x80000 > 0x100000)
2c2fa1
+		  addend = 0x100000;
2c2fa1
+		relocation = 0;
2c2fa1
 	      }
2c2fa1
 	    else if (r_type == R_PPC_EMB_SDA21
2c2fa1
 		     || r_type == R_PPC_VLE_SDA21
2c2fa1
 		     || r_type == R_PPC_VLE_SDA21_LO)
2c2fa1
 	      {
2c2fa1
-		bfd_vma insn;  /* Fill in register field.  */
2c2fa1
-
2c2fa1
-		insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
2c2fa1
+		/* Fill in register field.  */
2c2fa1
 		insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
2c2fa1
-		bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
2c2fa1
 	      }
2c2fa1
+	    bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
2c2fa1
 	  }
2c2fa1
 	  break;
2c2fa1
 
2c2fa1
@@ -8931,46 +8933,39 @@ ppc_elf_relocate_section (bfd *output_bfd,
2c2fa1
 		  }
2c2fa1
 	      }
2c2fa1
 
2c2fa1
-	   value = sda->root.u.def.section->output_section->vma
2c2fa1
-   		   + sda->root.u.def.section->output_offset;
2c2fa1
-
2c2fa1
-	   if (r_type == R_PPC_VLE_SDAREL_LO16A)
2c2fa1
-	      {
2c2fa1
-		value = (value + addend) & 0xffff;
2c2fa1
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                     value, split16a_type);
2c2fa1
-	      }
2c2fa1
-	   else if (r_type == R_PPC_VLE_SDAREL_LO16D)
2c2fa1
-	      {
2c2fa1
-		value = (value + addend) & 0xffff;
2c2fa1
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                     value, split16d_type);
2c2fa1
-	      }
2c2fa1
-	   else if (r_type == R_PPC_VLE_SDAREL_HI16A)
2c2fa1
+	    value = (sda->root.u.def.section->output_section->vma
2c2fa1
+		     + sda->root.u.def.section->output_offset
2c2fa1
+		     + addend);
2c2fa1
+
2c2fa1
+	    if (r_type == R_PPC_VLE_SDAREL_LO16A)
2c2fa1
+	      ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+				   value, split16a_type);
2c2fa1
+	    else if (r_type == R_PPC_VLE_SDAREL_LO16D)
2c2fa1
+	      ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+				   value, split16d_type);
2c2fa1
+	    else if (r_type == R_PPC_VLE_SDAREL_HI16A)
2c2fa1
 	      {
2c2fa1
-		value = ((value + addend) >> 16) & 0xffff;
2c2fa1
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                     value, split16a_type);
2c2fa1
+		value = value >> 16;
2c2fa1
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+				     value, split16a_type);
2c2fa1
 	      }
2c2fa1
-	   else if (r_type == R_PPC_VLE_SDAREL_HI16D)
2c2fa1
+	    else if (r_type == R_PPC_VLE_SDAREL_HI16D)
2c2fa1
 	      {
2c2fa1
-		value = ((value + addend) >> 16) & 0xffff;
2c2fa1
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                     value, split16d_type);
2c2fa1
+		value = value >> 16;
2c2fa1
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+				     value, split16d_type);
2c2fa1
 	      }
2c2fa1
-	   else if (r_type == R_PPC_VLE_SDAREL_HA16A)
2c2fa1
+	    else if (r_type == R_PPC_VLE_SDAREL_HA16A)
2c2fa1
 	      {
2c2fa1
-		value += addend;
2c2fa1
-		value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
2c2fa1
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                     value, split16a_type);
2c2fa1
+		value = (value + 0x8000) >> 16;
2c2fa1
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+				     value, split16a_type);
2c2fa1
 	      }
2c2fa1
-	   else if (r_type == R_PPC_VLE_SDAREL_HA16D)
2c2fa1
+	    else if (r_type == R_PPC_VLE_SDAREL_HA16D)
2c2fa1
 	      {
2c2fa1
-		value += addend;
2c2fa1
-		value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
2c2fa1
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
2c2fa1
-                                     value, split16d_type);
2c2fa1
+		value = (value + 0x8000) >> 16;
2c2fa1
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
2c2fa1
+				     value, split16d_type);
2c2fa1
 	      }
2c2fa1
 	  }
2c2fa1
 	  continue;
2c2fa1
@@ -9130,13 +9125,36 @@ ppc_elf_relocate_section (bfd *output_bfd,
2c2fa1
 	  ret = FALSE;
2c2fa1
 	}
2c2fa1
 
2c2fa1
-      r = _bfd_final_link_relocate (howto,
2c2fa1
-				    input_bfd,
2c2fa1
-				    input_section,
2c2fa1
-				    contents,
2c2fa1
-				    rel->r_offset,
2c2fa1
-				    relocation,
2c2fa1
-				    addend);
2c2fa1
+      /* 16-bit fields in insns mostly have signed values, but a
2c2fa1
+	 few insns have 16-bit unsigned values.  Really, we should
2c2fa1
+	 have different reloc types.  */
2c2fa1
+      if (howto->complain_on_overflow != complain_overflow_dont
2c2fa1
+	  && howto->dst_mask == 0xffff
2c2fa1
+	  && (input_section->flags & SEC_CODE) != 0)
2c2fa1
+	{
2c2fa1
+	  enum complain_overflow complain = complain_overflow_signed;
2c2fa1
+
2c2fa1
+	  if ((elf_section_flags (input_section) & SHF_PPC_VLE) == 0)
2c2fa1
+	    {
2c2fa1
+	      unsigned int insn;
2c2fa1
+
2c2fa1
+	      insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
2c2fa1
+	      if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
2c2fa1
+		  || (insn & (0x3f << 26)) == 24u << 26 /* ori */
2c2fa1
+		  || (insn & (0x3f << 26)) == 26u << 26 /* xori */
2c2fa1
+		  || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
2c2fa1
+		complain = complain_overflow_unsigned;
2c2fa1
+	    }
2c2fa1
+	  if (howto->complain_on_overflow != complain)
2c2fa1
+	    {
2c2fa1
+	      alt_howto = *howto;
2c2fa1
+	      alt_howto.complain_on_overflow = complain;
2c2fa1
+	      howto = &alt_howto;
2c2fa1
+	    }
2c2fa1
+	}
2c2fa1
+
2c2fa1
+      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
2c2fa1
+				    rel->r_offset, relocation, addend);
2c2fa1
 
2c2fa1
       if (r != bfd_reloc_ok)
2c2fa1
 	{