32-bit PowerPC sdata linker problem

Alan Modra amodra@gmail.com
Sat Jun 7 12:34:00 GMT 2014


On Fri, Jun 06, 2014 at 04:15:23PM +0200, Sebastian Huber wrote:
> On 2014-06-06 15:49, Alan Modra wrote:
> >On Fri, Jun 06, 2014 at 03:23:52PM +0200, Sebastian Huber wrote:
> >>>On 2014-06-06 15:05, Alan Modra wrote:
> >>>> >On Fri, Jun 06, 2014 at 02:48:55PM +0200, Sebastian Huber wrote:
> >>>>> >>	cmplwi	cr0, \_REG, ppc_exc_lock_std@sdarel
> >>>>> >>
> >>>>> >>	.endm
> >>>>> >>
> >>>>> >>I guess, I have to rewrite this a bit.
> >>>> >
> >>>> >Doesn't using a cmpwi rather than cmplwi work?
> >>>> >
> >>>
> >>>No, the cmplwi uses 0x0000 || UIMM with the cmpwi we have
> >>>EXTS(SIMM), but the upper 16-bit must be zero so that the comparison
> >>>works in the macro.
> >Oh, of course.  Perhaps I should make cmpli accept both signed and
> >unsigned 16-bit fields.
> 
> I think our usage of this cmplwi with the implicit truncation from
> the linker is quite a hack.  On the other hand it worked for several
> years.

Applied.

bfd/
	* elf32-ppc.c (ppc_elf_relocate_section): Treat field of cmpli
	insn as a bitfield; Use complain_overflow_bitfield.
	* elf64-ppc.c (ppc64_elf_relocate_section): Likewise.
opcodes/
	* ppc-opc.c (UISIGNOPT): Define and use with cmpli.
gas/
	* config/tc-ppc.c (ppc_insert_operand): Handle PPC_OPERAND_SIGNOPT
	on unsigned fields.  Comment on PPC_OPERAND_SIGNOPT signed fields
	in 64-bit mode.
gold/
	* powerpc.cc (relocate): Treat field of cmpli insn as a bitfield.

-- 
Alan Modra
Australia Development Lab, IBM

diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 1bea6f8..344845d 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -9147,10 +9147,11 @@ ppc_elf_relocate_section (bfd *output_bfd,
 	      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 */)
+	      if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+		complain = complain_overflow_bitfield;
+	      else if ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+		       || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+		       || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
 		complain = complain_overflow_unsigned;
 	    }
 	  if (howto->complain_on_overflow != complain)
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index e7e2e39..b8d7465 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -14648,14 +14648,15 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 	  enum complain_overflow complain = complain_overflow_signed;
 
 	  insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3));
