This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Thumb32 assembler (65/69)


More relocations.  This adds BFD_RELOC_* constants for the new
relocations that the Thumb32 branches need, and implements final-link
support for them.

zw

	* reloc.c: Add BFD_RELOC_THUMB_PCREL_BRANCH7, BFD_RELOC_THUMB_BRANCH20,
	BFD_RELOC_THUMB_BRANCH25.
	* bfd-in2.h, libbfd.h: Regenerate.
	* elf32-arm.h (R_ARM_THM_JMP19, R_ARM_THM_JUMP6 howtos): Correct
	bitsize.
	(elf32_arm_reloc_map): Add entries for new relocs.
	(elf32_arm_final_link_relocate): Add support for R_ARM_THM_JUMP24,
	R_ARM_THM_JUMP19, and R_ARM_THM_JUMP6.

===================================================================
Index: bfd/bfd-in2.h
--- bfd/bfd-in2.h	(revision 75)
+++ bfd/bfd-in2.h	(revision 76)
@@ -2669,11 +2669,17 @@
 field in the instruction.  */
   BFD_RELOC_THUMB_PCREL_BLX,
 
-/* Thumb 23-, 12- and 9-bit pc-relative branches.  The lowest bit must
-be zero and is not stored in the instruction.  */
+/* Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches.
+The lowest bit must be zero and is not stored in the instruction.
+Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an
+"nn" one smaller in all cases.  Note further that BRANCH23
+corresponds to R_ARM_THM_CALL.  */
+  BFD_RELOC_THUMB_PCREL_BRANCH7,
   BFD_RELOC_THUMB_PCREL_BRANCH9,
   BFD_RELOC_THUMB_PCREL_BRANCH12,
+  BFD_RELOC_THUMB_PCREL_BRANCH20,
   BFD_RELOC_THUMB_PCREL_BRANCH23,
+  BFD_RELOC_THUMB_PCREL_BRANCH25,
 
 /* 12-bit immediate offset, used in ARM-format ldr and str instructions.  */
   BFD_RELOC_ARM_OFFSET_IMM,
===================================================================
Index: bfd/reloc.c
--- bfd/reloc.c	(revision 75)
+++ bfd/reloc.c	(revision 76)
@@ -2622,15 +2622,25 @@
   Thumb 22 bit pc-relative branch.  The lowest bit must be zero and is
   not stored in the instruction.  The 2nd lowest bit comes from a 1 bit
   field in the instruction.
+
 ENUM
+  BFD_RELOC_THUMB_PCREL_BRANCH7
+ENUMX
   BFD_RELOC_THUMB_PCREL_BRANCH9
 ENUMX
   BFD_RELOC_THUMB_PCREL_BRANCH12
 ENUMX
+  BFD_RELOC_THUMB_PCREL_BRANCH20
+ENUMX
   BFD_RELOC_THUMB_PCREL_BRANCH23
+ENUMX
+  BFD_RELOC_THUMB_PCREL_BRANCH25
 ENUMDOC
-  Thumb 23-, 12- and 9-bit pc-relative branches.  The lowest bit must
-  be zero and is not stored in the instruction.
+  Thumb 7-, 9-, 12-, 20-, 23-, and 25-bit pc-relative branches.
+  The lowest bit must be zero and is not stored in the instruction.
+  Note that the corresponding ELF R_ARM_THM_JUMPnn constant has an
+  "nn" one smaller in all cases.  Note further that BRANCH23
+  corresponds to R_ARM_THM_CALL.
 
 ENUM
   BFD_RELOC_ARM_OFFSET_IMM
===================================================================
Index: bfd/libbfd.h
--- bfd/libbfd.h	(revision 75)
+++ bfd/libbfd.h	(revision 76)
@@ -1149,9 +1149,12 @@
   "BFD_RELOC_ARM_PCREL_BRANCH",
   "BFD_RELOC_ARM_PCREL_BLX",
   "BFD_RELOC_THUMB_PCREL_BLX",
+  "BFD_RELOC_THUMB_PCREL_BRANCH7",
   "BFD_RELOC_THUMB_PCREL_BRANCH9",
   "BFD_RELOC_THUMB_PCREL_BRANCH12",
+  "BFD_RELOC_THUMB_PCREL_BRANCH20",
   "BFD_RELOC_THUMB_PCREL_BRANCH23",
