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

Re: arm-elf-as truncates branch offsets w/o warning


Hi Grant,

  OK, here is another patch for you to try out.  It is basically your
  patch with a little extra code to handle the case where a
  pc-relative unrelocated instruction can be generated.  ie this code
  will handle your first example:

      .text
      .org 0x05000000
      b    label1
      nop
      nop
      nop
 label1:
      nop

  [I do not run out of memeory linking this one.  But then I have a big
  machine!]

  But it will not handle your second example, where the destination of
  the branch is not known to be in the same section as the source of
  the branch.  (At least this is not known at assemble time).  Instead
  an error message will be genreated, ratehr than silently producing
  bad code.

  The patch will also generate an error for your third case where the
  branch definitely is out of range, despite it being within the same
  section.
  
  Can you try the patch out and let me know if it works for you.

Cheers
	Nick


Index: config/tc-arm.c
===================================================================
RCS file: /cvs/src//src/gas/config/tc-arm.c,v
retrieving revision 1.33
diff -p -r1.33 tc-arm.c
*** tc-arm.c	2000/02/24 19:46:27	1.33
--- tc-arm.c	2000/03/17 02:22:35
*************** md_apply_fix3 (fixP, val, seg)
*** 5560,5571 ****
      case BFD_RELOC_ARM_PCREL_BRANCH:
        newval = md_chars_to_number (buf, INSN_SIZE);
  
  #ifdef OBJ_ELF
        if (! target_oabi)
!         value = fixP->fx_offset;
  #endif
!       value  = (value >> 2) & 0x00ffffff;
!       value  = (value + (newval & 0x00ffffff)) & 0x00ffffff;
        newval = value | (newval & 0xff000000);
        md_number_to_chars (buf, newval, INSN_SIZE);
        break;
--- 5560,5623 ----
      case BFD_RELOC_ARM_PCREL_BRANCH:
        newval = md_chars_to_number (buf, INSN_SIZE);
  
+       /* Sign-extend a 24-bit number.  */
+ #define SEXT24(x)	((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
+ 
  #ifdef OBJ_ELF
        if (! target_oabi)
! 	value = fixP->fx_offset;
  #endif
! 
!       /* We are going to store value (shifted right by two) in the
! 	 instruction, in a 24 bit, signed field.  Thus we need to check
! 	 that none of the top 8 bits of the shifted value (top 7 bits of
!          the unshifted, unsigned value) are set, or that they are all set.  */
!       if ((value & 0xfe000000UL) != 0
! 	  && ((value & 0xfe000000UL) != 0xfe000000UL))
! 	{
! #ifdef OBJ_ELF
! 	  /* Normally we would be stuck at this point, since we cannot store
! 	     the absolute address that is the destination of the branch in the
! 	     24 bits of the branch instruction.  If however, we happen to know
! 	     that the destination of the branch is in the same section as the
! 	     branch instruciton itself, then we can compute the relocation for
! 	     ourselves and not have to bother the linker with it.
! 	     
! 	     FIXME: The tests for OBJ_ELF and ! target_oabi are only here
! 	     because I have not worked out how to do this for OBJ_COFF or
! 	     target_oabi.  */
! 	  if (! target_oabi
! 	      && fixP->fx_addsy != NULL
! 	      && S_IS_DEFINED (fixP->fx_addsy)
! 	      && S_GET_SEGMENT (fixP->fx_addsy) == seg)
! 	    {
! 	      /* Compute the pc relative valeu to go into the branch.  */
! 	      value = fixP->fx_offset - fixP->fx_frag->fr_address;
! 
! 	      /* Permit a negative branch provided that enough bits are set.  */
! 	      if ((value & 0xfe000000UL) == 0xfe000000UL)
! 		{
! 		  value &= ~ 0xfc000000UL;
! 		  fixP->fx_done = 1;
! 		}
! 	      /* Also allow a positive branch, provided enough bits are clear.  */
! 	      else if ((value & 0xfe000000UL) == 0)
! 		fixP->fx_done = 1;
! 	    }
! 	  
! 	  if (! fixP->fx_done)
! #endif
! 	    as_bad_where (fixP->fx_file, fixP->fx_line,
! 			  _("gas can't handle same-section branch dest >= 0x04000000"));
! 	}
! 
!       value >>= 2;
!       value += SEXT24 (newval);
!       
!       if (value & 0xff000000UL)
! 	as_bad_where (fixP->fx_file, fixP->fx_line,
! 		      _("out of range branch"));
!       
        newval = value | (newval & 0xff000000);
        md_number_to_chars (buf, newval, INSN_SIZE);
        break;

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