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]

gas patch: m68k bug fix for as -l


OK guys,

Here is my first patch with actual useful stuff in it, not just portability
goo! It fixes what I and the PalmOS (an m68k embedded system) community would
consider a serious bug in gas. Currently (that is, until I implement link-time
relaxing for m68k ELF, which will be my next task) gas emits long (32-bit)
references for branches to external symbols. On 68020 these are long branches
(PC-relative), but on the 68000 which doesn't have them absolute jumps are
emitted instead. This is a problem for PIC environments where absolute
references are forbidden (such as PalmOS).

gas, however, has the -l option which is supposed to make references to
external symbols short, which are PC-relative and thus OK. But as most people
in the PalmOS community know, the -l option is broken for most types of
branches on 68000. For some branches (unconditional jra and jbsr) it has no
effect whatsoever, while for others (all conditional Bcc's and DBcc's) it
produces totally bogus code (a short 16-bit *absolute* reference, which will
fail everywhere except in the first 32 KB of the absolute address space).

The patch below fixes this bug (it also adds an abort when the relaxing state
machine gets into a state it should never get into, as a self-check). Is it OK?
I think this really is a bug and this patch should be applied both to the trunk
and to the release branch.

--
Michael Sokolov		Harhan Engineering Laboratory
Public Service Agent	International Free Computing Task Force
			International Engineering and Science Task Force
			615 N GOOD LATIMER EXPY STE #4
			DALLAS TX 75204-5852 USA

Phone: +1-214-824-7693 (Harhan Eng Lab office)
E-mail: msokolov@ivan.Harhan.ORG (ARPA TCP/SMTP) (UUCP coming soon)

2000-04-17  Michael Sokolov  <msokolov@ivan.Harhan.ORG>

	* config/tc-m68k.c (md_convert_frag_1, md_estimate_size_before_relax):
	abort if we end up in the ABRANCH LONG case for a conditional branch on
	a 68000, as that can only mean an internal bug.
	(md_estimate_size_before_relax): Handle flag_short_refs correctly for
	ABRANCH, BCC68000, and DBCC.

Index: tc-m68k.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-m68k.c,v
retrieving revision 1.5
diff -c -3 -p -r1.5 tc-m68k.c
*** tc-m68k.c	1999/07/12 08:34:56	1.5
--- tc-m68k.c	2000/04/17 21:14:46
*************** md_convert_frag_1 (fragP)
*** 4348,4354 ****
  	    }
  	  else
  	    {
! 	      as_bad (_("Long branch offset not supported."));
  	    }
  	}
        else
--- 4348,4357 ----
  	    }
  	  else
  	    {
! 	      /* This should never happen, because if it's a conditional
! 	         branch and we are on a 68000, BCC68000 should have been
! 	         picked instead of ABRANCH. */
! 	      abort ();
  	    }
  	}
        else
*************** md_estimate_size_before_relax (fragP, se
*** 4529,4534 ****
--- 4532,4545 ----
  	    fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), BYTE);
  	    break;
  	  }
+ 	else if ((fragP->fr_symbol != NULL) && flag_short_refs)
+ 	  {			/* Symbol is undefined and we want short ref */
+ 	    fix_new (fragP, (int) (fragP->fr_fix), 2, fragP->fr_symbol,
+ 		     fragP->fr_offset, 1, NO_RELOC);
+ 	    fragP->fr_fix += 2;
+ 	    frag_wane (fragP);
+ 	    break;
+ 	  }
  	else if ((fragP->fr_symbol == 0) || !HAVE_LONG_BRANCH(current_architecture))
  	  {
  	    /* On 68000, or for absolute value, switch to abs long */
*************** md_estimate_size_before_relax (fragP, se
*** 4553,4559 ****
  	      }
  	    else
  	      {
! 		as_warn (_("Long branch offset to extern symbol not supported."));
  	      }
  	  }
  	else
--- 4564,4573 ----
  	      }
  	    else
  	      {
! 		/* This should never happen, because if it's a conditional
! 		   branch and we are on a 68000, BCC68000 should have been
! 		   picked instead of ABRANCH. */
! 		abort ();
  	      }
  	  }
  	else
