Fix Thumb BLX encoding and simulation

Nick Clifton nickc@cambridge.redhat.com
Thu May 23 05:50:00 GMT 2002


Hi Guys,

  It turns out that the current tools have not been encoding the
  thumb BLX instruction correctly.  The sources were all internally
  consistent, but when you run the binaries on real hardware, they
  break. :-(  I am applying the patch below to fix this problem.

  There is another issue however, in that arm-coff relocs do not seem
  to be applied properly at the moment.  I am investigating this
  problem, but I do not have a fix yet.

Cheers
        Nick

gas/ChangeLog
2002-05-23  Nick Clifton  <nickc@cambridge.redhat.com>

	* config/tc-arm.c (md_apply_fix3): For the Thumb BLX reloc
	round the relocation up rather than down.

bfd/ChangeLog
2002-05-23  Nick Clifton  <nickc@cambridge.redhat.com>

	* elf32-arm.h (elf32_arm_final_link_relocate): For the Thumb
	BLX reloc round the relocation up rather than down.
	* coff-arm.c (coff_arm_relocate_section): Likewise.

sim/arm/ChangeLog
2002-05-23  Nick Clifton  <nickc@cambridge.redhat.com>

	* thumbemu.c (ARMul_ThumbDecode): When decoding a BLX(1)
	instruction do not add in the second bit of the base address -
	this has already been accounted for.

Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.122
diff -c -3 -p -w -r1.122 tc-arm.c
*** gas/config/tc-arm.c	22 May 2002 16:46:27 -0000	1.122
--- gas/config/tc-arm.c	23 May 2002 12:25:34 -0000
*************** md_apply_fix3 (fixP, valP, seg)
*** 9946,9959 ****
  	newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
  	newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
  	if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
! 	  /* Remove bit zero of the adjusted offset.  Bit zero can only be
! 	     set if the upper insn is at a half-word boundary, since the
! 	     destination address, an ARM instruction, must always be on a
! 	     word boundary.  The semantics of the BLX (1) instruction, however,
! 	     are that bit zero in the offset must always be zero, and the
! 	     corresponding bit one in the target address will be set from bit
! 	     one of the source address.  */
! 	  newval2 &= ~1;
  	md_number_to_chars (buf, newval, THUMB_SIZE);
  	md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
        }
--- 9947,9957 ----
  	newval  = (newval  & 0xf800) | ((value & 0x7fffff) >> 12);
  	newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
  	if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
! 	  /* For a BLX instruction, make sure that the relocation is rounded up
! 	     to a word boundary.  This follows the semantics of the instruction
! 	     which specifies that bit 1 of the target address will come from bit
! 	     1 of the base address.  */
! 	  newval2 = (newval2 + 1) & ~ 1;
  	md_number_to_chars (buf, newval, THUMB_SIZE);
  	md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
        }

Index: bfd/elf32-arm.h
===================================================================
RCS file: /cvs/src/src/bfd/elf32-arm.h,v
retrieving revision 1.81
diff -c -3 -p -w -r1.81 elf32-arm.h
*** bfd/elf32-arm.h	7 May 2002 00:16:50 -0000	1.81
--- bfd/elf32-arm.h	23 May 2002 12:25:32 -0000
*************** elf32_arm_final_link_relocate (howto, in
*** 1471,1492 ****
  	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
  	  overflow = true;
  
- 	/* Put RELOCATION back into the insn.  */
- 	upper_insn = (upper_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 12) & 0x7ff);
- 	lower_insn = (lower_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 1) & 0x7ff);
- 
  #ifndef OLD_ARM_ABI
  	if (r_type == R_ARM_THM_XPC22
  	    && ((lower_insn & 0x1800) == 0x0800))
! 	  /* Remove bit zero of the adjusted offset.  Bit zero can only be
! 	     set if the upper insn is at a half-word boundary, since the
! 	     destination address, an ARM instruction, must always be on a
! 	     word boundary.  The semantics of the BLX (1) instruction, however,
! 	     are that bit zero in the offset must always be zero, and the
! 	     corresponding bit one in the target address will be set from bit
! 	     one of the source address.  */
! 	  lower_insn &= ~1;
  #endif
  	/* 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);
--- 1471,1489 ----
  	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
  	  overflow = true;
  
  #ifndef OLD_ARM_ABI
  	if (r_type == R_ARM_THM_XPC22
  	    && ((lower_insn & 0x1800) == 0x0800))
! 	  /* For a BLX instruction, make sure that the relocation is rounded up
! 	     to a word boundary.  This follows the semantics of the instruction
! 	     which specifies that bit 1 of the target address will come from bit
! 	     1 of the base address.  */
! 	  relocation = (relocation + 2) & ~ 3;
  #endif
