public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* Better overflow checking for powerpc32 relocations
@ 2014-03-08  6:04 Alan Modra
  2014-03-08 14:31 ` Joseph S. Myers
  2014-03-14  4:30 ` Fix overflow handling of VLE_SDA21 Alan Modra
  0 siblings, 2 replies; 3+ messages in thread
From: Alan Modra @ 2014-03-08  6:04 UTC (permalink / raw)
  To: binutils

Similar to the powerpc64 patch, this improves overflow checking in
elf32-ppc.c.  Many reloc "howto" entries needed fixes, some just
cosmetic.

The patch also fixes the R_PPC_VLE_SDA21 reloc application code, which
was horribly broken.  In fact, it may still be broken since Power ISA
2.07 says e_li behaves as
   RT <- EXTS(li20 1:4 || li20 5:8 || li20 0 || li20 9:19)
where li20 is a field taken from bits 17..20, 11..15, 21..31 of the
instruction.  Freescale VLEPEM says differently, and I assume
correctly, that
   RT <- EXTS(li20 0:3 || li20 4:8 || li20 9:19)
The VLE_SDA21 relocation description matches this too.

Now the VLE_SDA21 relocation specifies in the case where e_addi16 is
converted to e_li for symbols in .PPC.EMB.sdata0 or .PPC.EMB.sbss0
(no base register), that the field is restricted to 16 bits, with the
sign bit being propagated to the top 4 bits.  I don't see the sense in
restricting the value like this, so have allowed the full 20 bit
signed value.  This of course is compatible with the reloc description
in that values in the 16 bit signed range will result in exactly the
same insn field as when the reloc description is followed to the
letter.

	* elf32-ppc.c (ppc_elf_howto_raw): Correct overflow check for
	many relocations.  Correct bitsize and rightshift too for a number
	of VLE relocs.  Describe R_PPC_VLE_SDA21 and R_PPC_VLE_SDA21_LO.
	Correct dst_mask on R_PPC_VLE_SDA21_LO.
	(ppc_elf_vle_split16): Tidy, delete unnecessary prototype.
	(ppc_elf_relocate_section): Modify overflow test for 16-bit
	fields in instructions to signed/unsigned according to whether
	the field takes a signed or unsigned value.  Tidy vle split16 code.
	Correct R_PPC_VLE_SDA21 and R_PPC_VLE_SDA21_LO handling.

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 5bfa33b..750aa5e 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -50,8 +50,6 @@ static bfd_reloc_status_type ppc_elf_addr16_ha_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 static bfd_reloc_status_type ppc_elf_unhandled_reloc
   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
-static void ppc_elf_vle_split16
-  (bfd *, bfd_byte *, bfd_vma, bfd_vma, split16_format_type);
 
 /* Branch prediction bit for branch taken relocs.  */
 #define BRANCH_PREDICT_BIT 0x200000
@@ -192,7 +190,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_NONE",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -207,7 +205,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_ADDR32",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -223,7 +221,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 26,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_ADDR24",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -300,7 +298,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_ADDR14",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -317,7 +315,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_ADDR14_BRTAKEN",/* name */
 	 FALSE,			/* partial_inplace */
@@ -334,7 +332,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_ADDR14_BRNTAKEN",/* name */
 	 FALSE,			/* partial_inplace */