*************** md_estimate_size_before_relax (fragP, se
*** 4618,4638 ****
  	    break;
  	  }
  	/* only Bcc 68000 instructions can come here */
! 	/* change bcc into b!cc/jmp absl long */
! 	fragP->fr_opcode[0] ^= 0x01;	/* invert bcc */
! 	if (flag_short_refs)
  	  {
! 	    fragP->fr_opcode[1] = 0x04;	/* branch offset = 6 */
! 	    /* JF: these were fr_opcode[2,3] */
! 	    buffer_address[0] = 0x4e;	/* put in jmp long (0x4ef9) */
! 	    buffer_address[1] = (char) 0xf8;
! 	    fragP->fr_fix += 2;	/* account for jmp instruction */
  	    fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
! 		     fragP->fr_offset, 0, NO_RELOC);
  	    fragP->fr_fix += 2;
  	  }
  	else
  	  {
  	    fragP->fr_opcode[1] = 0x06;	/* branch offset = 6 */
  	    /* JF: these were fr_opcode[2,3] */
  	    buffer_address[0] = 0x4e;	/* put in jmp long (0x4ef9) */
--- 4632,4648 ----
  	    break;
  	  }
  	/* only Bcc 68000 instructions can come here */
! 	if ((fragP->fr_symbol != NULL) && flag_short_refs)
  	  {
! 	    /* the user wants short refs, so emit one */
  	    fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
! 		     fragP->fr_offset, 1, NO_RELOC);
  	    fragP->fr_fix += 2;
  	  }
  	else
  	  {
+ 	    /* change bcc into b!cc/jmp absl long */
+ 	    fragP->fr_opcode[0] ^= 0x01;	/* invert bcc */
  	    fragP->fr_opcode[1] = 0x06;	/* branch offset = 6 */
  	    /* JF: these were fr_opcode[2,3] */
  	    buffer_address[0] = 0x4e;	/* put in jmp long (0x4ef9) */
*************** md_estimate_size_before_relax (fragP, se
*** 4657,4681 ****
  	    break;
  	  }
  	/* only DBcc 68000 instructions can come here */
! 	/* change dbcc into dbcc/jmp absl long */
! 	/* JF: these used to be fr_opcode[2-4], which is wrong. */
! 	buffer_address[0] = 0x00;	/* branch offset = 4 */
! 	buffer_address[1] = 0x04;
! 	buffer_address[2] = 0x60;	/* put in bra pc + ... */
! 
! 	if (flag_short_refs)
! 	  {
! 	    /* JF: these were fr_opcode[5-7] */
! 	    buffer_address[3] = 0x04;	/* plus 4 */
! 	    buffer_address[4] = 0x4e;	/* Put in Jump Word */
! 	    buffer_address[5] = (char) 0xf8;
! 	    fragP->fr_fix += 6;	/* account for bra/jmp instruction */
  	    fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
! 		     fragP->fr_offset, 0, NO_RELOC);
  	    fragP->fr_fix += 2;
  	  }
  	else
  	  {
  	    /* JF: these were fr_opcode[5-7] */
  	    buffer_address[3] = 0x06;	/* Plus 6 */
  	    buffer_address[4] = 0x4e;	/* put in jmp long (0x4ef9) */
--- 4667,4687 ----
  	    break;
  	  }
  	/* only DBcc 68000 instructions can come here */
! 
! 	if (fragP->fr_symbol != NULL && flag_short_refs)
! 	  {
! 	    /* the user wants short refs, so emit one */
  	    fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
! 		     fragP->fr_offset, 1, NO_RELOC);
  	    fragP->fr_fix += 2;
  	  }
  	else
  	  {
+ 	    /* change dbcc into dbcc/jmp absl long */
+ 	    /* JF: these used to be fr_opcode[2-4], which is wrong. */
+ 	    buffer_address[0] = 0x00;	/* branch offset = 4 */
+ 	    buffer_address[1] = 0x04;
+ 	    buffer_address[2] = 0x60;	/* put in bra pc + ... */
  	    /* JF: these were fr_opcode[5-7] */
  	    buffer_address[3] = 0x06;	/* Plus 6 */
  	    buffer_address[4] = 0x4e;	/* put in jmp long (0x4ef9) */

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