This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
ARM MOVW/MOVT fixes
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Sat, 8 Mar 2008 01:18:50 +0000
- Subject: ARM MOVW/MOVT fixes
The attached patch fixes a bunch of bugs in the handling of ARM MOVW and MOVT
relocations. Specifically:
- Relocation addends were being encoded incorrectly. This was a threefold
failure. elf32_arm_relocate_section doesn't know how to handle these. The
bitmask in the HOWTO table is wrong, and we don't check that that bitmask is
sane before using the simple contiguous-bits fallback.
- elf32_arm_final_link_relocate has an off by one error. REL addends are 16
bits including the sign bit.
- Copy relocations are not generated when MOVW/T relocations refer to data
objects in shared libraries. elf32_arm_check_relocs should only set
needs_plt for call type relocations.
- The assembler enforces the wrong range for relocation addends. It looks
like someone got confused or copy/pasted from ADD/SUB instructions.
Paul
2008-03-07 Paul Brook <paul@codesourcery.com>
bfd/
* elf32-arm.c (elf32_arm_howto_table_1): Fix bitmasks for MOVW and
MOVT relocations.
(elf32_arm_final_link_relocate): Fix off by one MOVW/MOVT sign
extension.
(elf32_arm_relocate_section): Handle MOVW and MOVT
relocations. Improve safety check for other weird relocations.
(elf32_arm_check_relocs): Only set h->needs_plt for branch/call
relocations.
gas/
* config/tc-arm.c (md_apply_fix): Use correct offset range.
ld/testsuite/
* ld-arm/arm-elf.exp (armelftests): Add movw-merge and arm-app-movw.
* ld-arm/arm-app-movw.s: New test.
* ld-arm/arm-app.r: Update expected output.
* ld-arm/movw-merge.d: New test.
* ld-arm/movw-merge.s: New test.
Index: bfd/elf32-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/bfd/elf32-arm.c,v
retrieving revision 1.136
diff -u -p -r1.136 elf32-arm.c
--- bfd/elf32-arm.c 20 Feb 2008 17:42:35 -0000 1.136
+++ bfd/elf32-arm.c 8 Mar 2008 00:25:37 -0000
@@ -696,8 +696,8 @@ static reloc_howto_type elf32_arm_howto_
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVW_ABS_NC", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_ARM_MOVT_ABS, /* type */
@@ -710,8 +710,8 @@ static reloc_howto_type elf32_arm_howto_
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVT_ABS", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
FALSE), /* pcrel_offset */
HOWTO (R_ARM_MOVW_PREL_NC, /* type */
@@ -724,8 +724,8 @@ static reloc_howto_type elf32_arm_howto_
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVW_PREL_NC", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
TRUE), /* pcrel_offset */
HOWTO (R_ARM_MOVT_PREL, /* type */
@@ -738,8 +738,8 @@ static reloc_howto_type elf32_arm_howto_
bfd_elf_generic_reloc, /* special_function */
"R_ARM_MOVT_PREL", /* name */
FALSE, /* partial_inplace */
- 0x0000ffff, /* src_mask */
- 0x0000ffff, /* dst_mask */
+ 0x000f0fff, /* src_mask */
+ 0x000f0fff, /* dst_mask */
TRUE), /* pcrel_offset */
HOWTO (R_ARM_THM_MOVW_ABS_NC, /* type */
@@ -5916,7 +5881,7 @@ elf32_arm_final_link_relocate (reloc_how
if (globals->use_rel)
{
addend = ((insn >> 4) & 0xf000) | (insn & 0xfff);
- signed_addend = (addend ^ 0x10000) - 0x10000;
+ signed_addend = (addend ^ 0x8000) - 0x8000;
}
value += signed_addend;
@@ -5966,7 +5931,7 @@ elf32_arm_final_link_relocate (reloc_how
| ((insn >> 15) & 0x0800)
| ((insn >> 4) & 0x0700)
| (insn & 0x00ff);
- signed_addend = (addend ^ 0x10000) - 0x10000;
+ signed_addend = (addend ^ 0x8000) - 0x8000;
}
value += signed_addend;
@@ -6548,34 +6513,85 @@ elf32_arm_relocate_section (bfd *
asection *msec;
bfd_vma addend, value;
- if (howto->rightshift)
+ switch (r_type)
{
- (*_bfd_error_handler)
- (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
- input_bfd, input_section,
- (long) rel->r_offset, howto->name);
- return FALSE;
- }
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ addend = ((value & 0xf0000) >> 4) | (value & 0xfff);
+ addend = (addend ^ 0x8000) - 0x8000;
+ break;
- value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ value = bfd_get_16 (input_bfd, contents + rel->r_offset)
+ << 16;
+ value |= bfd_get_16 (input_bfd,
+ contents + rel->r_offset + 2);
+ addend = ((value & 0xf7000) >> 4) | (value & 0xff)
+ | ((value & 0x04000000) >> 15);
+ addend = (addend ^ 0x8000) - 0x8000;
+ break;
- /* Get the (signed) value from the instruction. */
- addend = value & howto->src_mask;
- if (addend & ((howto->src_mask + 1) >> 1))
- {
- bfd_signed_vma mask;
+ default:
+ if (howto->rightshift
+ || (howto->src_mask & (howto->src_mask + 1)))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
+ input_bfd, input_section,
+ (long) rel->r_offset, howto->name);
+ return FALSE;
+ }
- mask = -1;
- mask &= ~ howto->src_mask;
- addend |= mask;
+ value = bfd_get_32 (input_bfd, contents + rel->r_offset);
+
+ /* Get the (signed) value from the instruction. */
+ addend = value & howto->src_mask;
+ if (addend & ((howto->src_mask + 1) >> 1))
+ {
+ bfd_signed_vma mask;
+
+ mask = -1;
+ mask &= ~ howto->src_mask;
+ addend |= mask;
+ }
+ break;
}
+
msec = sec;
addend =
_bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
- relocation;
addend += msec->output_section->vma + msec->output_offset;
- value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask);
- bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+
+ /* Cases here must match those in the preceeding
+ switch statement. */
+ switch (r_type)
+ {
+ case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVT_ABS:
+ value = (value & 0xfff0f000) | ((addend & 0xf000) << 4)
+ | (addend & 0xfff);
+ bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+ break;
+
+ case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVT_ABS:
+ value = (value & 0xfbf08f00) | ((addend & 0xf700) << 4)
+ | (addend & 0xff) | ((addend & 0x0800) << 15);
+ bfd_put_16 (input_bfd, value >> 16,
+ contents + rel->r_offset);
+ bfd_put_16 (input_bfd, value,
+ contents + rel->r_offset + 2);
+ break;
+
+ default:
+ value = (value & ~ howto->dst_mask)
+ | (addend & howto->dst_mask);
+ bfd_put_32 (input_bfd, value, contents + rel->r_offset);
+ break;
+ }
}
}
else
@@ -7663,6 +7679,7 @@ elf32_arm_check_relocs (bfd *abfd, struc
asection *sreloc;
bfd_vma *local_got_offsets;
struct elf32_arm_link_hash_table *htab;
+ bfd_boolean needs_plt;
if (info->relocatable)
return TRUE;
@@ -7804,10 +7821,6 @@ elf32_arm_check_relocs (bfd *abfd, struc
break;
/* Fall through */
- case R_ARM_ABS32:
- case R_ARM_ABS32_NOI:
- case R_ARM_REL32:
- case R_ARM_REL32_NOI:
case R_ARM_PC24:
case R_ARM_PLT32:
case R_ARM_CALL:
@@ -7816,6 +7829,13 @@ elf32_arm_check_relocs (bfd *abfd, struc
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
case R_ARM_THM_JUMP19:
+ needs_plt = 1;
+ goto normal_reloc;
+
+ case R_ARM_ABS32:
+ case R_ARM_ABS32_NOI:
+ case R_ARM_REL32:
+ case R_ARM_REL32_NOI:
case R_ARM_MOVW_ABS_NC:
case R_ARM_MOVT_ABS:
case R_ARM_MOVW_PREL_NC:
@@ -7824,6 +7844,9 @@ elf32_arm_check_relocs (bfd *abfd, struc
case R_ARM_THM_MOVT_ABS:
case R_ARM_THM_MOVW_PREL_NC:
case R_ARM_THM_MOVT_PREL:
+ needs_plt = 0;
+ normal_reloc:
+
/* Should the interworking branches be listed here? */
if (h != NULL)
{
@@ -7840,11 +7863,7 @@ elf32_arm_check_relocs (bfd *abfd, struc
refers to is in a different object. We can't tell for
sure yet, because something later might force the
symbol local. */
- if (r_type != R_ARM_ABS32
- && r_type != R_ARM_REL32
- && r_type != R_ARM_ABS32_NOI
- && r_type != R_ARM_REL32_NOI
- && r_type != R_ARM_ABS12)
+ if (needs_plt)
h->needs_plt = 1;
/* If we create a PLT entry, this relocation will reference
Index: gas/config/tc-arm.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/gas/config/tc-arm.c,v
retrieving revision 1.349
diff -u -p -r1.349 tc-arm.c
--- gas/config/tc-arm.c 5 Mar 2008 01:31:26 -0000 1.349
+++ gas/config/tc-arm.c 6 Mar 2008 20:39:18 -0000
@@ -18804,7 +18804,7 @@ md_apply_fix (fixS * fixP,
/* REL format relocations are limited to a 16-bit addend. */
if (!fixP->fx_done)
{
- if (value < -0x1000 || value > 0xffff)
+ if (value < -0x8000 || value > 0x7fff)
as_bad_where (fixP->fx_file, fixP->fx_line,
_("offset out of range"));
}
Index: ld/testsuite/ld-arm/arm-app-movw.s
===================================================================
RCS file: ld/testsuite/ld-arm/arm-app-movw.s
diff -N ld/testsuite/ld-arm/arm-app-movw.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/arm-app-movw.s 6 Mar 2008 20:43:39 -0000
@@ -0,0 +1,11 @@
+ .text
+ .globl _start
+_start:
+ movw r0, #:lower16:data_obj
+ movt r0, #:upper16:data_obj
+ movw r0, #:lower16:lib_func1
+ movt r0, #:upper16:lib_func1
+
+ .globl app_func2
+app_func2:
+ bx lr
Index: ld/testsuite/ld-arm/arm-app.r
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/testsuite/ld-arm/arm-app.r,v
retrieving revision 1.2
diff -u -p -r1.2 arm-app.r
--- ld/testsuite/ld-arm/arm-app.r 17 Nov 2004 17:50:27 -0000 1.2
+++ ld/testsuite/ld-arm/arm-app.r 8 Mar 2008 00:15:20 -0000
@@ -1,5 +1,5 @@
-tmpdir/arm-app: file format elf32-(little|big)arm
+tmpdir/arm-app.*: file format elf32-(little|big)arm
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
Index: ld/testsuite/ld-arm/arm-elf.exp
===================================================================
RCS file: /var/cvsroot/src-cvs/src/ld/testsuite/ld-arm/arm-elf.exp,v
retrieving revision 1.32
diff -u -p -r1.32 arm-elf.exp
--- ld/testsuite/ld-arm/arm-elf.exp 20 Feb 2008 15:17:56 -0000 1.32
+++ ld/testsuite/ld-arm/arm-elf.exp 8 Mar 2008 00:25:37 -0000
@@ -176,6 +176,12 @@ set armelftests {
{"ARMv4 interworking" "-static -T arm.ld --fix-v4bx-interworking" "--fix-v4bx -meabi=4" {armv4-bx.s}
{{objdump -d armv4-bx.d}}
"armv4-bx"}
+ {"MOVW/MOVT and merged sections" "-T arm.ld" "" {movw-merge.s}
+ {{objdump -dw movw-merge.d}}
+ "movw-merge"}
+ {"MOVW/MOVT against shared libraries" "tmpdir/arm-lib.so" "" {arm-app-movw.s}
+ {{objdump -Rw arm-app.r}}
+ "arm-app-movw"}
}
run_ld_link_tests $armelftests
Index: ld/testsuite/ld-arm/movw-merge.d
===================================================================
RCS file: ld/testsuite/ld-arm/movw-merge.d
diff -N ld/testsuite/ld-arm/movw-merge.d
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/movw-merge.d 6 Mar 2008 18:00:56 -0000
@@ -0,0 +1,13 @@
+
+.*: file format.*
+
+Disassembly of section .text:
+
+00008000 <[^>]*>:
+ 8000: e3080013 movw r0, #32787 ; 0x8013
+ 8004: e3400000 movt r0, #0 ; 0x0
+
+00008008 <[^>]*>:
+ 8008: f248 0013 movw r0, #32787 ; 0x8013
+ 800c: f2c0 0000 movt r0, #0 ; 0x0
+
Index: ld/testsuite/ld-arm/movw-merge.s
===================================================================
RCS file: ld/testsuite/ld-arm/movw-merge.s
diff -N ld/testsuite/ld-arm/movw-merge.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-arm/movw-merge.s 6 Mar 2008 18:00:56 -0000
@@ -0,0 +1,20 @@
+ .arch armv7-a
+ .syntax unified
+ .text
+ .global _start
+ .type _start, %function
+_start:
+ movw r0, #:lower16:.LC0
+ movt r0, #:upper16:.LC0
+ .thumb
+ .global tfunc
+ .type tfunc, %function
+tfunc:
+ movw r0, #:lower16:.LC0
+ movt r0, #:upper16:.LC0
+
+ .section .rodata.str1.4,"aMS",%progbits,1
+ .align 2
+ .ascii "pad"
+.LC0:
+ .ascii "inner: cont \000"