@@ -446,7 +444,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_GOT16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -462,7 +460,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 ppc_elf_addr16_ha_reloc, /* special_function */
 	 "R_PPC_GOT16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -497,7 +495,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_COPY",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -513,7 +511,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_GLOB_DAT",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -528,7 +526,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_JMP_SLOT",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -545,7 +543,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_RELATIVE",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -577,7 +575,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_UADDR32",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -607,7 +605,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_REL32",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -623,7 +621,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_PLT32",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -639,7 +637,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_PLTREL32",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -671,7 +669,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_PLT16_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -687,7 +685,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 ppc_elf_addr16_ha_reloc, /* special_function */
 	 "R_PPC_PLT16_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -718,7 +716,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_SECTOFF",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -748,7 +746,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_SECTOFF_HI",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -763,7 +761,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 ppc_elf_addr16_ha_reloc, /* special_function */
 	 "R_PPC_SECTOFF_HA",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1239,7 +1237,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_EMB_NADDR32",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1254,7 +1252,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_EMB_NADDR16",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1449,10 +1447,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   HOWTO (R_PPC_VLE_LO16A,	/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_LO16A",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1464,10 +1462,10 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
   HOWTO (R_PPC_VLE_LO16D,	/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_LO16D",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -1477,12 +1475,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 split16a format.  */
   HOWTO (R_PPC_VLE_HI16A,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_HI16A",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -1492,12 +1490,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 split16d format.  */
   HOWTO (R_PPC_VLE_HI16D,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_HI16D",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -1507,12 +1505,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (High Adjusted) in split16a format.  */
   HOWTO (R_PPC_VLE_HA16A,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_HA16A",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -1522,12 +1520,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (High Adjusted) in split16d format.  */
   HOWTO (R_PPC_VLE_HA16D,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_HA16D",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -1535,14 +1533,16 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 0x1f07ff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* This reloc does nothing.  */
-  HOWTO (R_PPC_VLE_SDA21,		/* type */
+  /* This reloc is like R_PPC_EMB_SDA21 but only applies to e_add16i
+     instructions.  If the register base is 0 then the linker changes
+     the e_add16i to an e_li instruction.  */
+  HOWTO (R_PPC_VLE_SDA21,	/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_VLE_SDA21",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -1550,29 +1550,29 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* This reloc does nothing.  */
+  /* Like R_PPC_VLE_SDA21 but ignore overflow.  */
   HOWTO (R_PPC_VLE_SDA21_LO,	/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_VLE_SDA21_LO",	/* name */
 	 FALSE,			/* partial_inplace */
 	 0,			/* src_mask */
-	 0,			/* dst_mask */
+	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   /* The 16 LSBS relative to _SDA_BASE_ in split16a format.  */
   HOWTO (R_PPC_VLE_SDAREL_LO16A,/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_SDAREL_LO16A",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1581,14 +1581,13 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 FALSE),		/* pcrel_offset */
 
   /* The 16 LSBS relative to _SDA_BASE_ in split16d format.  */
-  /* This reloc does nothing.  */
   HOWTO (R_PPC_VLE_SDAREL_LO16D, /* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_SDAREL_LO16D",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -1598,12 +1597,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16a format.  */
   HOWTO (R_PPC_VLE_SDAREL_HI16A,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_SDAREL_HI16A",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1613,12 +1612,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 relative to _SDA_BASE_ in split16d format.  */
   HOWTO (R_PPC_VLE_SDAREL_HI16D,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_SDAREL_HI16D",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1628,12 +1627,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16a format.  */
   HOWTO (R_PPC_VLE_SDAREL_HA16A,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_SDAREL_HA16A",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1643,12 +1642,12 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 
   /* Bits 16-31 (HA) relative to _SDA_BASE split16d format.  */
   HOWTO (R_PPC_VLE_SDAREL_HA16D,	/* type */
-	 0,			/* rightshift */
+	 16,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield,	/* complain_on_overflow */
+	 complain_overflow_dont,	/* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_VLE_SDAREL_HA16D",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1662,7 +1661,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	 /* special_function */
 	 "R_PPC_IRELATIVE",	/* name */
 	 FALSE,			/* partial_inplace */
@@ -1677,7 +1676,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
 	 16,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 bfd_elf_generic_reloc,	/* special_function */
 	 "R_PPC_REL16",		/* name */
 	 FALSE,			/* partial_inplace */
@@ -4790,20 +4789,19 @@ ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 }
 
 static void
-ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents,
-                 bfd_vma offset, bfd_vma relocation,
-		 split16_format_type split16_format)
+ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *loc,
+		     bfd_vma value,
+		     split16_format_type split16_format)
 
 {
-  bfd_vma insn, top5, bottom11;
+  unsigned int insn, top5;
 
-  insn = bfd_get_32 (output_bfd, contents + offset);
-  top5 = relocation >> 11;
-  top5 = top5 << (split16_format == split16a_type ? 20 : 16);
-  bottom11 = relocation & 0x7ff;
+  insn = bfd_get_32 (output_bfd, loc);
+  top5 = value & 0xf800;
+  top5 = top5 << (split16_format == split16a_type ? 9 : 5);
   insn |= top5;
-  insn |= bottom11;
-  bfd_put_32 (output_bfd, insn, contents + offset);
+  insn |= value & 0x7ff;
+  bfd_put_32 (output_bfd, insn, loc);
 }
 
 \f
@@ -7570,6 +7568,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
       bfd_boolean warned;
       unsigned int tls_type, tls_mask, tls_gd;
       struct plt_entry **ifunc;
+      struct reloc_howto_struct alt_howto;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       sym = NULL;
@@ -8252,9 +8251,9 @@ ppc_elf_relocate_section (bfd *output_bfd,
 		 howto->name,
 		 sym_name);
 	  }
-	break;
+	  break;
 
-	/* Relocations that need no special processing.  */
+	  /* Relocations that need no special processing.  */
 	case R_PPC_LOCAL24PC:
 	  /* It makes no sense to point a local relocation
 	     at a symbol not in this object.  */
@@ -8743,45 +8742,39 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	  break;
 
 	case R_PPC_VLE_LO16A:
-	  relocation = (relocation + addend) & 0xffff;
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16a_type);
+	  relocation = relocation + addend;
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+			       relocation, split16a_type);
 	  continue;
 
 	case R_PPC_VLE_LO16D:
-	  relocation = (relocation + addend) & 0xffff;
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16d_type);
+	  relocation = relocation + addend;
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+			       relocation, split16d_type);
 	  continue;
 
 	case R_PPC_VLE_HI16A:
-	  relocation = ((relocation + addend) >> 16) & 0xffff;
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16a_type);
+	  relocation = (relocation + addend) >> 16;
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+			       relocation, split16a_type);
 	  continue;
 
 	case R_PPC_VLE_HI16D:
-	  relocation = ((relocation + addend) >> 16) & 0xffff;
-	  ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                               relocation, split16d_type);
+	  relocation = (relocation + addend) >> 16;
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+			       relocation, split16d_type);
 	  continue;
 
 	case R_PPC_VLE_HA16A:
-	  {
-	    bfd_vma value = relocation + addend;
-	    value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-	    ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                 value, split16a_type);
-	  }
+	  relocation = (relocation + addend + 0x8000) >> 16;
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+			       relocation, split16a_type);
 	  continue;
 
 	case R_PPC_VLE_HA16D:
-	  {
-	    bfd_vma value = relocation + addend;
-	    value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-	    ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                 value, split16d_type);
-	  }
+	  relocation = (relocation + addend + 0x8000) >> 16;
+	  ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+			       relocation, split16d_type);
 	  continue;
 
 	  /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0.  */
