This is the mail archive of the binutils@sourceware.org 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]

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"

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