This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Thumb32 assembler (65/69)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Tue, 26 Apr 2005 03:02:16 -0700
- Subject: 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);