-	  if (howto->rightshift == 0
-	      ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
-		 || (insn & (0x3f << 26)) == 24u << 26 /* ori */
-		 || (insn & (0x3f << 26)) == 26u << 26 /* xori */
-		 || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
-	      : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
-		 || (insn & (0x3f << 26)) == 25u << 26 /* oris */
-		 || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+	  if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+	    complain = complain_overflow_bitfield;
+	  else if (howto->rightshift == 0
+		   ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+		      || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+		      || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
+		   : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
+		      || (insn & (0x3f << 26)) == 25u << 26 /* oris */
+		      || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
 	    complain = complain_overflow_unsigned;
 	  if (howto->complain_on_overflow != complain)
 	    {
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 2c8ce6a..ff4ea64 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -1781,10 +1781,23 @@ ppc_insert_operand (unsigned long insn,
   right = max & -max;
   min = 0;
 
-  if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+  if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0)
+    {
+      /* Extend the allowed range for addis to [-65536, 65535].
+	 Similarly for some VLE high part insns.  For 64-bit it
+	 would be good to disable this for signed fields since the
+	 value is sign extended into the high 32 bits of the register.
+	 If the value is, say, an address, then we might care about
+	 the high bits.  However, gcc as of 2014-06 uses unsigned
+	 values when loading the high part of 64-bit constants using
+	 lis.
+	 Use the same extended range for cmpli, to allow at least
+	 [-32768, 65535].  */
+      min = ~max & -right;
+    }
+  else if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
     {
-      if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
-	max = (max >> 1) & -right;
+      max = (max >> 1) & -right;
       min = ~max & -right;
     }
 
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index bd3994a..96432ed 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -7409,14 +7409,15 @@ Target_powerpc<size, big_endian>::Relocate::relocate(
       Insn insn = elfcpp::Swap<32, big_endian>::readval(iview);
 
       overflow = Reloc::CHECK_SIGNED;
-      if (overflow == Reloc::CHECK_LOW_INSN
-	  ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
-	     || (insn & (0x3f << 26)) == 24u << 26 /* ori */
-	     || (insn & (0x3f << 26)) == 26u << 26 /* xori */
-	     || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
-	  : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
-	     || (insn & (0x3f << 26)) == 25u << 26 /* oris */
-	     || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
+      if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */)
+	overflow = Reloc::CHECK_BITFIELD;
+      else if (overflow == Reloc::CHECK_LOW_INSN
+	       ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */
+		  || (insn & (0x3f << 26)) == 24u << 26 /* ori */
+		  || (insn & (0x3f << 26)) == 26u << 26 /* xori */)
+	       : ((insn & (0x3f << 26)) == 29u << 26 /* andis */
+		  || (insn & (0x3f << 26)) == 25u << 26 /* oris */
+		  || (insn & (0x3f << 26)) == 27u << 26 /* xoris */))
 	overflow = Reloc::CHECK_UNSIGNED;
     }
 
diff --git a/opcodes/ppc-opc.c b/opcodes/ppc-opc.c
index 1d27961..a5cfe1a 100644
--- a/opcodes/ppc-opc.c
+++ b/opcodes/ppc-opc.c
@@ -654,8 +654,11 @@ const struct powerpc_operand powerpc_operands[] =
 #define UI TO + 1
   { 0xffff, 0, NULL, NULL, 0 },
 
+#define UISIGNOPT UI + 1
+  { 0xffff, 0, NULL, NULL, PPC_OPERAND_SIGNOPT },
+
   /* The IMM field in an SE_IM5 instruction.  */
-#define UI5 UI + 1
+#define UI5 UISIGNOPT + 1
   { 0x1f, 4, NULL, NULL, 0 },
 
   /* The OIMM field in an SE_OIM5 instruction.  */
@@ -3500,10 +3503,10 @@ const struct powerpc_opcode powerpc_opcodes[] = {
 
 {"dozi",	OP(9),		OP_MASK,     M601,	PPCNONE,	{RT, RA, SI}},
 
-{"cmplwi",	OPL(10,0),	OPL_MASK,    PPCCOM,	PPCNONE,	{OBF, RA, UI}},
-{"cmpldi",	OPL(10,1),	OPL_MASK,    PPC64,	PPCNONE,	{OBF, RA, UI}},
-{"cmpli",	OP(10),		OP_MASK,     PPC,	PPCNONE,	{BF, L, RA, UI}},
-{"cmpli",	OP(10),		OP_MASK,     PWRCOM,	PPC,		{BF, RA, UI}},
+{"cmplwi",	OPL(10,0),	OPL_MASK,    PPCCOM,	PPCNONE,	{OBF, RA, UISIGNOPT}},
+{"cmpldi",	OPL(10,1),	OPL_MASK,    PPC64,	PPCNONE,	{OBF, RA, UISIGNOPT}},
+{"cmpli",	OP(10),		OP_MASK,     PPC,	PPCNONE,	{BF, L, RA, UISIGNOPT}},
+{"cmpli",	OP(10),		OP_MASK,     PWRCOM,	PPC,		{BF, RA, UISIGNOPT}},
 
 {"cmpwi",	OPL(11,0),	OPL_MASK,    PPCCOM,	PPCNONE,	{OBF, RA, SI}},
 {"cmpdi",	OPL(11,1),	OPL_MASK,    PPC64,	PPCNONE,	{OBF, RA, SI}},



More information about the Binutils mailing list