+ 	/* Put RELOCATION back into the insn.  */
+ 	upper_insn = (upper_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 12) & 0x7ff);
+ 	lower_insn = (lower_insn & ~(bfd_vma) 0x7ff) | ((relocation >> 1) & 0x7ff);
+ 
  	/* 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);

Index: bfd/coff-arm.c
===================================================================
RCS file: /cvs/src/src/bfd/coff-arm.c,v
retrieving revision 1.37
diff -c -3 -p -w -r1.37 coff-arm.c
*** bfd/coff-arm.c	18 Apr 2002 09:28:29 -0000	1.37
--- bfd/coff-arm.c	23 May 2002 12:25:31 -0000
*************** coff_arm_relocate_section (output_bfd, i
*** 1701,1721 ****
  		  || signed_check < reloc_signed_min)
  		overflow = true;
  
! 	      /* For the BLX(1) instruction remove bit 0 of the adjusted offset.
! 		 Bit 0 can only be set if the upper insn is at a half-word boundary,
! 		 since the destination address, an ARM instruction, must always be
! 		 on a word boundary.  The semantics of the BLX (1) instruction,
! 		 however, are that bit 0 in the offset must always be 0, and the
! 		 corresponding bit 1 in the target address will be set from bit
! 		 1 of the source address.  */
! 	      if ((x & 0x18000000) == 0x08000000)
! 		relocation &= ~0x2;
! 
! 	      /* Put the relocation into the correct bits.  */
  	      if (bfd_big_endian (input_bfd))
  		relocation = (((relocation & 0xffe) >> 1)  | ((relocation << 4) & 0x07ff0000));
  	      else
  		relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
  
  	      /* Add the relocation to the correct bits of X.  */
  	      x = ((x & ~howto->dst_mask) | relocation);
--- 1701,1723 ----
  		  || signed_check < reloc_signed_min)
  		overflow = true;
  
! 	      /* Put the relocation into the correct bits.
! 		 For a BLX instruction, make sure that the relocation is rounded up
! 		 to a word boundary.  This follows the semantics of the instruction
! 		 which specifies that bit 1 of the target address will come from bit
! 		 1 of the base address.  */
  	      if (bfd_big_endian (input_bfd))
+ 	        {
+ 		  if ((x & 0x1800) == 0x0800 && (relocation & 0x02))
+ 		    relocation += 2;
  		  relocation = (((relocation & 0xffe) >> 1)  | ((relocation << 4) & 0x07ff0000));
+ 		}
  	      else
+ 	        {
+ 		  if ((x & 0x18000000) == 0x08000000 && (relocation & 0x02))
+ 		    relocation += 2;
  		  relocation = (((relocation & 0xffe) << 15) | ((relocation >> 12) & 0x7ff));
+ 		}
  
  	      /* Add the relocation to the correct bits of X.  */
  	      x = ((x & ~howto->dst_mask) | relocation);

Index: sim/arm/thumbemu.c
===================================================================
RCS file: /cvs/src/src/sim/arm/thumbemu.c,v
retrieving revision 1.3
diff -c -3 -p -w -r1.3 thumbemu.c
*** sim/arm/thumbemu.c	6 Mar 2001 22:33:47 -0000	1.3
--- sim/arm/thumbemu.c	23 May 2002 12:25:35 -0000
*************** tdstate ARMul_ThumbDecode (state, pc, ti
*** 520,531 ****
  	    {
  	      ARMword tmp = (pc + 2);
  
- 	      /* Bit one of the destination address comes from bit one of the
- 		 address of the first (H == 10) half of the instruction, not
- 		 from the offset in the instruction.  */
  	      state->Reg[15] = ((state->Reg[14]
! 				 + ((tinstr & 0x07FE) << 1)
! 				 + ((pc - 2) & 2))
  				& 0xFFFFFFFC);
  	      CLEART;
  	      state->Reg[14] = (tmp | 1);
--- 520,527 ----
  	    {
  	      ARMword tmp = (pc + 2);
  
  	      state->Reg[15] = ((state->Reg[14]
! 				 + ((tinstr & 0x07FE) << 1))
  				& 0xFFFFFFFC);
  	      CLEART;
  	      state->Reg[14] = (tmp | 1);
*************** tdstate ARMul_ThumbDecode (state, pc, ti
*** 538,543 ****
--- 534,540 ----
  	  break;
  	}
        /* else we fall through to process the second half of the BL */
+       pc += 2;			/* point the pc at the 2nd half */
      case 31:			/* BL instruction 2 */
        /* Format 19 */
        /* There is no single ARM instruction equivalent for this



More information about the Gdb-patches mailing list