@@ -8792,6 +8785,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	  {
 	    const char *name;
 	    int reg;
+	    unsigned int insn;
 	    struct elf_link_hash_entry *sda = NULL;
 
 	    if (sec == NULL || sec->output_section == NULL)
@@ -8845,32 +8839,40 @@ ppc_elf_relocate_section (bfd *output_bfd,
 		addend -= SYM_VAL (sda);
 	      }
 
+	    insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
 	    if (reg == 0
 		&& (r_type == R_PPC_VLE_SDA21
 		    || r_type == R_PPC_VLE_SDA21_LO))
 	      {
-		/* Use the split20 format.  */
-		bfd_vma insn, bits12to15, bits21to31;
-		bfd_vma value  = (relocation + rel->r_offset) & 0xffff;
-		/* Propagate sign bit, if necessary.  */
-		insn = (value & 0x8000) ? 0x70107800 : 0x70000000;
-		bits12to15 = value & 0x700;
-		bits21to31 = value & 0x7ff;
-		insn |= bits12to15;
-		insn |= bits21to31;
-  		bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
-		continue;
+		relocation = relocation + addend;
+		addend = 0;
+
+		/* Force e_li insn, keeping RT from original insn.  */
+		insn &= 0x1f << 21;
+		insn |= 28u << 26;
+
+		/* We have an li20 field, bits 17..20, 11..15, 21..31.  */
+		/* Top 4 bits of value to 17..20.  */
+		insn |= (relocation & 0xf0000) >> 5;
+		/* Next 5 bits of the value to 11..15.  */
+		insn |= (relocation & 0xf800) << 5;
+		/* And the final 11 bits of the value to bits 21 to 31.  */
+		insn |= relocation & 0x7ff;
+
+		/* Use _bfd_final_link_relocate to report overflow,
+		   but do so with a value that won't modify the insn.  */
+		if (relocation + 0x80000 > 0x100000)
+		  addend = 0x100000;
+		relocation = 0;
 	      }
 	    else if (r_type == R_PPC_EMB_SDA21
 		     || r_type == R_PPC_VLE_SDA21
 		     || r_type == R_PPC_VLE_SDA21_LO)
 	      {
-		bfd_vma insn;  /* Fill in register field.  */
-
-		insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
+		/* Fill in register field.  */
 		insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
-		bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
 	      }
+	    bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
 	  }
 	  break;
 