+  "BFD_RELOC_THUMB_PCREL_BRANCH25",
   "BFD_RELOC_ARM_OFFSET_IMM",
   "BFD_RELOC_ARM_THUMB_OFFSET",
   "BFD_RELOC_ARM_TARGET1",
===================================================================
Index: bfd/elf32-arm.c
--- bfd/elf32-arm.c	(revision 75)
+++ bfd/elf32-arm.c	(revision 76)
@@ -778,7 +778,7 @@
   HOWTO (R_ARM_THM_JUMP19,	/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 20,			/* bitsize */
+	 19,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_signed,/* complain_on_overflow */
@@ -792,7 +792,7 @@
   HOWTO (R_ARM_THM_JUMP6,	/* type */
 	 1,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 7,			/* bitsize */
+	 6,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_unsigned,/* complain_on_overflow */
@@ -1312,9 +1312,12 @@
     {BFD_RELOC_16,                   R_ARM_ABS16},
     {BFD_RELOC_ARM_OFFSET_IMM,       R_ARM_ABS12},
     {BFD_RELOC_ARM_THUMB_OFFSET,     R_ARM_THM_ABS5},
+    {BFD_RELOC_THUMB_PCREL_BRANCH25, R_ARM_THM_JUMP24},
     {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_CALL},
     {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_JUMP11},
+    {BFD_RELOC_THUMB_PCREL_BRANCH20, R_ARM_THM_JUMP19},
     {BFD_RELOC_THUMB_PCREL_BRANCH9,  R_ARM_THM_JUMP8},
+    {BFD_RELOC_THUMB_PCREL_BRANCH7,  R_ARM_THM_JUMP6},
     {BFD_RELOC_ARM_GLOB_DAT,         R_ARM_GLOB_DAT},
     {BFD_RELOC_ARM_JUMP_SLOT,        R_ARM_JUMP_SLOT},
     {BFD_RELOC_ARM_RELATIVE,         R_ARM_RELATIVE},
@@ -3309,8 +3312,154 @@
       }
       break;
 
+    case R_ARM_THM_JUMP24:
+      /* Thumb32 unconditional branch instruction.  */
+      {
+	bfd_vma relocation;
+	bfd_boolean overflow = FALSE;
+	bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+	bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+	bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
+	bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
+	bfd_vma check;
+	bfd_signed_vma signed_check;
+
+	/* Need to refetch the addend, reconstruct the top three bits, and glue the
+	   two pieces together.  */
+	if (globals->use_rel)
+	  {
+	    bfd_vma S     = (upper_insn & 0x0400) >> 10;
+	    bfd_vma upper = (upper_insn & 0x03ff);
+	    bfd_vma I1    = (lower_insn & 0x2000) >> 13;
+	    bfd_vma I2    = (lower_insn & 0x0800) >> 11;
+	    bfd_vma lower = (lower_insn & 0x07ff);
+
+	    upper |= ~(I2 ^ S) << 10;
+	    upper |= ~(I1 ^ S) << 11;
+	    upper |= ~S << 12;
+	    upper -= 0x1000; /* Sign extend.  */
+
+	    addend = (upper << 12) | (lower << 1);
+	    signed_addend = addend;
+	  }
+
+	/* ??? Should handle interworking?  GCC might someday try to
+	   use this for tail calls.  */
+
+      	relocation = value + signed_addend;
+	relocation -= (input_section->output_section->vma
+		       + input_section->output_offset
+		       + rel->r_offset);
+
+	check = relocation >> howto->rightshift;
+
+	/* If this is a signed value, the rightshift just dropped
+	   leading 1 bits (assuming twos complement).  */
+	if ((bfd_signed_vma) relocation >= 0)
+	  signed_check = check;
+	else
+	  signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
+
+	/* Assumes two's complement.  */
+	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
+	  overflow = TRUE;
+
+	/* Put RELOCATION back into the insn.  */
+	{
+	  bfd_vma S  = (relocation & 0x00100000) >> 20;
+	  bfd_vma J2 = (relocation & 0x00080000) >> 19;
+	  bfd_vma J1 = (relocation & 0x00040000) >> 18;
+	  bfd_vma hi = (relocation & 0x0003f000) >> 12;
+	  bfd_vma lo = (relocation & 0x00000ffe) >>  1;
+
+	  upper_insn = (upper_insn & ~(bfd_vma) 0x043f) | (S << 10) | hi;
+	  lower_insn = (lower_insn & ~(bfd_vma) 0x2fff) | (J1 << 13) | (J2 << 11) | lo;
+	}
+
+	/* Put the relocated value back in the object file:  */
+	bfd_put_16 (input_bfd, upper_insn, hit_data);
+	bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+
+	return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
+      }
+
+    case R_ARM_THM_JUMP19:
+      /* Thumb32 conditional branch instruction.  */
+      {
+	bfd_vma relocation;
+	bfd_boolean overflow = FALSE;
+	bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
+	bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
+	bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
+	bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
+	bfd_vma check;
+	bfd_signed_vma signed_check;
+
+	/* Need to refetch the addend, reconstruct the top three bits,
+	   and squish the two 11 bit pieces together.  */
+	if (globals->use_rel)
+	  {
+	    bfd_vma S     = (upper_insn & 0x0400) >> 10;
+	    bfd_vma upper = (upper_insn & 0x001f);
+	    bfd_vma J1    = (lower_insn & 0x2000) >> 13;
+	    bfd_vma J2    = (lower_insn & 0x0800) >> 11;
+	    bfd_vma lower = (lower_insn & 0x07ff);
+
+	    upper |= J2 << 6;
+	    upper |= J1 << 7;
+	    upper |= ~S << 8;
+	    upper -= 0x0100; /* Sign extend.  */
+
+	    addend = (upper << 12) | (lower << 1);
+	    signed_addend = addend;
+	  }
+
+	/* ??? Should handle interworking?  GCC might someday try to
+	   use this for tail calls.  */
+
+      	relocation = value + signed_addend;
+	relocation -= (input_section->output_section->vma
+		       + input_section->output_offset
+		       + rel->r_offset);
+
+	check = relocation >> howto->rightshift;
+
+	/* If this is a signed value, the rightshift just dropped
+	   leading 1 bits (assuming twos complement).  */
+	if ((bfd_signed_vma) relocation >= 0)
+	  signed_check = check;
+	else
+	  signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
+
+	/* Assumes two's complement.  */
+	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
+	  overflow = TRUE;
+
+	/* Put RELOCATION back into the insn.  */
+	{
+	  bfd_vma S  = (relocation & 0x01000000) >> 24;
+	  bfd_vma I1 = (relocation & 0x00800000) >> 23;
+	  bfd_vma I2 = (relocation & 0x00400000) >> 22;
+	  bfd_vma hi = (relocation & 0x003ff000) >> 12;
+	  bfd_vma lo = (relocation & 0x00000ffe) >>  1;
+
+	  I1 ^= S;
+	  I2 ^= S;
+
+	  upper_insn = (upper_insn & ~(bfd_vma) 0x07ff) | (S << 10) | hi;
+	  lower_insn = (lower_insn & ~(bfd_vma) 0x2fff) | (I1 << 13) | (I2 << 11) | lo;
+	}
+
+	/* Put the relocated value back in the object file:  */
+	bfd_put_16 (input_bfd, upper_insn, hit_data);
+	bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
+
+	return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
+      }
+
     case R_ARM_THM_JUMP11:
     case R_ARM_THM_JUMP8:
+    case R_ARM_THM_JUMP6:
       /* Thumb B (branch) instruction).  */
       {
 	bfd_signed_vma relocation;
@@ -3318,6 +3467,10 @@
 	bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
 	bfd_signed_vma signed_check;
 
+	/* CZB cannot jump backward.  */
+	if (r_type == R_ARM_THM_JUMP6)
+	  reloc_signed_min = 0;
+
 	if (globals->use_rel)
 	  {
 	    /* Need to refetch addend.  */
@@ -3343,7 +3496,11 @@
 
 	relocation >>= howto->rightshift;
 	signed_check = relocation;
-	relocation &= howto->dst_mask;
+
+	if (r_type == R_ARM_THM_JUMP6)
+	  relocation = ((relocation & 0x0020) << 4) | ((relocation & 0x001f) << 3);
+	else
+	  relocation &= howto->dst_mask;
 	relocation |= (bfd_get_16 (input_bfd, hit_data) & (~ howto->dst_mask));
 
 	bfd_put_16 (input_bfd, relocation, hit_data);

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]