@@ -8931,46 +8933,39 @@ ppc_elf_relocate_section (bfd *output_bfd,
 		  }
 	      }
 
-	   value = sda->root.u.def.section->output_section->vma
-   		   + sda->root.u.def.section->output_offset;
-
-	   if (r_type == R_PPC_VLE_SDAREL_LO16A)
-	      {
-		value = (value + addend) & 0xffff;
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16a_type);
-	      }
-	   else if (r_type == R_PPC_VLE_SDAREL_LO16D)
-	      {
-		value = (value + addend) & 0xffff;
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16d_type);
-	      }
-	   else if (r_type == R_PPC_VLE_SDAREL_HI16A)
+	    value = (sda->root.u.def.section->output_section->vma
+		     + sda->root.u.def.section->output_offset
+		     + addend);
+
+	    if (r_type == R_PPC_VLE_SDAREL_LO16A)
+	      ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+				   value, split16a_type);
+	    else if (r_type == R_PPC_VLE_SDAREL_LO16D)
+	      ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+				   value, split16d_type);
+	    else if (r_type == R_PPC_VLE_SDAREL_HI16A)
 	      {
-		value = ((value + addend) >> 16) & 0xffff;
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16a_type);
+		value = value >> 16;
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+				     value, split16a_type);
 	      }
-	   else if (r_type == R_PPC_VLE_SDAREL_HI16D)
+	    else if (r_type == R_PPC_VLE_SDAREL_HI16D)
 	      {
-		value = ((value + addend) >> 16) & 0xffff;
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16d_type);
+		value = value >> 16;
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+				     value, split16d_type);
 	      }
-	   else if (r_type == R_PPC_VLE_SDAREL_HA16A)
+	    else if (r_type == R_PPC_VLE_SDAREL_HA16A)
 	      {
-		value += addend;
-		value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16a_type);
+		value = (value + 0x8000) >> 16;
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+				     value, split16a_type);
 	      }
-	   else if (r_type == R_PPC_VLE_SDAREL_HA16D)
+	    else if (r_type == R_PPC_VLE_SDAREL_HA16D)
 	      {
-		value += addend;
-		value = (((value >> 16) + ((value & 0x8000) ? 1 : 0)) & 0xffff);
-	        ppc_elf_vle_split16 (output_bfd, contents, rel->r_offset,
-                                     value, split16d_type);
+		value = (value + 0x8000) >> 16;
+		ppc_elf_vle_split16 (output_bfd, contents + rel->r_offset,
+				     value, split16d_type);
 	      }
 	  }
 	  continue;
@@ -9130,13 +9125,36 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	  ret = FALSE;
 	}
 
-      r = _bfd_final_link_relocate (howto,
-				    input_bfd,
-				    input_section,
-				    contents,
-				    rel->r_offset,
-				    relocation,
-				    addend);
+      /* 16-bit fields in insns mostly have signed values, but a
+	 few insns have 16-bit unsigned values.  Really, we should
+	 have different reloc types.  */
+      if (howto->complain_on_overflow != complain_overflow_dont
+	  && howto->dst_mask == 0xffff
+	  && (input_section->flags & SEC_CODE) != 0)
+	{
+	  enum complain_overflow complain = complain_overflow_signed;
+
+	  if ((elf_section_flags (input_section) & SHF_PPC_VLE) == 0)
+	    {
+	      unsigned int insn;
+
+	      insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
+	      if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+		  || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+		  || (insn & (0x3f << 26)) == 26u << 26 /* xori */
+		  || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+		complain = complain_overflow_unsigned;
+	    }
+	  if (howto->complain_on_overflow != complain)
+	    {
+	      alt_howto = *howto;
+	      alt_howto.complain_on_overflow = complain;
+	      howto = &alt_howto;
+	    }
+	}
+
+      r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+				    rel->r_offset, relocation, addend);
 
       if (r != bfd_reloc_ok)
 	{

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Better overflow checking for powerpc32 relocations
  2014-03-08  6:04 Better overflow checking for powerpc32 relocations Alan Modra
@ 2014-03-08 14:31 ` Joseph S. Myers
  2014-03-14  4:30 ` Fix overflow handling of VLE_SDA21 Alan Modra
  1 sibling, 0 replies; 3+ messages in thread
From: Joseph S. Myers @ 2014-03-08 14:31 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils

Really I think relocation overflow checking should have testcases in the 
ld testsuite (I made sure to include such testcases for the C6X port, 
ld-tic6x/reloc-overflow-*, plus other tests for non-overflowing values).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Fix overflow handling of VLE_SDA21
  2014-03-08  6:04 Better overflow checking for powerpc32 relocations Alan Modra
  2014-03-08 14:31 ` Joseph S. Myers
@ 2014-03-14  4:30 ` Alan Modra
  1 sibling, 0 replies; 3+ messages in thread
From: Alan Modra @ 2014-03-14  4:30 UTC (permalink / raw)
  To: binutils

What was I thinking?  "do so with a value that won't modify the insn"
would require
	relocation = ((insn & 0xffff) ^ 0x8000) - 0x8000;
We may as well do this the obvious way.  Also, the overflow test
was wrong when bfd_vma is 64-bit.

bfd/
	* elf32-ppc.c (ppc_elf_relocate_section): Correct overflow
	handling for VLE_SDA21 relocs.
ld/testsuite/
	* ld-powerpc/vle.ld: Place .PPC.EMB.sdata0 within 32k of 0.
	* ld-powerpc/vle-reloc-3.d: Update.

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 750aa5e..868fe50 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -8859,11 +8859,12 @@ ppc_elf_relocate_section (bfd *output_bfd,
 		/* And the final 11 bits of the value to bits 21 to 31.  */
 		insn |= relocation & 0x7ff;
 
-		/* Use _bfd_final_link_relocate to report overflow,
-		   but do so with a value that won't modify the insn.  */
-		if (relocation + 0x80000 > 0x100000)
-		  addend = 0x100000;
-		relocation = 0;
+		bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
+
+		if (r_type == R_PPC_VLE_SDA21
+		    && ((relocation + 0x80000) & 0xffffffff) > 0x100000)
+		  goto overflow;
+		continue;
 	      }
 	    else if (r_type == R_PPC_EMB_SDA21
 		     || r_type == R_PPC_VLE_SDA21
@@ -9160,6 +9161,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	{
 	  if (r == bfd_reloc_overflow)
 	    {
+	    overflow:
 	      if (warned)
 		continue;
 	      if (h != NULL
diff --git a/ld/testsuite/ld-powerpc/vle-reloc-3.d b/ld/testsuite/ld-powerpc/vle-reloc-3.d
index e29f4f0..584c483 100644
--- a/ld/testsuite/ld-powerpc/vle-reloc-3.d
+++ b/ld/testsuite/ld-powerpc/vle-reloc-3.d
@@ -5,4 +5,4 @@ Disassembly of section .text:
 01800094 <sda21_test>:
  1800094:	1c ad 80 08 	e_add16i r5,r13,-32760
  1800098:	1c a2 80 04 	e_add16i r5,r2,-32764
- 180009c:	70 00 00 ac 	e_li    r0,172
+ 180009c:	70 b0 78 04 	e_li    r5,-32764
diff --git a/ld/testsuite/ld-powerpc/vle.ld b/ld/testsuite/ld-powerpc/vle.ld
index 01b6598..ff92a05 100644
--- a/ld/testsuite/ld-powerpc/vle.ld
+++ b/ld/testsuite/ld-powerpc/vle.ld
@@ -2,10 +2,11 @@ SECTIONS
 {
   . = 0x01800000 + SIZEOF_HEADERS;
   .text : { *(.text) }
-  .PPC.EMB.sdata0 : { *(.PPC.EMB.sdata0) }
   .sdata2 : { PROVIDE (_SDA2_BASE_ = 32768); *(.sdata2) }
   . = ALIGN (0x10000) + (. & (0x10000 - 1));
   .data : { *(.data) }
   .sdata : { PROVIDE (_SDA_BASE_ = 32768); *(.sdata) }
+  . = 0xffff8000;
+  .PPC.EMB.sdata0 : { *(.PPC.EMB.sdata0) }
   /DISCARD/ : { *(*) }
 }

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-03-14  4:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-08  6:04 Better overflow checking for powerpc32 relocations Alan Modra
2014-03-08 14:31 ` Joseph S. Myers
2014-03-14  4:30 ` Fix overflow handling of VLE_SDA21 Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).