This is the mail archive of the binutils@sources.redhat.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]
Other format: [Raw text]

Committed, MMIX linker relaxation of function calls.


If nothing else, this was a bit of binutils exercise to keep in
shape. :-)  The PUSHJ five-instruction-expansions looked awful.
(Now the GETA expansions look awful.  Next on the TODO list.
And the stubs could do with some reuse.  Also on the list.)

Summary: Controlled by the presence of R_MMIX_PUSHJ_STUBBABLE
that GAS will emit, the linker adds PUSHJ stubs at the end of
the input section when a PUSHJ insn can't reach the target
directly.  The stubs are JMP instructions if target is within
reach (64MB), else the full five-expansion instruction as with
the previously used R_MMIX_PUSHJ.  Brings 1-5% speedup highly
dependent on the program (inner loops reduce the benefit).

Sorry about the KnR, will fix later.

bfd:
	Support linker relaxation of new R_MMIX_PUSHJ_STUBBABLE relocs.
	* elf64-mmix.c (MAX_PUSHJ_STUB_SIZE): New macro.
	(struct _mmix_elf_section_data): New member pjs.
	(mmix_set_relaxable_size, mmix_elf_get_section_contents): New
	functions.
	(elf_mmix_howto_table): New entry for R_MMIX_PUSHJ_STUBBABLE.
	(mmix_reloc_map): Ditto.
	(mmix_elf_relocate_section): Handle R_MMIX_PUSHJ_STUBBABLE.
	(mmix_final_link_relocate, mmix_elf_check_common_relocs): Ditto.
	(mmix_elf_perform_relocation): Ditto.  Don't mark parameter addr
	unused.
	(mmix_elf_check_relocs): Move early return to after
	mmix_elf_check_common_relocs call.
	(mmix_elf_symbol_processing): Fix cut-and-pasto in head comment.
	(_bfd_mmix_before_linker_allocation): Rename from
	_bfd_mmix_prepare_linker_allocated_gregs.  All referers changed.
	Arrange to set the initial relaxable size of sections.
	(_bfd_mmix_after_linker_allocation): Rename from
	_bfd_mmix_finalize_linker_allocated_gregs.
	(mmix_elf_relax_section): Relax a R_MMIX_PUSHJ_STUBBABLE reloc.
	(bfd_elf64_get_section_contents): Define.
	* reloc.c: Add ENUMX for BFD_RELOC_MMIX_PUSHJ_STUBBABLE.
	* libbfd.h, bfd-in2.h: Regenerate.

include/elf:

	* mmix.h (R_MMIX_PUSHJ_STUBBABLE): New reloc number.
	(_bfd_mmix_before_linker_allocation): Rename from
	_bfd_mmix_prepare_linker_allocated_gregs.
	(_bfd_mmix_after_linker_allocation): Rename from
	_bfd_mmix_finalize_linker_allocated_gregs.

ld:
	* emultempl/mmix-elfnmmo.em (mmix_before_allocation): Force linker
	relaxation always; don't exclude relocatable linking.  Adjust for
	_bfd_mmix_prepare_linker_allocated_gregs renamed to
	_bfd_mmix_before_linker_allocation.
	(mmix_after_allocation): Adjust for
	_bfd_mmix_finalize_linker_allocated_gregs renamed to
	_bfd_mmix_after_linker_allocation.
	* scripttempl/mmo.sc: Use ADDR (.text), not . - SIZEOF (.text).

gas:
	Generate BFD_RELOC_MMIX_PUSHJ_STUBBABLE for PUSHJ when possible.
	* doc/c-mmix.texi (MMIX-Opts): Document --no-pushj-stubs and
	--no-stubs.
	* config/tc-mmix.c: Include limits.h.  Expand on mmix_relax_table
	comment.
	(expand_op, mmix_next_semicolon_is_eoln): Fix head comment.
	(pushj_stubs): New variable.
	(OPTION_NOPUSHJSTUBS, STATE_PUSHJSTUB, PUSHJSTUB_MIN)
	(PUSHJSTUB_MAX): New macros.
	(md_longopts): New options "--no-pushj-stubs" and synonym
	"--no-stubs".
	(mmix_relax_table): Handle new entry for STATE_PUSHJSTUB.
	(md_parse_option): Handle OPTION_NOPUSHJSTUBS.
	(md_estimate_size_before_relax): Modify STATE_PUSHJ state for
	PUSHJ stub relaxation.
	(md_convert_frag): Handle STATE_PUSHJSTUB.
	(md_apply_fix3): Handle BFD_RELOC_MMIX_PUSHJ_STUBBABLE.
	(tc_gen_reloc): Ditto.
	(mmix_md_relax_frag): Handle PUSHJ stub relaxation.
	* config/tc-mmix.h (TC_SEGMENT_INFO_TYPE): Define.
	(struct mmix_segment_info_type): New.

gas/testsuite:
	* gas/mmix/op-0-1.d, gas/mmix/pushj-c.d, gas/mmix/weak1.d: Add
	--no-pushj-stubs option.
	* gas/mmix/reloclab-r.d, gas/mmix/reloclab.d: Add --no-stubs
	option.
	* gas/mmix/reloclab.l: Adjust for PUSHJ stub.
	* gas/mmix/pushj-cs.d, gas/mmix/reloclab-s.d, gas/mmix/relax2.s,
	gas/mmix/relax2.d, gas/mmix/op-0-1s.d, gas/mmix/reloclab-rs.d,
	gas/mmix/weak1-s.d: New tests.


ld/testsuite:
	* ld-mmix/greg-14.d, ld-mmix/greg-5.d, ld-mmix/pushja1b.d,
	ld-mmix/pushja1f.d, ld-mmix/pushja7b.d, ld-mmix/pushja7f.d: Pass
	--no-pushj-stubs to the assembler.
	* ld-mmix/pushjs2b.d, ld-mmix/greg-14s.d, ld-mmix/pushjs1.d,
	ld-mmix/greg-5s.d, ld-mmix/pushjs3b.d, ld-mmix/pushja1f-s.d,
	ld-mmix/pushjs1m.d, ld-mmix/pushja7b-s.d, ld-mmix/pushja7f-s.d,
	ld-mmix/pushja1b-s.d, ld-mmix/pushjs2.d, ld-mmix/pushjs3.d,
	ld-mmix/pushjs4b.d, ld-mmix/pushjs4.d, ld-mmix/pushjs1bm.d,
	ld-mmix/pushjs1b.d, ld-mmix/pushjs2m.d, ld-mmix/pushjs1r.d,
	ld-mmix/pushjs3m.d, ld-mmix/pushjs2bm.d, ld-mmix/pushjs4m.d,
	ld-mmix/pushjs3bm.d, ld-mmix/pushjs2r.d, ld-mmix/pushjs4bm.d,
	ld-mmix/pushjs3r.d, ld-mmix/pushjs4r.d: New tests.

Index: reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.93
diff -p -c -r1.93 reloc.c
*** reloc.c	17 Oct 2003 23:03:44 -0000	1.93
--- reloc.c	18 Oct 2003 00:44:14 -0000
*************** ENUMX
*** 3133,3138 ****
--- 3133,3140 ----
    BFD_RELOC_MMIX_PUSHJ_2
  ENUMX
    BFD_RELOC_MMIX_PUSHJ_3
+ ENUMX
+   BFD_RELOC_MMIX_PUSHJ_STUBBABLE
  ENUMDOC
    These are relocations for the PUSHJ instruction.
  ENUM
Index: elf64-mmix.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-mmix.c,v
retrieving revision 1.25
diff -p -c -r1.25 elf64-mmix.c
*** elf64-mmix.c	25 Jun 2003 06:40:23 -0000	1.25
--- elf64-mmix.c	18 Oct 2003 00:44:12 -0000
*************** Foundation, Inc., 59 Temple Place - Suit
*** 21,27 ****
  /* No specific ABI or "processor-specific supplement" defined.  */

  /* TODO:
!    - Linker relaxation.  */

  #include "bfd.h"
  #include "sysdep.h"
--- 21,30 ----
  /* No specific ABI or "processor-specific supplement" defined.  */

  /* TODO:
!    - "Traditional" linker relaxation (shrinking whole sections).
!    - Merge reloc stubs jumping to same location.
!    - GETA stub relaxation (call a stub for out of range new
!      R_MMIX_GETA_STUBBABLE).  */

  #include "bfd.h"
  #include "sysdep.h"
*************** Foundation, Inc., 59 Temple Place - Suit
*** 32,37 ****
--- 35,42 ----

  #define MINUS_ONE	(((bfd_vma) 0) - 1)

+ #define MAX_PUSHJ_STUB_SIZE (5 * 4)
+
  /* Put these everywhere in new code.  */
  #define FATAL_DEBUG						\
   _bfd_abort (__FILE__, __LINE__,				\
*************** struct _mmix_elf_section_data
*** 49,54 ****
--- 54,77 ----
      struct bpo_reloc_section_info *reloc;
      struct bpo_greg_section_info *greg;
    } bpo;
+
+   struct pushj_stub_info
+   {
+     /* Maximum number of stubs needed for this section.  */
+     bfd_size_type n_pushj_relocs;
+
+     /* Size of stubs after a mmix_elf_relax_section round.  */
+     bfd_size_type stubs_size_sum;
+
+     /* Per-reloc stubs_size_sum information.  The stubs_size_sum member is the sum
+        of these.  Allocated in mmix_elf_check_common_relocs.  */
+     bfd_size_type *stub_size;
+
+     /* Offset of next stub during relocation.  Somewhat redundant with the
+        above: error coverage is easier and we don't have to reset the
+        stubs_size_sum for relocation.  */
+     bfd_size_type stub_offset;
+   } pjs;
  };

  #define mmix_elf_section_data(sec) \
*************** struct bpo_greg_section_info
*** 119,127 ****
      size_t n_remaining_bpo_relocs_this_relaxation_round;

      /* The number of linker-allocated GREGs resulting from BPO relocs.
!        This is an approximation after _bfd_mmix_allocated_gregs_init and
!        supposedly accurate after mmix_elf_relax_section is called for all
!        incoming non-collected sections.  */
      size_t n_allocated_bpo_gregs;

      /* Index into reloc_request[], sorted on increasing "value", secondary
--- 142,150 ----
      size_t n_remaining_bpo_relocs_this_relaxation_round;

      /* The number of linker-allocated GREGs resulting from BPO relocs.
!        This is an approximation after _bfd_mmix_before_linker_allocation
!        and supposedly accurate after mmix_elf_relax_section is called for
!        all incoming non-collected sections.  */
      size_t n_allocated_bpo_gregs;

      /* Index into reloc_request[], sorted on increasing "value", secondary
*************** extern void mmix_elf_symbol_processing P
*** 202,207 ****
--- 225,239 ----
  extern void mmix_dump_bpo_gregs
    PARAMS ((struct bfd_link_info *, bfd_error_handler_type));

+ static void
+ mmix_set_relaxable_size
+   PARAMS ((bfd *, asection *, void *));
+
+ static bfd_boolean
+ mmix_elf_get_section_contents
+   PARAMS ((bfd *, sec_ptr, void *, file_ptr, bfd_size_type));
+
+
  /* Watch out: this currently needs to have elements with the same index as
     their R_MMIX_ number.  */
  static reloc_howto_type elf_mmix_howto_table[] =
*************** static reloc_howto_type elf_mmix_howto_t
*** 538,544 ****
    /* The PUSHJ instruction can reach any (code) address, as long as it's
       the beginning of a function (no usable restriction).  It can silently
       expand to a 64-bit operand, but will emit an error if any of the two
!      least significant bits are set.  The howto members reflect a simple
       PUSHJ.  */
    HOWTO (R_MMIX_PUSHJ,		/* type */
  	 2,			/* rightshift */
--- 570,577 ----
    /* The PUSHJ instruction can reach any (code) address, as long as it's
       the beginning of a function (no usable restriction).  It can silently
       expand to a 64-bit operand, but will emit an error if any of the two
!      least significant bits are set.  It can also expand into a call to a
!      stub; see R_MMIX_PUSHJ_STUBBABLE.  The howto members reflect a simple
       PUSHJ.  */
    HOWTO (R_MMIX_PUSHJ,		/* type */
  	 2,			/* rightshift */
*************** static reloc_howto_type elf_mmix_howto_t
*** 754,759 ****
--- 787,806 ----
  	 0,			/* src_mask */
  	 0,			/* dst_mask */
  	 FALSE),		/* pcrel_offset */
+
+   HOWTO (R_MMIX_PUSHJ_STUBBABLE, /* type */
+ 	 2,			/* rightshift */
+ 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+ 	 19,			/* bitsize */
+ 	 TRUE,			/* pc_relative */
+ 	 0,			/* bitpos */
+ 	 complain_overflow_signed, /* complain_on_overflow */
+ 	 mmix_elf_reloc,	/* special_function */
+ 	 "R_MMIX_PUSHJ_STUBBABLE", /* name */
+ 	 FALSE,			/* partial_inplace */
+ 	 ~0x0100ffff,		/* src_mask */
+ 	 0x0100ffff,		/* dst_mask */
+ 	 TRUE)			/* pcrel_offset */
   };


*************** static const struct mmix_reloc_map mmix_
*** 790,796 ****
      {BFD_RELOC_MMIX_REG_OR_BYTE, R_MMIX_REG_OR_BYTE},
      {BFD_RELOC_MMIX_REG, R_MMIX_REG},
      {BFD_RELOC_MMIX_BASE_PLUS_OFFSET, R_MMIX_BASE_PLUS_OFFSET},
!     {BFD_RELOC_MMIX_LOCAL, R_MMIX_LOCAL}
    };

  static reloc_howto_type *
--- 837,844 ----
      {BFD_RELOC_MMIX_REG_OR_BYTE, R_MMIX_REG_OR_BYTE},
      {BFD_RELOC_MMIX_REG, R_MMIX_REG},
      {BFD_RELOC_MMIX_BASE_PLUS_OFFSET, R_MMIX_BASE_PLUS_OFFSET},
!     {BFD_RELOC_MMIX_LOCAL, R_MMIX_LOCAL},
!     {BFD_RELOC_MMIX_PUSHJ_STUBBABLE, R_MMIX_PUSHJ_STUBBABLE}
    };

  static reloc_howto_type *
*************** mmix_elf_perform_relocation (isec, howto
*** 880,886 ****
       asection *isec;
       reloc_howto_type *howto;
       PTR datap;
!      bfd_vma addr ATTRIBUTE_UNUSED;
       bfd_vma value;
  {
    bfd *abfd = isec->owner;
--- 928,934 ----
       asection *isec;
       reloc_howto_type *howto;
       PTR datap;
!      bfd_vma addr;
       bfd_vma value;
  {
    bfd *abfd = isec->owner;
*************** mmix_elf_perform_relocation (isec, howto
*** 931,936 ****
--- 979,1074 ----
        }
        break;

+     case R_MMIX_PUSHJ_STUBBABLE:
+       /* If the address fits, we're fine.  */
+       if ((value & 3) == 0
+ 	  /* Note rightshift 0; see R_MMIX_JMP case below.  */
+ 	  && (r = bfd_check_overflow (complain_overflow_signed,
+ 				      howto->bitsize,
+ 				      0,
+ 				      bfd_arch_bits_per_address (abfd),
+ 				      value)) == bfd_reloc_ok)
+ 	goto pcrel_mmix_reloc_fits;
+       else
+ 	{
+ 	  bfd_size_type raw_size
+ 	    = (isec->_raw_size
+ 	       - mmix_elf_section_data (isec)->pjs.n_pushj_relocs
+ 	       * MAX_PUSHJ_STUB_SIZE);
+
+ 	  /* We have the bytes at the PUSHJ insn and need to get the
+ 	     position for the stub.  There's supposed to be room allocated
+ 	     for the stub.  */
+ 	  bfd_byte *stubcontents
+ 	    = ((char *) datap
+ 	       - (addr - (isec->output_section->vma + isec->output_offset))
+ 	       + raw_size
+ 	       + mmix_elf_section_data (isec)->pjs.stub_offset);
+ 	  bfd_vma stubaddr;
+
+ 	  /* The address doesn't fit, so redirect the PUSHJ to the
+ 	     location of the stub.  */
+ 	  r = mmix_elf_perform_relocation (isec,
+ 					   &elf_mmix_howto_table
+ 					   [R_MMIX_ADDR19],
+ 					   datap,
+ 					   addr,
+ 					   isec->output_section->vma
+ 					   + isec->output_offset
+ 					   + raw_size
+ 					   + (mmix_elf_section_data (isec)
+ 					      ->pjs.stub_offset)
+ 					   - addr);
+ 	  if (r != bfd_reloc_ok)
+ 	    return r;
+
+ 	  stubaddr
+ 	    = (isec->output_section->vma
+ 	       + isec->output_offset
+ 	       + raw_size
+ 	       + mmix_elf_section_data (isec)->pjs.stub_offset);
+
+ 	  /* We generate a simple JMP if that suffices, else the whole 5
+ 	     insn stub.  */
+ 	  if (bfd_check_overflow (complain_overflow_signed,
+ 				  elf_mmix_howto_table[R_MMIX_ADDR27].bitsize,
+ 				  0,
+ 				  bfd_arch_bits_per_address (abfd),
+ 				  addr + value - stubaddr) == bfd_reloc_ok)
+ 	    {
+ 	      bfd_put_32 (abfd, JMP_INSN_BYTE << 24, stubcontents);
+ 	      r = mmix_elf_perform_relocation (isec,
+ 					       &elf_mmix_howto_table
+ 					       [R_MMIX_ADDR27],
+ 					       stubcontents,
+ 					       stubaddr,
+ 					       value + addr - stubaddr);
+ 	      mmix_elf_section_data (isec)->pjs.stub_offset += 4;
+
+ 	      if (raw_size
+ 		  + mmix_elf_section_data (isec)->pjs.stub_offset
+ 		  > isec->_cooked_size)
+ 		abort ();
+
+ 	      return r;
+ 	    }
+ 	  else
+ 	    {
+ 	      /* Put a "GO $255,0" after the common sequence.  */
+ 	      bfd_put_32 (abfd,
+ 			  ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24)
+ 			  | 0xff00, (bfd_byte *) stubcontents + 16);
+
+ 	      /* Prepare for the general code to set the first part of the
+ 		 linker stub, and */
+ 	      value += addr;
+ 	      datap = stubcontents;
+ 	      mmix_elf_section_data (isec)->pjs.stub_offset
+ 		+= MAX_PUSHJ_STUB_SIZE;
+ 	    }
+ 	}
+       break;
+
      case R_MMIX_PUSHJ:
        {
  	int inreg = bfd_get_8 (abfd, (bfd_byte *) datap + 1);
*************** mmix_elf_perform_relocation (isec, howto
*** 978,983 ****
--- 1116,1122 ----
        /* FALLTHROUGH.  */
      case R_MMIX_ADDR19:
      case R_MMIX_ADDR27:
+     pcrel_mmix_reloc_fits:
        /* These must be in range, or else we emit an error.  */
        if ((value & 3) == 0
  	  /* Note rightshift 0; see above.  */
*************** mmix_elf_perform_relocation (isec, howto
*** 993,999 ****

  	  if ((bfd_signed_vma) value < 0)
  	    {
! 	      highbit = (1 << 24);
  	      value += (1 << (howto->bitsize - 1));
  	    }
  	  else
--- 1132,1138 ----

  	  if ((bfd_signed_vma) value < 0)
  	    {
! 	      highbit = 1 << 24;
  	      value += (1 << (howto->bitsize - 1));
  	    }
  	  else
*************** mmix_elf_relocate_section (output_bfd, i
*** 1203,1208 ****
--- 1342,1352 ----
    struct elf_link_hash_entry **sym_hashes;
    Elf_Internal_Rela *rel;
    Elf_Internal_Rela *relend;
+   bfd_size_type raw_size
+     = (input_section->_raw_size
+        - mmix_elf_section_data (input_section)->pjs.n_pushj_relocs
+        * MAX_PUSHJ_STUB_SIZE);
+   size_t pjsno = 0;

    symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
    sym_hashes = elf_sym_hashes (input_bfd);
*************** mmix_elf_relocate_section (output_bfd, i
*** 1231,1240 ****

        if (info->relocatable)
  	{
! 	  /* This is a relocatable link.  We don't have to change
!              anything, unless the reloc is against a section symbol,
!              in which case we have to adjust according to where the
!              section symbol winds up in the output section.  */
  	  if (r_symndx < symtab_hdr->sh_info)
  	    {
  	      sym = local_syms + r_symndx;
--- 1375,1384 ----

        if (info->relocatable)
  	{
! 	  /* This is a relocatable link.  For most relocs we don't have to
! 	     change anything, unless the reloc is against a section
! 	     symbol, in which case we have to adjust according to where
! 	     the section symbol winds up in the output section.  */
  	  if (r_symndx < symtab_hdr->sh_info)
  	    {
  	      sym = local_syms + r_symndx;
*************** mmix_elf_relocate_section (output_bfd, i
*** 1246,1251 ****
--- 1390,1464 ----
  		}
  	    }

+ 	  /* For PUSHJ stub relocs however, we may need to change the
+ 	     reloc and the section contents, if the reloc doesn't reach
+ 	     beyond the end of the output section and previous stubs.
+ 	     Then we change the section contents to be a PUSHJ to the end
+ 	     of the input section plus stubs (we can do that without using
+ 	     a reloc), and then we change the reloc to be a R_MMIX_PUSHJ
+ 	     at the stub location.  */
+ 	  if (r_type == R_MMIX_PUSHJ_STUBBABLE)
+ 	    {
+ 	      /* We've already checked whether we need a stub; use that
+ 		 knowledge.  */
+ 	      if (mmix_elf_section_data (input_section)->pjs.stub_size[pjsno]
+ 		  != 0)
+ 		{
+ 		  Elf_Internal_Rela relcpy;
+
+ 		  if (mmix_elf_section_data (input_section)
+ 		      ->pjs.stub_size[pjsno] != MAX_PUSHJ_STUB_SIZE)
+ 		    abort ();
+
+ 		  /* There's already a PUSHJ insn there, so just fill in
+ 		     the offset bits to the stub.  */
+ 		  if (mmix_final_link_relocate (elf_mmix_howto_table
+ 						+ R_MMIX_ADDR19,
+ 						input_section,
+ 						contents,
+ 						rel->r_offset,
+ 						0,
+ 						input_section
+ 						->output_section->vma
+ 						+ input_section->output_offset
+ 						+ raw_size
+ 						+ mmix_elf_section_data (input_section)
+ 						->pjs.stub_offset,
+ 						NULL, NULL) != bfd_reloc_ok)
+ 		    return FALSE;
+
+ 		  /* Put a JMP insn at the stub; it goes with the
+ 		     R_MMIX_JMP reloc.  */
+ 		  bfd_put_32 (output_bfd, JMP_INSN_BYTE << 24,
+ 			      contents
+ 			      + raw_size
+ 			      + mmix_elf_section_data (input_section)
+ 			      ->pjs.stub_offset);
+
+ 		  /* Change the reloc to be at the stub, and to a full
+ 		     R_MMIX_JMP reloc.  */
+ 		  rel->r_info = ELF64_R_INFO (r_symndx, R_MMIX_JMP);
+ 		  rel->r_offset
+ 		    = (raw_size
+ 		       + mmix_elf_section_data (input_section)
+ 		       ->pjs.stub_offset);
+
+ 		  mmix_elf_section_data (input_section)->pjs.stub_offset
+ 		    += MAX_PUSHJ_STUB_SIZE;
+
+ 		  /* Shift this reloc to the end of the relocs to maintain
+ 		     the r_offset sorted reloc order.  */
+ 		  relcpy = *rel;
+ 		  memmove (rel, rel + 1, (char *) relend - (char *) rel);
+ 		  relend[-1] = relcpy;
+
+ 		  /* Back up one reloc, or else we'd skip the next reloc
+ 		   in turn.  */
+ 		  rel--;
+ 		}
+
+ 	      pjsno++;
+ 	    }
  	  continue;
  	}

*************** mmix_final_link_relocate (howto, input_s
*** 1383,1388 ****
--- 1596,1602 ----
    switch (howto->type)
      {
        /* All these are PC-relative.  */
+     case R_MMIX_PUSHJ_STUBBABLE:
      case R_MMIX_PUSHJ:
      case R_MMIX_CBRANCH:
      case R_MMIX_ADDR19:
*************** mmix_elf_check_common_relocs  (abfd, inf
*** 1669,1677 ****
    const Elf_Internal_Rela *rel;
    const Elf_Internal_Rela *rel_end;

-   if (info->relocatable)
-     return TRUE;
-
    /* We currently have to abuse this COFF-specific member, since there's
       no target-machine-dedicated member.  There's no alternative outside
       the bfd_link_info struct; we can't specialize a hash-table since
--- 1883,1888 ----
*************** mmix_elf_check_common_relocs  (abfd, inf
*** 1689,1694 ****
--- 1900,1909 ----
  	     the ELF dynobj for this, since the ELF bits assume lots of
  	     DSO-related stuff if that member is non-NULL.  */
  	case R_MMIX_BASE_PLUS_OFFSET:
+ 	  /* We don't do anything with this reloc for a relocatable link.  */
+ 	  if (info->relocatable)
+ 	    break;
+
  	  if (bpo_greg_owner == NULL)
  	    {
  	      bpo_greg_owner = abfd;
*************** mmix_elf_check_common_relocs  (abfd, inf
*** 1756,1768 ****
  	  gregdata->n_max_bpo_relocs++;

  	  /* We don't get another chance to set this before GC; we've not
! 	     set up set up any hook that runs before GC.  */
  	  gregdata->n_bpo_relocs
  	    = gregdata->n_max_bpo_relocs;
  	  break;
  	}
      }

    return TRUE;
  }

--- 1971,2004 ----
  	  gregdata->n_max_bpo_relocs++;

  	  /* We don't get another chance to set this before GC; we've not
! 	     set up any hook that runs before GC.  */
  	  gregdata->n_bpo_relocs
  	    = gregdata->n_max_bpo_relocs;
  	  break;
+
+ 	case R_MMIX_PUSHJ_STUBBABLE:
+ 	  mmix_elf_section_data (sec)->pjs.n_pushj_relocs++;
+ 	  break;
  	}
      }

+   /* Allocate per-reloc stub storage and initialize it to the max stub
+      size.  */
+   if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs != 0)
+     {
+       size_t i;
+
+       mmix_elf_section_data (sec)->pjs.stub_size
+ 	= bfd_alloc (abfd, mmix_elf_section_data (sec)->pjs.n_pushj_relocs
+ 		     * sizeof (mmix_elf_section_data (sec)
+ 			       ->pjs.stub_size[0]));
+       if (mmix_elf_section_data (sec)->pjs.stub_size == NULL)
+ 	return FALSE;
+
+       for (i = 0; i < mmix_elf_section_data (sec)->pjs.n_pushj_relocs; i++)
+ 	mmix_elf_section_data (sec)->pjs.stub_size[i] = MAX_PUSHJ_STUB_SIZE;
+     }
+
    return TRUE;
  }

*************** mmix_elf_check_relocs (abfd, info, sec,
*** 1780,1788 ****
    const Elf_Internal_Rela *rel;
    const Elf_Internal_Rela *rel_end;

-   if (info->relocatable)
-     return TRUE;
-
    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
    sym_hashes = elf_sym_hashes (abfd);
    sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf64_External_Sym);
--- 2016,2021 ----
*************** mmix_elf_check_relocs (abfd, info, sec,
*** 1798,1803 ****
--- 2031,2039 ----
    if (!mmix_elf_check_common_relocs (abfd, info, sec, relocs))
      return FALSE;

+   if (info->relocatable)
+     return TRUE;
+
    rel_end = relocs + sec->reloc_count;
    for (rel = relocs; rel < rel_end; rel++)
      {
*************** static asection mmix_elf_reg_section;
*** 1904,1911 ****
  static asymbol mmix_elf_reg_section_symbol;
  static asymbol *mmix_elf_reg_section_symbol_ptr;

! /* Handle the special MIPS section numbers that a symbol may use.
!    This is used for both the 32-bit and the 64-bit ABI.  */

  void
  mmix_elf_symbol_processing (abfd, asym)
--- 2140,2146 ----
  static asymbol mmix_elf_reg_section_symbol;
  static asymbol *mmix_elf_reg_section_symbol_ptr;

! /* Handle the special section numbers that a symbol may use.  */

  void
  mmix_elf_symbol_processing (abfd, asym)
*************** mmix_elf_final_link (abfd, info)
*** 2082,2092 ****
    return TRUE;
  }

  /* Initialize stuff for the linker-generated GREGs to match
     R_MMIX_BASE_PLUS_OFFSET relocs seen by the linker.  */

  bfd_boolean
! _bfd_mmix_prepare_linker_allocated_gregs (abfd, info)
       bfd *abfd ATTRIBUTE_UNUSED;
       struct bfd_link_info *info;
  {
--- 2317,2365 ----
    return TRUE;
  }

+ /* We need to include the maximum size of PUSHJ-stubs in the initial
+    section size.  This is expected to shrink during linker relaxation.
+
+    You might think that we should set *only* _cooked_size, but that won't
+    work: section contents allocation will be using _raw_size in mixed
+    format linking and not enough storage will be allocated.  FIXME: That's
+    a major bug, including the name bfd_get_section_size_before_reloc; it
+    should be bfd_get_section_size_before_relax.  The relaxation functions
+    set _cooked size.  Relaxation happens before relocation.  All functions
+    *after relaxation* should be using _cooked size.  */
+
+ static void
+ mmix_set_relaxable_size (abfd, sec, ptr)
+      bfd *abfd ATTRIBUTE_UNUSED;
+      asection *sec;
+      void *ptr;
+ {
+   struct bfd_link_info *info = ptr;
+
+   /* Make sure we only do this for section where we know we want this,
+      otherwise we might end up resetting the size of COMMONs.  */
+   if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0)
+     return;
+
+   sec->_cooked_size
+     = (sec->_raw_size
+        + mmix_elf_section_data (sec)->pjs.n_pushj_relocs
+        * MAX_PUSHJ_STUB_SIZE);
+   sec->_raw_size = sec->_cooked_size;
+
+   /* For use in relocatable link, we start with a max stubs size.  See
+      mmix_elf_relax_section.  */
+   if (info->relocatable && sec->output_section)
+     mmix_elf_section_data (sec->output_section)->pjs.stubs_size_sum
+       += (mmix_elf_section_data (sec)->pjs.n_pushj_relocs
+ 	  * MAX_PUSHJ_STUB_SIZE);
+ }
+
  /* Initialize stuff for the linker-generated GREGs to match
     R_MMIX_BASE_PLUS_OFFSET relocs seen by the linker.  */

  bfd_boolean
! _bfd_mmix_before_linker_allocation (abfd, info)
       bfd *abfd ATTRIBUTE_UNUSED;
       struct bfd_link_info *info;
  {
*************** _bfd_mmix_prepare_linker_allocated_gregs
*** 2097,2102 ****
--- 2370,2380 ----
    bfd_vma gregs_size;
    size_t i;
    size_t *bpo_reloc_indexes;
+   bfd *ibfd;
+
+   /* Set the initial size of sections.  */
+   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+     bfd_map_over_sections (ibfd, mmix_set_relaxable_size, info);

    /* The bpo_greg_owner bfd is supposed to have been set by
       mmix_elf_check_relocs when the first R_MMIX_BASE_PLUS_OFFSET is seen.
*************** _bfd_mmix_prepare_linker_allocated_gregs
*** 2160,2166 ****
     calculated at this point; we just move the contents into place here.  */

  bfd_boolean
! _bfd_mmix_finalize_linker_allocated_gregs (abfd, link_info)
       bfd *abfd ATTRIBUTE_UNUSED;
       struct bfd_link_info *link_info;
  {
--- 2438,2444 ----
     calculated at this point; we just move the contents into place here.  */

  bfd_boolean
! _bfd_mmix_after_linker_allocation (abfd, link_info)
       bfd *abfd ATTRIBUTE_UNUSED;
       struct bfd_link_info *link_info;
  {
*************** mmix_dump_bpo_gregs (link_info, pf)
*** 2324,2329 ****
--- 2602,2609 ----
     from the first allocated register number) and offsets for use in real
     relocation.

+    PUSHJ stub accounting is also done here.
+
     Symbol- and reloc-reading infrastructure copied from elf-m10200.c.  */

  static bfd_boolean
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2340,2376 ****
    struct bpo_greg_section_info *gregdata;
    struct bpo_reloc_section_info *bpodata
      = mmix_elf_section_data (sec)->bpo.reloc;
!   size_t bpono;
    bfd *bpo_greg_owner;
    Elf_Internal_Sym *isymbuf = NULL;

    /* Assume nothing changes.  */
    *again = FALSE;

    /* If this is the first time we have been called for this section,
       initialize the cooked size.  */
!   if (sec->_cooked_size == 0)
!     sec->_cooked_size = sec->_raw_size;

!   /* We don't have to do anything for a relocatable link, if
!      this section does not have relocs, or if this is not a
!      code section.  */
!   if (link_info->relocatable
!       || (sec->flags & SEC_RELOC) == 0
        || sec->reloc_count == 0
        || (sec->flags & SEC_CODE) == 0
        || (sec->flags & SEC_LINKER_CREATED) != 0
!       /* If no R_MMIX_BASE_PLUS_OFFSET relocs, then nothing to do.  */
!       || bpodata == NULL)
      return TRUE;

    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;

    bpo_greg_owner = (bfd *) link_info->base_file;
-   bpo_gregs_section = bpodata->bpo_greg_section;
-   gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;

!   bpono = bpodata->first_base_plus_offset_reloc;

    /* Get a copy of the native relocations.  */
    internal_relocs
--- 2620,2670 ----
    struct bpo_greg_section_info *gregdata;
    struct bpo_reloc_section_info *bpodata
      = mmix_elf_section_data (sec)->bpo.reloc;
!   /* The initialization is to quiet compiler warnings.  The value is to
!      spot a missing actual initialization.  */
!   size_t bpono = (size_t) -1;
!   size_t pjsno = 0;
    bfd *bpo_greg_owner;
    Elf_Internal_Sym *isymbuf = NULL;
+   bfd_size_type raw_size
+     = (sec->_raw_size
+        - mmix_elf_section_data (sec)->pjs.n_pushj_relocs
+        * MAX_PUSHJ_STUB_SIZE);
+
+   mmix_elf_section_data (sec)->pjs.stubs_size_sum = 0;

    /* Assume nothing changes.  */
    *again = FALSE;

    /* If this is the first time we have been called for this section,
       initialize the cooked size.  */
!   if (sec->_cooked_size == 0 && sec->_raw_size != 0)
!     abort ();

!   /* We don't have to do anything if this section does not have relocs, or
!      if this is not a code section.  */
!   if ((sec->flags & SEC_RELOC) == 0
        || sec->reloc_count == 0
        || (sec->flags & SEC_CODE) == 0
        || (sec->flags & SEC_LINKER_CREATED) != 0
!       /* If no R_MMIX_BASE_PLUS_OFFSET relocs and no PUSHJ-stub relocs,
!          then nothing to do.  */
!       || (bpodata == NULL
! 	  && mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0))
      return TRUE;

    symtab_hdr = &elf_tdata (abfd)->symtab_hdr;

    bpo_greg_owner = (bfd *) link_info->base_file;

!   if (bpodata != NULL)
!     {
!       bpo_gregs_section = bpodata->bpo_greg_section;
!       gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
!       bpono = bpodata->first_base_plus_offset_reloc;
!     }
!   else
!     gregdata = NULL;

    /* Get a copy of the native relocations.  */
    internal_relocs
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2385,2394 ****
    for (irel = internal_relocs; irel < irelend; irel++)
      {
        bfd_vma symval;

!       if (ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_BASE_PLUS_OFFSET)
  	continue;

        /* Get the value of the symbol referred to by the reloc.  */
        if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
  	{
--- 2679,2739 ----
    for (irel = internal_relocs; irel < irelend; irel++)
      {
        bfd_vma symval;
+       struct elf_link_hash_entry *h = NULL;

!       /* We only process two relocs.  */
!       if (ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_BASE_PLUS_OFFSET
! 	  && ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_PUSHJ_STUBBABLE)
  	continue;

+       /* We process relocs in a distinctly different way when this is a
+ 	 relocatable link (for one, we don't look at symbols), so we avoid
+ 	 mixing its code with that for the "normal" relaxation.  */
+       if (link_info->relocatable)
+ 	{
+ 	  /* The only transformation in a relocatable link is to generate
+ 	     a full stub at the location of the stub calculated for the
+ 	     input section, if the relocated stub location, the end of the
+ 	     output section plus earlier stubs, cannot be reached.  Thus
+ 	     relocatable linking can only lead to worse code, but it still
+ 	     works.  */
+ 	  if (ELF64_R_TYPE (irel->r_info) == R_MMIX_PUSHJ_STUBBABLE)
+ 	    {
+ 	      /* If we can reach the end of the output-section and beyond
+ 		 any current stubs, then we don't need a stub for this
+ 		 reloc.  The relaxed order of output stub allocation may
+ 		 not exactly match the straightforward order, so we always
+ 		 assume presence of output stubs, which will allow
+ 		 relaxation only on relocations indifferent to the
+ 		 presence of output stub allocations for other relocations
+ 		 and thus the order of output stub allocation.  */
+ 	      if (bfd_check_overflow (complain_overflow_signed,
+ 				      19,
+ 				      0,
+ 				      bfd_arch_bits_per_address (abfd),
+ 				      /* Output-stub location.  */
+ 				      sec->output_section->_cooked_size
+ 				      + (mmix_elf_section_data (sec
+ 							       ->output_section)
+ 					 ->pjs.stubs_size_sum)
+ 				      /* Location of this PUSHJ reloc.  */
+ 				      - (sec->output_offset + irel->r_offset)
+ 				      /* Don't count *this* stub twice.  */
+ 				      - (mmix_elf_section_data (sec)
+ 					 ->pjs.stub_size[pjsno]
+ 					 + MAX_PUSHJ_STUB_SIZE))
+ 		  == bfd_reloc_ok)
+ 		mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0;
+
+ 	      mmix_elf_section_data (sec)->pjs.stubs_size_sum
+ 		+= mmix_elf_section_data (sec)->pjs.stub_size[pjsno];
+
+ 	      pjsno++;
+ 	    }
+
+ 	  continue;
+ 	}
+
        /* Get the value of the symbol referred to by the reloc.  */
        if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
  	{
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2424,2430 ****
        else
  	{
  	  unsigned long indx;
- 	  struct elf_link_hash_entry *h;

  	  /* An external symbol.  */
  	  indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info;
--- 2769,2774 ----
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2433,2444 ****
  	  if (h->root.type != bfd_link_hash_defined
  	      && h->root.type != bfd_link_hash_defweak)
  	    {
! 	      /* This appears to be a reference to an undefined symbol.
! 		 Just ignore it--it will be caught by the regular reloc
! 		 processing.  We need to keep BPO reloc accounting
! 		 consistent, though.  */
! 	      gregdata->n_remaining_bpo_relocs_this_relaxation_round--;
! 	      bpono++;
  	      continue;
  	    }

--- 2777,2792 ----
  	  if (h->root.type != bfd_link_hash_defined
  	      && h->root.type != bfd_link_hash_defweak)
  	    {
! 	      /* This appears to be a reference to an undefined symbol.  Just
! 		 ignore it--it will be caught by the regular reloc processing.
! 		 We need to keep BPO reloc accounting consistent, though
! 		 else we'll abort instead of emitting an error message.  */
! 	      if (ELF64_R_TYPE (irel->r_info) == R_MMIX_BASE_PLUS_OFFSET
! 		  && gregdata != NULL)
! 		{
! 		  gregdata->n_remaining_bpo_relocs_this_relaxation_round--;
! 		  bpono++;
! 		}
  	      continue;
  	    }

*************** mmix_elf_relax_section (abfd, sec, link_
*** 2447,2452 ****
--- 2795,2856 ----
  		    + h->root.u.def.section->output_offset);
  	}

+       if (ELF64_R_TYPE (irel->r_info) == (int) R_MMIX_PUSHJ_STUBBABLE)
+ 	{
+ 	  bfd_vma value = symval + irel->r_addend;
+ 	  bfd_vma dot
+ 	    = (sec->output_section->vma
+ 	       + sec->output_offset
+ 	       + irel->r_offset);
+ 	  bfd_vma stubaddr
+ 	    = (sec->output_section->vma
+ 	       + sec->output_offset
+ 	       + raw_size
+ 	       + mmix_elf_section_data (sec)->pjs.stubs_size_sum);
+
+ 	  if ((value & 3) == 0
+ 	      && bfd_check_overflow (complain_overflow_signed,
+ 				     19,
+ 				     0,
+ 				     bfd_arch_bits_per_address (abfd),
+ 				     value - dot
+ 				     - (value > dot
+ 					? mmix_elf_section_data (sec)
+ 					->pjs.stub_size[pjsno]
+ 					: 0))
+ 	      == bfd_reloc_ok)
+ 	    /* If the reloc fits, no stub is needed.  */
+ 	    mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0;
+ 	  else
+ 	    /* Maybe we can get away with just a JMP insn?  */
+ 	    if ((value & 3) == 0
+ 		&& bfd_check_overflow (complain_overflow_signed,
+ 				       27,
+ 				       0,
+ 				       bfd_arch_bits_per_address (abfd),
+ 				       value - stubaddr
+ 				       - (value > dot
+ 					  ? mmix_elf_section_data (sec)
+ 					  ->pjs.stub_size[pjsno] - 4
+ 					  : 0))
+ 		== bfd_reloc_ok)
+ 	      /* Yep, account for a stub consisting of a single JMP insn.  */
+ 	      mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 4;
+ 	  else
+ 	    /* Nope, go for the full insn stub.  It doesn't seem useful to
+ 	       emit the intermediate sizes; those will only be useful for
+ 	       a >64M program assuming contiguous code.  */
+ 	    mmix_elf_section_data (sec)->pjs.stub_size[pjsno]
+ 	      = MAX_PUSHJ_STUB_SIZE;
+
+ 	  mmix_elf_section_data (sec)->pjs.stubs_size_sum
+ 	    += mmix_elf_section_data (sec)->pjs.stub_size[pjsno];
+ 	  pjsno++;
+ 	  continue;
+ 	}
+
+       /* We're looking at a R_MMIX_BASE_PLUS_OFFSET reloc.  */
+
        gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono]].value
  	= symval + irel->r_addend;
        gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono++]].valid = TRUE;
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2457,2463 ****
       calculate how many registers we need to cover them.  Set the size of
       the linker gregs, and if the number of registers changed, indicate
       that we need to relax some more because we have more work to do.  */
!   if (gregdata->n_remaining_bpo_relocs_this_relaxation_round == 0)
      {
        size_t i;
        bfd_vma prev_base;
--- 2861,2868 ----
       calculate how many registers we need to cover them.  Set the size of
       the linker gregs, and if the number of registers changed, indicate
       that we need to relax some more because we have more work to do.  */
!   if (gregdata != NULL
!       && gregdata->n_remaining_bpo_relocs_this_relaxation_round == 0)
      {
        size_t i;
        bfd_vma prev_base;
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2529,2534 ****
--- 2934,2951 ----
        && elf_section_data (sec)->relocs != internal_relocs)
      free (internal_relocs);

+   if (sec->_cooked_size
+       < raw_size + mmix_elf_section_data (sec)->pjs.stubs_size_sum)
+     abort ();
+
+   if (sec->_cooked_size
+       > raw_size + mmix_elf_section_data (sec)->pjs.stubs_size_sum)
+     {
+       sec->_cooked_size
+ 	= raw_size + mmix_elf_section_data (sec)->pjs.stubs_size_sum;
+       *again = TRUE;
+     }
+
    return TRUE;

   error_return:
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2539,2544 ****
--- 2956,3008 ----
      free (internal_relocs);
    return FALSE;
  }
+
+ /* Because we set _raw_size to include the max size of pushj stubs,
+    i.e. larger than the actual section input size (see
+    mmix_set_relaxable_raw_size), we have to take care of that when reading
+    the section.  */
+
+ static bfd_boolean
+ mmix_elf_get_section_contents (abfd, section, location, offset, count)
+      bfd *abfd;
+      sec_ptr section;
+      void *location;
+      file_ptr offset;
+      bfd_size_type count;
+ {
+   bfd_size_type raw_size
+     = (section->_raw_size
+        - mmix_elf_section_data (section)->pjs.n_pushj_relocs
+        * MAX_PUSHJ_STUB_SIZE);
+
+   if (offset + count > section->_raw_size)
+     {
+       abort();
+       bfd_set_error (bfd_error_invalid_operation);
+       return FALSE;
+     }
+
+   /* Check bounds against the faked raw_size.  */
+   if (offset + count > raw_size)
+     {
+       /* Clear the part in the faked area.  */
+       memset (location + raw_size - offset, 0, count - (raw_size - offset));
+
+       /* If there's no initial part within the "real" contents, we're
+          done.  */
+       if ((bfd_size_type) offset >= raw_size)
+ 	return TRUE;
+
+       /* Else adjust the count and fall through to call the generic
+          function.  */
+       count = raw_size - offset;
+     }
+
+   return
+     _bfd_generic_get_section_contents (abfd, section, location, offset,
+ 				       count);
+ }
+

  #define ELF_ARCH		bfd_arch_mmix
  #define ELF_MACHINE_CODE 	EM_MMIX
*************** mmix_elf_relax_section (abfd, sec, link_
*** 2587,2591 ****
--- 3051,3056 ----
  #define bfd_elf64_new_section_hook	mmix_elf_new_section_hook
  #define bfd_elf64_bfd_final_link	mmix_elf_final_link
  #define bfd_elf64_bfd_relax_section	mmix_elf_relax_section
+ #define bfd_elf64_get_section_contents	mmix_elf_get_section_contents

  #include "elf64-target.h"
Index: libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.95
diff -p -c -r1.95 libbfd.h
*** libbfd.h	16 Oct 2003 04:11:06 -0000	1.95
--- libbfd.h	18 Oct 2003 00:44:12 -0000
*************** static const char *const bfd_reloc_code_
*** 1222,1227 ****
--- 1222,1228 ----
    "BFD_RELOC_MMIX_PUSHJ_1",
    "BFD_RELOC_MMIX_PUSHJ_2",
    "BFD_RELOC_MMIX_PUSHJ_3",
+   "BFD_RELOC_MMIX_PUSHJ_STUBBABLE",
    "BFD_RELOC_MMIX_JMP",
    "BFD_RELOC_MMIX_JMP_1",
    "BFD_RELOC_MMIX_JMP_2",
Index: bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.241
diff -p -c -r1.241 bfd-in2.h
*** bfd-in2.h	16 Oct 2003 04:11:04 -0000	1.241
--- bfd-in2.h	18 Oct 2003 00:44:11 -0000
*************** short offset into 11 bits.  */
*** 2955,2960 ****
--- 2955,2961 ----
    BFD_RELOC_MMIX_PUSHJ_1,
    BFD_RELOC_MMIX_PUSHJ_2,
    BFD_RELOC_MMIX_PUSHJ_3,
+   BFD_RELOC_MMIX_PUSHJ_STUBBABLE,

  /* These are relocations for the JMP instruction.  */
    BFD_RELOC_MMIX_JMP,
Index: mmix.h
===================================================================
RCS file: /cvs/src/src/include/elf/mmix.h,v
retrieving revision 1.4
diff -p -c -r1.4 mmix.h
*** mmix.h	29 Jun 2003 13:51:25 -0000	1.4
--- mmix.h	18 Oct 2003 00:36:15 -0000
*************** Foundation, Inc., 59 Temple Place - Suit
*** 23,29 ****

  #include "elf/reloc-macros.h"

! /* Relocations.  */
  START_RELOC_NUMBERS (elf_mmix_reloc_type)
    RELOC_NUMBER (R_MMIX_NONE, 0)

--- 23,29 ----

  #include "elf/reloc-macros.h"

! /* Relocations.  See the reloc table in bfd/elf64-mmix.c for details.  */
  START_RELOC_NUMBERS (elf_mmix_reloc_type)
    RELOC_NUMBER (R_MMIX_NONE, 0)

*************** START_RELOC_NUMBERS (elf_mmix_reloc_type
*** 90,95 ****
--- 90,98 ----

    /* A LOCAL assertion.  */
    RELOC_NUMBER (R_MMIX_LOCAL, 35)
+
+   /* A PUSHJ instruction, generating a stub if it does not reach.  */
+   RELOC_NUMBER (R_MMIX_PUSHJ_STUBBABLE, 36)
  END_RELOC_NUMBERS (R_MMIX_max)


*************** END_RELOC_NUMBERS (R_MMIX_max)
*** 157,165 ****
  #define MMO_SEC_DEBUGGING 0x10000

  #ifdef BFD_ARCH_SIZE
! extern bfd_boolean _bfd_mmix_prepare_linker_allocated_gregs
    (bfd *, struct bfd_link_info *);
! extern bfd_boolean _bfd_mmix_finalize_linker_allocated_gregs
    (bfd *, struct bfd_link_info *);
  extern bfd_boolean _bfd_mmix_check_all_relocs
    (bfd *, struct bfd_link_info *);
--- 160,168 ----
  #define MMO_SEC_DEBUGGING 0x10000

  #ifdef BFD_ARCH_SIZE
! extern bfd_boolean _bfd_mmix_before_linker_allocation
    (bfd *, struct bfd_link_info *);
! extern bfd_boolean _bfd_mmix_after_linker_allocation
    (bfd *, struct bfd_link_info *);
  extern bfd_boolean _bfd_mmix_check_all_relocs
    (bfd *, struct bfd_link_info *);
Index: emultempl/mmix-elfnmmo.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/mmix-elfnmmo.em,v
retrieving revision 1.9
diff -p -c -r1.9 mmix-elfnmmo.em
*** emultempl/mmix-elfnmmo.em	27 Jun 2003 00:38:25 -0000	1.9
--- emultempl/mmix-elfnmmo.em	18 Oct 2003 00:38:49 -0000
*************** mmix_before_allocation (void)
*** 38,48 ****
       maintenance burden to keep them in sync.  (Of course we lose the
       maintenance burden of checking that it still does what we need.)  */

!   /* Force -relax on if not doing a relocatable link.  */
!   if (! link_info.relocatable)
!     command_line.relax = TRUE;

!   if (!_bfd_mmix_prepare_linker_allocated_gregs (output_bfd, &link_info))
      einfo ("%X%P: Internal problems setting up section %s",
  	   MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
  }
--- 38,48 ----
       maintenance burden to keep them in sync.  (Of course we lose the
       maintenance burden of checking that it still does what we need.)  */

!   /* Force -relax on (regardless of whether we're doing a relocatable
!      link).  */
!   command_line.relax = TRUE;

!   if (!_bfd_mmix_before_linker_allocation (output_bfd, &link_info))
      einfo ("%X%P: Internal problems setting up section %s",
  	   MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
  }
*************** mmix_after_allocation (void)
*** 109,115 ****
    if (sec != NULL)
      bfd_set_section_vma (abfd, sec, 0);

!   if (!_bfd_mmix_finalize_linker_allocated_gregs (output_bfd, &link_info))
      {
        /* This is a fatal error; make einfo call not return.  */
        einfo ("%F%P: Can't finalize linker-allocated global registers\n");
--- 109,115 ----
    if (sec != NULL)
      bfd_set_section_vma (abfd, sec, 0);

!   if (!_bfd_mmix_after_linker_allocation (output_bfd, &link_info))
      {
        /* This is a fatal error; make einfo call not return.  */
        einfo ("%F%P: Can't finalize linker-allocated global registers\n");
Index: scripttempl/mmo.sc
===================================================================
RCS file: /cvs/src/src/ld/scripttempl/mmo.sc,v
retrieving revision 1.4
diff -p -c -r1.4 mmo.sc
*** scripttempl/mmo.sc	14 Apr 2003 13:03:17 -0000	1.4
--- scripttempl/mmo.sc	18 Oct 2003 00:38:49 -0000
*************** SECTIONS
*** 55,61 ****
      ${RELOCATING+ PROVIDE(_etext = .);}
      ${RELOCATING+ PROVIDE(__etext = .);}
    }
!   ${RELOCATING+Main = DEFINED (Main) ? Main : (DEFINED (_start) ? _start : . - SIZEOF (.text));}

    .stab 0 : { *(.stab) }
    .stabstr 0 : { *(.stabstr) }
--- 55,61 ----
      ${RELOCATING+ PROVIDE(_etext = .);}
      ${RELOCATING+ PROVIDE(__etext = .);}
    }
!   ${RELOCATING+Main = DEFINED (Main) ? Main : (DEFINED (_start) ? _start : ADDR (.text));}

    .stab 0 : { *(.stab) }
    .stabstr 0 : { *(.stabstr) }
Index: testsuite/ld-mmix/greg-14.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mmix/greg-14.d,v
retrieving revision 1.1
diff -p -c -r1.1 greg-14.d
*** testsuite/ld-mmix/greg-14.d	30 Oct 2001 15:20:14 -0000	1.1
--- testsuite/ld-mmix/greg-14.d	18 Oct 2003 00:38:50 -0000
***************
*** 2,8 ****
  #source: gregpsj1.s
  #source: start.s
  #source: a.s
! #as: -x
  #ld: -m mmo
  #objdump: -dt

--- 2,8 ----
  #source: gregpsj1.s
  #source: start.s
  #source: a.s
! #as: -x --no-pushj-stubs
  #ld: -m mmo
  #objdump: -dt

Index: testsuite/ld-mmix/greg-5.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mmix/greg-5.d,v
retrieving revision 1.2
diff -p -c -r1.2 greg-5.d
*** testsuite/ld-mmix/greg-5.d	19 Mar 2002 22:48:14 -0000	1.2
--- testsuite/ld-mmix/greg-5.d	18 Oct 2003 00:38:50 -0000
***************
*** 2,8 ****
  #source: gregpsj1.s
  #source: start.s
  #source: a.s
! #as: -x
  #ld: -m elf64mmix
  #objdump: -dt

--- 2,8 ----
  #source: gregpsj1.s
  #source: start.s
  #source: a.s
! #as: -x --no-pushj-stubs
  #ld: -m elf64mmix
  #objdump: -dt

Index: testsuite/ld-mmix/pushja1b.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mmix/pushja1b.d,v
retrieving revision 1.1
diff -p -c -r1.1 pushja1b.d
*** testsuite/ld-mmix/pushja1b.d	30 Oct 2001 15:20:14 -0000	1.1
--- testsuite/ld-mmix/pushja1b.d	18 Oct 2003 00:38:50 -0000
***************
*** 1,7 ****
  #source: start.s
  #source: a.s
  #source: pushja.s
! #as: -x
  #ld: -m elf64mmix
  #objdump: -dr

--- 1,7 ----
  #source: start.s
  #source: a.s
  #source: pushja.s
! #as: -x --no-pushj-stubs
  #ld: -m elf64mmix
  #objdump: -dr

Index: testsuite/ld-mmix/pushja1f.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mmix/pushja1f.d,v
retrieving revision 1.1
diff -p -c -r1.1 pushja1f.d
*** testsuite/ld-mmix/pushja1f.d	30 Oct 2001 15:20:14 -0000	1.1
--- testsuite/ld-mmix/pushja1f.d	18 Oct 2003 00:38:50 -0000
***************
*** 1,7 ****
  #source: start.s
  #source: pushja.s
  #source: a.s
! #as: -x
  #ld: -m elf64mmix
  #objdump: -dr

--- 1,7 ----
  #source: start.s
  #source: pushja.s
  #source: a.s
! #as: -x --no-pushj-stubs
  #ld: -m elf64mmix
  #objdump: -dr

Index: testsuite/ld-mmix/pushja7b.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mmix/pushja7b.d,v
retrieving revision 1.1
diff -p -c -r1.1 pushja7b.d
*** testsuite/ld-mmix/pushja7b.d	30 Oct 2001 15:20:14 -0000	1.1
--- testsuite/ld-mmix/pushja7b.d	18 Oct 2003 00:38:50 -0000
***************
*** 1,7 ****
  #source: start.s
  #source: a.s
  #source: pushja.s
! #as: -x
  #ld: -m mmo
  #objdump: -dr

--- 1,7 ----
  #source: start.s
  #source: a.s
  #source: pushja.s
! #as: -x --no-pushj-stubs
  #ld: -m mmo
  #objdump: -dr

Index: testsuite/ld-mmix/pushja7f.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-mmix/pushja7f.d,v
retrieving revision 1.1
diff -p -c -r1.1 pushja7f.d
*** testsuite/ld-mmix/pushja7f.d	30 Oct 2001 15:20:14 -0000	1.1
--- testsuite/ld-mmix/pushja7f.d	18 Oct 2003 00:38:50 -0000
***************
*** 1,7 ****
  #source: start.s
  #source: pushja.s
  #source: a.s
! #as: -x
  #ld: -m mmo
  #objdump: -dr

--- 1,7 ----
  #source: start.s
  #source: pushja.s
  #source: a.s
! #as: -x --no-pushj-stubs
  #ld: -m mmo
  #objdump: -dr

--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs2b.d	Sat Oct 18 04:37:29 2003
@@ -0,0 +1,33 @@
+#source: start4.s
+#source: nop123.s
+#source: a.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: pad4.s
+#source: pushja.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside the offset range gets a JMP
+# stub expansion, backwards, ELF version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <a-0x4>:
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+40008 <pushja>:
+   40008:	e3fd0002 	setl \$253,0x2
+   4000c:	f20c0002 	pushj \$12,40014 <pushja\+0xc>
+   40010:	e3fd0003 	setl \$253,0x3
+   40014:	f1fefffd 	jmp 8 <a>
+0+40018 <_start>:
+   40018:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/greg-14s.d	Sat Oct 18 04:54:55 2003
@@ -0,0 +1,23 @@
+#source: greg-1.s
+#source: gregpsj1.s
+#source: start.s
+#source: a.s
+#as: -x
+#ld: -m mmo
+#objdump: -dt
+
+# Like greg-14, but using PUSHJ stubs.
+
+.*:     file format mmo
+SYMBOL TABLE:
+0+4 g       \.text Main
+0+4 g       \.text _start
+0+fe g       \*REG\* areg
+0+8 g       \.text a
+Disassembly of section \.text:
+0+ <(Main|_start)-0x4>:
+   0:	f2fe0002 	pushj areg,8 <a>
+0+4 <(Main|_start)>:
+   4:	e3fd0001 	setl \$253,0x1
+0+8 <a>:
+   8:	e3fd0004 	setl \$253,0x4
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs1.d	Sat Oct 18 04:35:18 2003
@@ -0,0 +1,27 @@
+#source: start4.s
+#source: pushja.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just within the offset range gets no
+# stub expansion, ELF version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20cffff 	pushj \$12,40004 <a>
+       c:	e3fd0003 	setl \$253,0x3
+	\.\.\.
+0+40004 <a>:
+   40004:	e3fd0004 	setl \$253,0x4
+0+40008 <_start>:
+   40008:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/greg-5s.d	Sat Oct 18 04:54:49 2003
@@ -0,0 +1,31 @@
+#source: greg-1.s
+#source: gregpsj1.s
+#source: start.s
+#source: a.s
+#as: -x
+#ld: -m elf64mmix
+#objdump: -dt
+
+# Like greg-3, but a different expanding insn.
+
+.*:     file format elf64-mmix
+SYMBOL TABLE:
+0+ l    d  .text	0+
+2000000000000000 l    d  .data	0+
+2000000000000000 l    d  .sbss	0+
+2000000000000000 l    d  .bss	0+
+0+7f0 l    d  \.MMIX\.reg_contents	0+
+0+ l    d  \*ABS\*	0+
+0+ l    d  \*ABS\*	0+
+0+ l    d  \*ABS\*	0+
+0+4 g       \.text	0+ _start
+0+fe g       \*REG\*	0+ areg
+#...
+0+8 g       \.text	0+ a
+Disassembly of section \.text:
+0+ <_start-0x4>:
+   0:	f2fe0002 	pushj \$254,8 <a>
+0+4 <_start>:
+   4:	e3fd0001 	setl \$253,0x1
+0+8 <a>:
+   8:	e3fd0004 	setl \$253,0x4
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs3b.d	Sat Oct 18 04:36:46 2003
@@ -0,0 +1,30 @@
+#source: start4.s
+#source: nop123.s
+#source: a.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pushja.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just inside the offset range of a JMP
+# stub expansion works, backwards, ELF version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <a-0x4>:
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+3fffffc <pushja>:
+ 3fffffc:	e3fd0002 	setl \$253,0x2
+ 4000000:	f20c0002 	pushj \$12,4000008 <pushja\+0xc>
+ 4000004:	e3fd0003 	setl \$253,0x3
+ 4000008:	f1000000 	jmp 8 <a>
+0+400000c <_start>:
+ 400000c:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushja1f-s.d	Sat Oct 18 04:56:00 2003
@@ -0,0 +1,19 @@
+#source: start.s
+#source: pushja.s
+#source: a.s
+#as: -x
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Like pushja1f, but with PUSHJ stub.
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0+ <_start>:
+   0:	e3fd0001 	setl \$253,0x1
+0+4 <pushja>:
+   4:	e3fd0002 	setl \$253,0x2
+   8:	f20c0002 	pushj \$12,10 <a>
+   c:	e3fd0003 	setl \$253,0x3
+0+10 <a>:
+  10:	e3fd0004 	setl \$253,0x4
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs1m.d	Sat Oct 18 04:38:24 2003
@@ -0,0 +1,26 @@
+#source: nop123.s
+#source: pushja.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just within the offset range gets no
+# stub expansion, mmo version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20cffff 	pushj \$12,40004 <a>
+       c:	e3fd0003 	setl \$253,0x3
+	\.\.\.
+0+40004 <a>:
+   40004:	e3fd0004 	setl \$253,0x4
+0+40008 <Main>:
+   40008:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushja7b-s.d	Sat Oct 18 04:56:07 2003
@@ -0,0 +1,19 @@
+#source: start.s
+#source: a.s
+#source: pushja.s
+#as: -x
+#ld: -m mmo
+#objdump: -dr
+
+# Like pushja7b, but with PUSHJ stub.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <(Main|_start)>:
+   0:	e3fd0001 	setl \$253,0x1
+0+4 <a>:
+   4:	e3fd0004 	setl \$253,0x4
+0+8 <pushja>:
+   8:	e3fd0002 	setl \$253,0x2
+   c:	f30cfffe 	pushj \$12,4 <a>
+  10:	e3fd0003 	setl \$253,0x3
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushja7f-s.d	Sat Oct 18 04:56:13 2003
@@ -0,0 +1,19 @@
+#source: start.s
+#source: pushja.s
+#source: a.s
+#as: -x
+#ld: -m mmo
+#objdump: -dr
+
+# Like pushja7f, but with PUSHJ stub.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <(Main|_start)>:
+   0:	e3fd0001 	setl \$253,0x1
+0+4 <pushja>:
+   4:	e3fd0002 	setl \$253,0x2
+   8:	f20c0002 	pushj \$12,10 <a>
+   c:	e3fd0003 	setl \$253,0x3
+0+10 <a>:
+  10:	e3fd0004 	setl \$253,0x4
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushja1b-s.d	Sat Oct 18 04:56:19 2003
@@ -0,0 +1,19 @@
+#source: start.s
+#source: a.s
+#source: pushja.s
+#as: -x
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Like pushja1b but with PUSHJ stub.
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0+ <_start>:
+   0:	e3fd0001 	setl \$253,0x1
+0+4 <a>:
+   4:	e3fd0004 	setl \$253,0x4
+0+8 <pushja>:
+   8:	e3fd0002 	setl \$253,0x2
+   c:	f30cfffe 	pushj \$12,4 <a>
+  10:	e3fd0003 	setl \$253,0x3
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs2.d	Sat Oct 18 04:55:42 2003
@@ -0,0 +1,29 @@
+#source: start4.s
+#source: pushja.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside the PUSHJ offset range gets
+# a JMP stub expansion, ELF version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	f000ffff 	jmp 4000c <a>
+	\.\.\.
+0+4000c <a>:
+   4000c:	e3fd0004 	setl \$253,0x4
+0+40010 <_start>:
+   40010:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs3.d	Sat Oct 18 04:44:45 2003
@@ -0,0 +1,29 @@
+#source: start4.s
+#source: pushja.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just within reach of JMP gets it, ELF
+# version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	f0ffffff 	jmp 400000c <a>
+	\.\.\.
+0+400000c <a>:
+ 400000c:	e3fd0004 	setl \$253,0x4
+0+4000010 <_start>:
+ 4000010:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs4b.d	Sat Oct 18 04:45:38 2003
@@ -0,0 +1,35 @@
+#source: start4.s
+#source: nop123.s
+#source: a.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pushja.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside the offset range of a JMP
+# stub expansion works, backwards, ELF version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <a-0x4>:
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+4000000 <pushja>:
+ 4000000:	e3fd0002 	setl \$253,0x2
+ 4000004:	f20c0002 	pushj \$12,400000c <pushja\+0xc>
+ 4000008:	e3fd0003 	setl \$253,0x3
+ 400000c:	e3ff0008 	setl \$255,0x8
+ 4000010:	e6ff0000 	incml \$255,0x0
+ 4000014:	e5ff0000 	incmh \$255,0x0
+ 4000018:	e4ff0000 	inch \$255,0x0
+ 400001c:	9f00ff00 	go \$0,\$255,0
+0+4000020 <_start>:
+ 4000020:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs4.d	Sat Oct 18 04:46:26 2003
@@ -0,0 +1,34 @@
+#source: start4.s
+#source: pushja.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside reach of JMP works; it will
+# get the full expansion, ELF version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	e3ff0020 	setl \$255,0x20
+      14:	e6ff0400 	incml \$255,0x400
+      18:	e5ff0000 	incmh \$255,0x0
+      1c:	e4ff0000 	inch \$255,0x0
+      20:	9f00ff00 	go \$0,\$255,0
+	\.\.\.
+0+4000020 <a>:
+ 4000020:	e3fd0004 	setl \$253,0x4
+0+4000024 <_start>:
+ 4000024:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs1bm.d	Sat Oct 18 04:56:52 2003
@@ -0,0 +1,29 @@
+#source: nop123.s
+#source: nop123.s
+#source: a.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: pushja.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just within the offset range gets no
+# stub expansion, backwards, mmo version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <a-0x8>:
+       0:	fd010203 	swym 1,2,3
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+40004 <pushja>:
+   40004:	e3fd0002 	setl \$253,0x2
+   40008:	f30c0000 	pushj \$12,8 <a>
+   4000c:	e3fd0003 	setl \$253,0x3
+0+40010 <Main>:
+   40010:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs1b.d	Sat Oct 18 04:56:58 2003
@@ -0,0 +1,31 @@
+#source: start4.s
+#source: nop123.s
+#source: a.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: pushja.s
+#source: start.s
+#ld: -m elf64mmix
+#objdump: -dr
+
+# Check that PUSHJ with an offset just within the offset range gets no
+# stub expansion, backwards, ELF version.
+
+.*:     file format elf64-mmix
+Disassembly of section \.init:
+0+ <_start>:
+   0:	e37704a6 	setl \$119,0x4a6
+Disassembly of section \.text:
+0+4 <a-0x4>:
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+40004 <pushja>:
+   40004:	e3fd0002 	setl \$253,0x2
+   40008:	f30c0000 	pushj \$12,8 <a>
+   4000c:	e3fd0003 	setl \$253,0x3
+0+40010 <_start>:
+   40010:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs2m.d	Sat Oct 18 04:56:24 2003
@@ -0,0 +1,28 @@
+#source: nop123.s
+#source: pushja.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside the PUSHJ offset range gets
+# a JMP stub expansion, mmo version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	f000ffff 	jmp 4000c <a>
+	\.\.\.
+0+4000c <a>:
+   4000c:	e3fd0004 	setl \$253,0x4
+0+40010 <Main>:
+   40010:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs1r.d	Sat Oct 18 04:55:11 2003
@@ -0,0 +1,22 @@
+#source: nop123.s
+#source: pushja.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: nop123.s
+#ld: -r -m elf64mmix
+#objdump: -dr
+
+# When linking relocatable, check that PUSHJ with a distance to the end of
+# the section just within the offset range gets no stub expansion.
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0000 	pushj \$12,8 <pushja\+0x4>
+			8: R_MMIX_PUSHJ_STUBBABLE	a
+       c:	e3fd0003 	setl \$253,0x3
+	\.\.\.
+   40000:	fd010203 	swym 1,2,3
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs3m.d	Sat Oct 18 04:45:23 2003
@@ -0,0 +1,28 @@
+#source: nop123.s
+#source: pushja.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just within reach of JMP gets it, mmo
+# version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	f0ffffff 	jmp 400000c <a>
+	\.\.\.
+0+400000c <a>:
+ 400000c:	e3fd0004 	setl \$253,0x4
+0+4000010 <Main>:
+ 4000010:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs2bm.d	Sat Oct 18 04:47:57 2003
@@ -0,0 +1,31 @@
+#source: nop123.s
+#source: nop123.s
+#source: a.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: pad4.s
+#source: pushja.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside the offset range gets a JMP
+# stub expansion, backwards, mmo version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <a-0x8>:
+       0:	fd010203 	swym 1,2,3
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+40008 <pushja>:
+   40008:	e3fd0002 	setl \$253,0x2
+   4000c:	f20c0002 	pushj \$12,40014 <pushja\+0xc>
+   40010:	e3fd0003 	setl \$253,0x3
+   40014:	f1fefffd 	jmp 8 <a>
+0+40018 <Main>:
+   40018:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs4m.d	Sat Oct 18 04:46:35 2003
@@ -0,0 +1,33 @@
+#source: nop123.s
+#source: pushja.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pad4.s
+#source: pad4.s
+#source: a.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside reach of JMP works; it will
+# get the full expansion, mmo version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	e3ff0020 	setl \$255,0x20
+      14:	e6ff0400 	incml \$255,0x400
+      18:	e5ff0000 	incmh \$255,0x0
+      1c:	e4ff0000 	inch \$255,0x0
+      20:	9f00ff00 	go \$0,\$255,0
+	\.\.\.
+0+4000020 <a>:
+ 4000020:	e3fd0004 	setl \$253,0x4
+0+4000024 <Main>:
+ 4000024:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs3bm.d	Sat Oct 18 04:38:59 2003
@@ -0,0 +1,28 @@
+#source: nop123.s
+#source: nop123.s
+#source: a.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pushja.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just inside the offset range of a JMP
+# stub expansion works, backwards, mmo version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <a-0x8>:
+       0:	fd010203 	swym 1,2,3
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+3fffffc <pushja>:
+ 3fffffc:	e3fd0002 	setl \$253,0x2
+ 4000000:	f20c0002 	pushj \$12,4000008 <pushja\+0xc>
+ 4000004:	e3fd0003 	setl \$253,0x3
+ 4000008:	f1000000 	jmp 8 <a>
+0+400000c <Main>:
+ 400000c:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs2r.d	Mon Sep 29 06:23:51 2003
@@ -0,0 +1,27 @@
+#source: nop123.s
+#source: pushja.s
+#source: ext1l.s
+#source: pad2p18m32.s
+#source: pad16.s
+#source: nop123.s
+#ld: -r -m elf64mmix
+#objdump: -dr
+
+# When linking relocatably, check that PUSHJ with a distance to the end of
+# the section just outside the offset range gets expanded.
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	f0000000 	jmp 10 <pushja\+0xc>
+			10: R_MMIX_JMP	a
+	\.\.\.
+0+24 <ext1>:
+      24:	fd040810 	swym 4,8,16
+	\.\.\.
+   40018:	fd010203 	swym 1,2,3
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs4bm.d	Sat Oct 18 04:46:02 2003
@@ -0,0 +1,33 @@
+#source: nop123.s
+#source: nop123.s
+#source: a.s
+#source: pad2p26m32.s
+#source: pad16.s
+#source: pad4.s
+#source: pushja.s
+#source: start.s
+#ld: -m mmo
+#objdump: -dr
+
+# Check that PUSHJ with an offset just outside the offset range of a JMP
+# stub expansion works, backwards, mmo version.
+
+.*:     file format mmo
+Disassembly of section \.text:
+0+ <a-0x8>:
+       0:	fd010203 	swym 1,2,3
+       4:	fd010203 	swym 1,2,3
+0+8 <a>:
+       8:	e3fd0004 	setl \$253,0x4
+	\.\.\.
+0+4000000 <pushja>:
+ 4000000:	e3fd0002 	setl \$253,0x2
+ 4000004:	f20c0002 	pushj \$12,400000c <pushja\+0xc>
+ 4000008:	e3fd0003 	setl \$253,0x3
+ 400000c:	e3ff0008 	setl \$255,0x8
+ 4000010:	e6ff0000 	incml \$255,0x0
+ 4000014:	e5ff0000 	incmh \$255,0x0
+ 4000018:	e4ff0000 	inch \$255,0x0
+ 400001c:	9f00ff00 	go \$0,\$255,0
+0+4000020 <Main>:
+ 4000020:	e3fd0001 	setl \$253,0x1
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs3r.d	Mon Sep 29 06:47:30 2003
@@ -0,0 +1,32 @@
+#source: nop123.s
+#source: pushja.s
+#source: undef-2.s
+#source: nop123.s
+#source: pad16.s
+#source: pad2p18m32.s
+#ld: -r -m elf64mmix
+#objdump: -dr
+
+# When linking relocatably, check two expanded stubbable PUSHJs.
+
+# With better relaxation support for relocatable links, both should be
+# able to pass through unexpanded.  Right now, we just check that they can
+# coexist peacefully.
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	f0000000 	jmp 10 <pushja\+0xc>
+			10: R_MMIX_JMP	a
+	\.\.\.
+      24:	f2050001 	pushj \$5,28 <pushja\+0x24>
+      28:	f0000000 	jmp 28 <pushja\+0x24>
+			28: R_MMIX_JMP	undefd
+	\.\.\.
+      3c:	fd010203 	swym 1,2,3
+	\.\.\.
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ ld-mmix/pushjs4r.d	Mon Sep 29 06:51:08 2003
@@ -0,0 +1,29 @@
+#source: nop123.s
+#source: pushja.s
+#source: undef-2.s
+#source: pad2p18m32.s
+#source: nop123.s
+#ld: -r -m elf64mmix
+#objdump: -dr
+
+# When linking relocatably, check two stubbable PUSHJ:s, one expanded.
+
+# With better relaxation support for relocatable links, both should be
+# able to pass through unexpanded.  Right now, we just check that they can
+# coexist peacefully.
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0+ <pushja-0x4>:
+       0:	fd010203 	swym 1,2,3
+0+4 <pushja>:
+       4:	e3fd0002 	setl \$253,0x2
+       8:	f20c0002 	pushj \$12,10 <pushja\+0xc>
+       c:	e3fd0003 	setl \$253,0x3
+      10:	f0000000 	jmp 10 <pushja\+0xc>
+			10: R_MMIX_JMP	a
+	\.\.\.
+      24:	f2050000 	pushj \$5,24 <pushja\+0x20>
+			24: R_MMIX_PUSHJ_STUBBABLE	undefd
+	\.\.\.
+   40008:	fd010203 	swym 1,2,3
Index: doc/c-mmix.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-mmix.texi,v
retrieving revision 1.4
diff -p -c -r1.4 c-mmix.texi
*** doc/c-mmix.texi	19 Dec 2002 01:11:31 -0000	1.4
--- doc/c-mmix.texi	18 Oct 2003 00:37:09 -0000
*************** that at link stage can be contracted.  (
*** 82,87 ****
--- 82,102 ----
  implemented in @code{@value{LD}}.)  The option @samp{-x} also imples
  @samp{--linker-allocated-gregs}.

+ @cindex @samp{--no-pushj-stubs} command line option, MMIX
+ @cindex @samp{--no-stubs} command line option, MMIX
+ If instruction expansion is enabled, @code{@value{AS}} can expand a
+ @samp{PUSHJ} instruction into a series of instructions.  The shortest
+ expansion is to not expand it, but just mark the call as redirectable to a
+ stub, which @code{@value{LD}} creates at link-time, but only if the
+ original @samp{PUSHJ} instruction is found not to reach the target.  The
+ stub consists of the necessary instructions to form a jump to the target.
+ This happens if @code{@value{AS}} can assert that the @samp{PUSHJ}
+ instruction can reach such a stub.  The option @samp{--no-pushj-stubs}
+ disables this shorter expansion, and the longer series of instructions is
+ then created at assembly-time.  The option @samp{--no-stubs} is a synonym,
+ intended for compatibility with future releases, where generation of stubs
+ for other instructions may be implemented.
+
  @cindex @samp{--linker-allocated-gregs} command line option, MMIX
  Usually a two-operand-expression (@pxref{GREG-base}) without a matching
  @samp{GREG} directive is treated as an error by @code{@value{AS}}.  When
Index: config/tc-mmix.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mmix.c,v
retrieving revision 1.14
diff -p -c -r1.14 tc-mmix.c
*** config/tc-mmix.c	21 May 2003 12:07:55 -0000	1.14
--- config/tc-mmix.c	18 Oct 2003 00:37:09 -0000
***************
*** 27,32 ****
--- 27,33 ----


  #include <stdio.h>
+ #include <limits.h>
  #include "as.h"
  #include "subsegs.h"
  #include "bfd.h"
*************** struct mmix_symbol_gregs
*** 143,149 ****
     this line?  */
  static int label_without_colon_this_line = 1;

! /* Should we expand operands for external symbols?  */
  static int expand_op = 1;

  /* Should we warn when expanding operands?  FIXME: test-cases for when -x
--- 144,151 ----
     this line?  */
  static int label_without_colon_this_line = 1;

! /* Should we automatically expand instructions into multiple insns in
!    order to generate working code?  */
  static int expand_op = 1;

  /* Should we warn when expanding operands?  FIXME: test-cases for when -x
*************** int mmix_gnu_syntax = 0;
*** 170,177 ****
  /* Do we globalize all symbols?  */
  int mmix_globalize_symbols = 0;

  /* Do we know that the next semicolon is at the end of the operands field
!    (in mmixal mode; constant 1 in GNU mode)? */
  int mmix_next_semicolon_is_eoln = 1;

  /* Do we have a BSPEC in progress?  */
--- 172,183 ----
  /* Do we globalize all symbols?  */
  int mmix_globalize_symbols = 0;

+ /* When expanding insns, do we want to expand PUSHJ as a call to a stub
+    (or else as a series of insns)?  */
+ int pushj_stubs = 1;
+
  /* Do we know that the next semicolon is at the end of the operands field
!    (in mmixal mode; constant 1 in GNU mode)?  */
  int mmix_next_semicolon_is_eoln = 1;

  /* Do we have a BSPEC in progress?  */
*************** struct option md_longopts[] =
*** 189,194 ****
--- 195,201 ----
  #define OPTION_GLOBALIZE_SYMBOLS  (OPTION_GNU_SYNTAX + 1)
  #define OPTION_FIXED_SPEC_REGS  (OPTION_GLOBALIZE_SYMBOLS + 1)
  #define OPTION_LINKER_ALLOCATED_GREGS  (OPTION_FIXED_SPEC_REGS + 1)
+ #define OPTION_NOPUSHJSTUBS  (OPTION_LINKER_ALLOCATED_GREGS + 1)
     {"linkrelax", no_argument, NULL, OPTION_RELAX},
     {"no-expand", no_argument, NULL, OPTION_NOEXPAND},
     {"no-merge-gregs", no_argument, NULL, OPTION_NOMERGEGREG},
*************** struct option md_longopts[] =
*** 199,204 ****
--- 206,213 ----
      OPTION_FIXED_SPEC_REGS},
     {"linker-allocated-gregs", no_argument, NULL,
      OPTION_LINKER_ALLOCATED_GREGS},
+    {"no-pushj-stubs", no_argument, NULL, OPTION_NOPUSHJSTUBS},
+    {"no-stubs", no_argument, NULL, OPTION_NOPUSHJSTUBS},
     {NULL, no_argument, NULL, 0}
   };

*************** struct obstack mmix_sym_obstack;
*** 227,241 ****

     3. PUSHJ
        extra length: zero or four insns.

     4. JMP
!       extra length: zero or four insns.  */

  #define STATE_GETA	(1)
  #define STATE_BCC	(2)
  #define STATE_PUSHJ	(3)
  #define STATE_JMP	(4)
  #define STATE_GREG	(5)

  /* No fine-grainedness here.  */
  #define STATE_LENGTH_MASK	    (1)
--- 236,262 ----

     3. PUSHJ
        extra length: zero or four insns.
+       Special handling to deal with transition to PUSHJSTUB.

     4. JMP
!       extra length: zero or four insns.
!
!    5. GREG
!       special handling, allocates a named global register unless another
!       is within reach for all uses.
!
!    6. PUSHJSTUB
!       special handling (mostly) for external references; assumes the
!       linker will generate a stub if target is no longer than 256k from
!       the end of the section plus max size of previous stubs.  Zero or
!       four insns.  */

  #define STATE_GETA	(1)
  #define STATE_BCC	(2)
  #define STATE_PUSHJ	(3)
  #define STATE_JMP	(4)
  #define STATE_GREG	(5)
+ #define STATE_PUSHJSTUB	(6)

  /* No fine-grainedness here.  */
  #define STATE_LENGTH_MASK	    (1)
*************** struct obstack mmix_sym_obstack;
*** 279,284 ****
--- 300,323 ----
  #define PUSHJ_4F GETA_3F
  #define PUSHJ_4B GETA_3B

+ /* We'll very rarely have sections longer than LONG_MAX, but we'll make a
+    feeble attempt at getting 64-bit C99 or gcc-specific values (assuming
+    long long is 64 bits on the host).  */
+ #ifdef LLONG_MIN
+ #define PUSHJSTUB_MIN LLONG_MIN
+ #elsif defined (LONG_LONG_MIN)
+ #define PUSHJSTUB_MIN LONG_LONG_MIN
+ #else
+ #define PUSHJSTUB_MIN LONG_MIN
+ #endif
+ #ifdef LLONG_MAX
+ #define PUSHJSTUB_MAX LLONG_MAX
+ #elsif defined (LONG_LONG_MAX)
+ #define PUSHJSTUB_MAX LONG_LONG_MAX
+ #else
+ #define PUSHJSTUB_MAX LONG_MAX
+ #endif
+
  #define JMP_0F (65536 * 256 * 4 - 8)
  #define JMP_0B (-65536 * 256 * 4 - 4)

*************** const relax_typeS mmix_relax_table[] =
*** 311,318 ****
     {BCC_5F,	BCC_5B,
  		BCC_MAX_LEN - 4,	0},

!    /* PUSHJ (3, 0).  */
!    {PUSHJ_0F,	PUSHJ_0B,	0,	ENCODE_RELAX (STATE_PUSHJ, STATE_MAX)},

     /* PUSHJ (3, 1).  */
     {PUSHJ_4F,	PUSHJ_4B,
--- 350,357 ----
     {BCC_5F,	BCC_5B,
  		BCC_MAX_LEN - 4,	0},

!    /* PUSHJ (3, 0).  Next state is actually PUSHJSTUB (6, 0).  */
!    {PUSHJ_0F,	PUSHJ_0B,	0,	ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO)},

     /* PUSHJ (3, 1).  */
     {PUSHJ_4F,	PUSHJ_4B,
*************** const relax_typeS mmix_relax_table[] =
*** 326,332 ****
  		JMP_MAX_LEN - 4,	0},

     /* GREG (5, 0), (5, 1), though the table entry isn't used.  */
!    {0, 0, 0, 0}, {0, 0, 0, 0}
  };

  const pseudo_typeS md_pseudo_table[] =
--- 365,377 ----
  		JMP_MAX_LEN - 4,	0},

     /* GREG (5, 0), (5, 1), though the table entry isn't used.  */
!    {0, 0, 0, 0}, {0, 0, 0, 0},
!
!    /* PUSHJSTUB (6, 0).  PUSHJ (3, 0) uses the range, so we set it to infinite.  */
!    {PUSHJSTUB_MAX, PUSHJSTUB_MIN,
!     		0,			ENCODE_RELAX (STATE_PUSHJ, STATE_MAX)},
!    /* PUSHJSTUB (6, 1) isn't used.  */
!    {0, 0,	PUSHJ_MAX_LEN, 		0}
  };

  const pseudo_typeS md_pseudo_table[] =
*************** md_parse_option (c, arg)
*** 661,666 ****
--- 706,715 ----
        allocate_undefined_gregs_in_linker = 1;
        break;

+     case OPTION_NOPUSHJSTUBS:
+       pushj_stubs = 0;
+       break;
+
      default:
        return 0;
      }
*************** md_estimate_size_before_relax (fragP, se
*** 2181,2192 ****
      {
        HANDLE_RELAXABLE (STATE_GETA);
        HANDLE_RELAXABLE (STATE_BCC);
-       HANDLE_RELAXABLE (STATE_PUSHJ);
        HANDLE_RELAXABLE (STATE_JMP);

      case ENCODE_RELAX (STATE_GETA, STATE_ZERO):
      case ENCODE_RELAX (STATE_BCC, STATE_ZERO):
-     case ENCODE_RELAX (STATE_PUSHJ, STATE_ZERO):
      case ENCODE_RELAX (STATE_JMP, STATE_ZERO):
        /* When relaxing a section for the second time, we don't need to do
  	 anything except making sure that fr_var is set right.  */
--- 2230,2256 ----
      {
        HANDLE_RELAXABLE (STATE_GETA);
        HANDLE_RELAXABLE (STATE_BCC);
        HANDLE_RELAXABLE (STATE_JMP);

+     case ENCODE_RELAX (STATE_PUSHJ, STATE_UNDF):
+       if (fragP->fr_symbol != NULL
+ 	  && S_GET_SEGMENT (fragP->fr_symbol) == segment
+ 	  && !S_IS_WEAK (fragP->fr_symbol))
+ 	/* The symbol lies in the same segment - a relaxable case.  */
+ 	fragP->fr_subtype = ENCODE_RELAX (STATE_PUSHJ, STATE_ZERO);
+       else if (pushj_stubs)
+ 	/* If we're to generate stubs, assume we can reach a stub after
+            the section.  */
+ 	fragP->fr_subtype = ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO);
+       /* FALLTHROUGH.  */
+     case ENCODE_RELAX (STATE_PUSHJ, STATE_ZERO):
+     case ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO):
+       /* We need to distinguish different relaxation rounds.  */
+       seg_info (segment)->tc_segment_info_data.last_stubfrag = fragP;
+       break;
+
      case ENCODE_RELAX (STATE_GETA, STATE_ZERO):
      case ENCODE_RELAX (STATE_BCC, STATE_ZERO):
      case ENCODE_RELAX (STATE_JMP, STATE_ZERO):
        /* When relaxing a section for the second time, we don't need to do
  	 anything except making sure that fr_var is set right.  */
*************** md_convert_frag (abfd, sec, fragP)
*** 2307,2312 ****
--- 2371,2386 ----

    switch (fragP->fr_subtype)
      {
+     case ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO):
+       /* Setting the unknown bits to 0 seems the most appropriate.  */
+       mmix_set_geta_branch_offset (opcodep, 0);
+       tmpfixP = fix_new (opc_fragP, opcodep - opc_fragP->fr_literal, 8,
+ 			 fragP->fr_symbol, fragP->fr_offset, 1,
+ 			 BFD_RELOC_MMIX_PUSHJ_STUBBABLE);
+       COPY_FR_WHERE_TO_FX (fragP, tmpfixP);
+       var_part_size = 0;
+       break;
+
      case ENCODE_RELAX (STATE_GETA, STATE_ZERO):
      case ENCODE_RELAX (STATE_BCC, STATE_ZERO):
      case ENCODE_RELAX (STATE_PUSHJ, STATE_ZERO):
*************** md_apply_fix3 (fixP, valP, segment)
*** 2453,2458 ****
--- 2527,2533 ----
      case BFD_RELOC_MMIX_GETA:
      case BFD_RELOC_MMIX_CBRANCH:
      case BFD_RELOC_MMIX_PUSHJ:
+     case BFD_RELOC_MMIX_PUSHJ_STUBBABLE:
        /* If this fixup is out of range, punt to the linker to emit an
  	 error.  This should only happen with -no-expand.  */
        if (val < -(((offsetT) 1 << 19)/2)
*************** tc_gen_reloc (section, fixP)
*** 2665,2670 ****
--- 2740,2746 ----
      case BFD_RELOC_MMIX_PUSHJ_1:
      case BFD_RELOC_MMIX_PUSHJ_2:
      case BFD_RELOC_MMIX_PUSHJ_3:
+     case BFD_RELOC_MMIX_PUSHJ_STUBBABLE:
      case BFD_RELOC_MMIX_JMP:
      case BFD_RELOC_MMIX_JMP_1:
      case BFD_RELOC_MMIX_JMP_2:
*************** mmix_md_relax_frag (seg, fragP, stretch)
*** 3333,3345 ****
       fragS *fragP;
       long stretch;
  {
!   if (fragP->fr_subtype != STATE_GREG_DEF
!       && fragP->fr_subtype != STATE_GREG_UNDF)
!     return relax_frag (seg, fragP, stretch);

!   /* If we're defined, we don't grow.  */
!   if (fragP->fr_subtype == STATE_GREG_DEF)
!     return 0;

    as_fatal (_("internal: unexpected relax type %d:%d"),
  	    fragP->fr_type, fragP->fr_subtype);
--- 3409,3529 ----
       fragS *fragP;
       long stretch;
  {
!   switch (fragP->fr_subtype)
!     {
!       /* Growth for this type has been handled by mmix_md_end and
! 	 correctly estimated, so there's nothing more to do here.  */
!     case STATE_GREG_DEF:
!       return 0;

!     case ENCODE_RELAX (STATE_PUSHJ, STATE_ZERO):
!       {
! 	/* We need to handle relaxation type ourselves, since relax_frag
! 	   doesn't update fr_subtype if there's no size increase in the
! 	   current section; when going from plain PUSHJ to a stub.  This
! 	   is otherwise functionally the same as relax_frag in write.c,
! 	   simplified for this case.  */
! 	offsetT aim;
! 	addressT target;
! 	addressT address;
! 	symbolS *symbolP;
! 	target = fragP->fr_offset;
! 	address = fragP->fr_address;
! 	symbolP = fragP->fr_symbol;
!
! 	if (symbolP)
! 	  {
! 	    fragS *sym_frag;
!
! 	    sym_frag = symbol_get_frag (symbolP);
! 	    know (S_GET_SEGMENT (symbolP) != absolute_section
! 		  || sym_frag == &zero_address_frag);
! 	    target += S_GET_VALUE (symbolP);
!
! 	    /* If frag has yet to be reached on this pass, assume it will
! 	       move by STRETCH just as we did.  If this is not so, it will
! 	       be because some frag between grows, and that will force
! 	       another pass.  */
!
! 	    if (stretch != 0
! 		&& sym_frag->relax_marker != fragP->relax_marker
! 		&& S_GET_SEGMENT (symbolP) == seg)
! 	      target += stretch;
! 	  }
!
! 	aim = target - address - fragP->fr_fix;
! 	if (aim >= PUSHJ_0B && aim <= PUSHJ_0F)
! 	  {
! 	    /* Target is reachable with a PUSHJ.  */
! 	    segment_info_type *seginfo = seg_info (seg);
!
! 	    /* If we're at the end of a relaxation round, clear the stub
! 	       counter as initialization for the next round.  */
! 	    if (fragP == seginfo->tc_segment_info_data.last_stubfrag)
! 	      seginfo->tc_segment_info_data.nstubs = 0;
! 	    return 0;
! 	  }
!
! 	/* Not reachable.  Try a stub.  */
! 	fragP->fr_subtype = ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO);
!       }
!       /* FALLTHROUGH.  */
!
!       /* See if this PUSHJ is redirectable to a stub.  */
!     case ENCODE_RELAX (STATE_PUSHJSTUB, STATE_ZERO):
!       {
! 	segment_info_type *seginfo = seg_info (seg);
! 	fragS *lastfrag = seginfo->frchainP->frch_last;
! 	relax_substateT prev_type = fragP->fr_subtype;
!
! 	/* The last frag is always an empty frag, so it suffices to look
! 	   at its address to know the ending address of this section.  */
! 	know (lastfrag->fr_type == rs_fill
! 	      && lastfrag->fr_fix == 0
! 	      && lastfrag->fr_var == 0);
!
! 	/* For this PUSHJ to be relaxable into a call to a stub, the
! 	   distance must be no longer than 256k bytes from the PUSHJ to
! 	   the end of the section plus the maximum size of stubs so far.  */
! 	if ((lastfrag->fr_address
! 	     + stretch
! 	     + PUSHJ_MAX_LEN * seginfo->tc_segment_info_data.nstubs)
! 	    - (fragP->fr_address + fragP->fr_fix)
! 	    > GETA_0F
! 	    || !pushj_stubs)
! 	  fragP->fr_subtype = mmix_relax_table[prev_type].rlx_more;
! 	else
! 	  seginfo->tc_segment_info_data.nstubs++;
!
! 	/* If we're at the end of a relaxation round, clear the stub
! 	   counter as initialization for the next round.  */
! 	if (fragP == seginfo->tc_segment_info_data.last_stubfrag)
! 	  seginfo->tc_segment_info_data.nstubs = 0;
!
! 	return
! 	   (mmix_relax_table[fragP->fr_subtype].rlx_length
! 	    - mmix_relax_table[prev_type].rlx_length);
!       }
!
!     case ENCODE_RELAX (STATE_PUSHJ, STATE_MAX):
!       {
! 	segment_info_type *seginfo = seg_info (seg);
!
! 	/* Need to cover all STATE_PUSHJ states to act on the last stub
! 	   frag (the end of this relax round; initialization for the
! 	   next).  */
! 	if (fragP == seginfo->tc_segment_info_data.last_stubfrag)
! 	  seginfo->tc_segment_info_data.nstubs = 0;
!
! 	return 0;
!       }
!
!     default:
!       return relax_frag (seg, fragP, stretch);
!
!     case STATE_GREG_UNDF:
!       BAD_CASE (fragP->fr_subtype);
!     }

    as_fatal (_("internal: unexpected relax type %d:%d"),
  	    fragP->fr_type, fragP->fr_subtype);
Index: config/tc-mmix.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-mmix.h,v
retrieving revision 1.6
diff -p -c -r1.6 tc-mmix.h
*** config/tc-mmix.h	23 Oct 2002 05:21:09 -0000	1.6
--- config/tc-mmix.h	18 Oct 2003 00:37:09 -0000
***************
*** 1,5 ****
  /* tc-mmix.h -- Header file for tc-mmix.c.
!    Copyright (C) 2001, 2002 Free Software Foundation, Inc.
     Written by Hans-Peter Nilsson (hp@bitrange.com).

     This file is part of GAS, the GNU Assembler.
--- 1,5 ----
  /* tc-mmix.h -- Header file for tc-mmix.c.
!    Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
     Written by Hans-Peter Nilsson (hp@bitrange.com).

     This file is part of GAS, the GNU Assembler.
*************** extern int mmix_assemble_return_nonzero
*** 123,129 ****
  extern const struct relax_type mmix_relax_table[];
  #define TC_GENERIC_RELAX_TABLE mmix_relax_table

! /* We use the relax table for everything except the GREG frags.  */
  extern long mmix_md_relax_frag PARAMS ((segT, fragS *, long));
  #define md_relax_frag mmix_md_relax_frag

--- 123,129 ----
  extern const struct relax_type mmix_relax_table[];
  #define TC_GENERIC_RELAX_TABLE mmix_relax_table

! /* We use the relax table for everything except the GREG frags and PUSHJ.  */
  extern long mmix_md_relax_frag PARAMS ((segT, fragS *, long));
  #define md_relax_frag mmix_md_relax_frag

*************** extern void mmix_frob_file PARAMS ((void
*** 198,203 ****
--- 198,214 ----
  /* Used by mmix_frob_file.  Hangs on section symbols and unknown symbols.  */
  struct mmix_symbol_gregs;
  #define TC_SYMFIELD_TYPE struct mmix_symbol_gregs *
+
+ /* Used by relaxation, counting maximum needed PUSHJ stubs for a section.  */
+ struct mmix_segment_info_type
+  {
+    /* We only need to keep track of the last stubbable frag because
+       there's no less hackish way to keep track of different relaxation
+       rounds.  */
+    fragS *last_stubfrag;
+    bfd_size_type nstubs;
+  };
+ #define TC_SEGMENT_INFO_TYPE struct mmix_segment_info_type

  extern void mmix_md_elf_section_change_hook PARAMS ((void));
  #define md_elf_section_change_hook mmix_md_elf_section_change_hook
Index: op-0-1.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mmix/op-0-1.d,v
retrieving revision 1.2
diff -p -c -r1.2 op-0-1.d
*** op-0-1.d	3 Sep 2003 08:26:51 -0000	1.2
--- op-0-1.d	18 Oct 2003 14:35:15 -0000
***************
*** 1,5 ****
  #objdump: -srt
! #as: -x

  .*:     file format elf64-mmix

--- 1,5 ----
  #objdump: -srt
! #as: -x --no-stubs

  .*:     file format elf64-mmix

Index: pushj-c.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mmix/pushj-c.d,v
retrieving revision 1.1
diff -p -c -r1.1 pushj-c.d
*** pushj-c.d	30 Oct 2001 15:20:08 -0000	1.1
--- pushj-c.d	18 Oct 2003 14:35:15 -0000
***************
*** 1,4 ****
! #as: -x
  #objdump: -tdr

  .*:     file format elf64-mmix
--- 1,4 ----
! #as: -x --no-pushj-stubs
  #objdump: -tdr

  .*:     file format elf64-mmix
Index: reloclab-r.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mmix/reloclab-r.d,v
retrieving revision 1.1
diff -p -c -r1.1 reloclab-r.d
*** reloclab-r.d	30 Oct 2001 15:20:08 -0000	1.1
--- reloclab-r.d	18 Oct 2003 14:35:15 -0000
***************
*** 1,5 ****
  #objdump: -dr
! #as: -linkrelax -x
  #source: reloclab.s
  .*:     file format elf64-mmix

--- 1,5 ----
  #objdump: -dr
! #as: -linkrelax -x --no-stubs
  #source: reloclab.s
  .*:     file format elf64-mmix

Index: reloclab.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mmix/reloclab.d,v
retrieving revision 1.1
diff -p -c -r1.1 reloclab.d
*** reloclab.d	30 Oct 2001 15:20:08 -0000	1.1
--- reloclab.d	18 Oct 2003 14:35:15 -0000
***************
*** 1,5 ****
  #objdump: -dr
! #as: -x

  .*:     file format elf64-mmix

--- 1,5 ----
  #objdump: -dr
! #as: -x --no-stubs

  .*:     file format elf64-mmix

Index: reloclab.l
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mmix/reloclab.l,v
retrieving revision 1.1
diff -p -c -r1.1 reloclab.l
*** reloclab.l	30 Oct 2001 15:20:08 -0000	1.1
--- reloclab.l	18 Oct 2003 14:35:15 -0000
*************** GAS for MMIX .*/reloclab\.s 			page 1
*** 24,36 ****
    10      FD000000
    10      FD000000
    11 004c F2070000 		PUSHJ \$7,foobar
!   11      FD000000
!   11      FD000000
!   11      FD000000
!   11      FD000000
!   12 0060 F1FFFFF7 		JMP there
!   13 0064 F558FFF6 		GETA \$88,there
!   14 0068 476FFFF5 		BOD \$111,there
  GAS for MMIX .*/reloclab\.s 			page 2


--- 24,32 ----
    10      FD000000
    10      FD000000
    11 004c F2070000 		PUSHJ \$7,foobar
!   12 0050 F1FFFFFB 		JMP there
!   13 0054 F558FFFA 		GETA \$88,there
!   14 0058 476FFFF9 		BOD \$111,there
  GAS for MMIX .*/reloclab\.s 			page 2


Index: weak1.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/mmix/weak1.d,v
retrieving revision 1.2
diff -p -c -r1.2 weak1.d
*** weak1.d	3 Sep 2003 08:26:51 -0000	1.2
--- weak1.d	18 Oct 2003 14:35:15 -0000
***************
*** 1,4 ****
! #as: -x
  #objdump: -str

  # Relaxation thought a weak symbol was within reach.
--- 1,4 ----
! #as: -x --no-pushj-stubs
  #objdump: -str

  # Relaxation thought a weak symbol was within reach.
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ gas/mmix/pushj-cs.d	Sat Oct 18 16:30:48 2003
@@ -0,0 +1,18 @@
+#as: -x
+#source: pushj-c.s
+#objdump: -tdr
+
+.*:     file format elf64-mmix
+SYMBOL TABLE:
+0+ l    d  .text	0+
+0+ l    d  .data	0+
+0+ l    d  .bss	0+
+ffff0000ffff0000 l       \*ABS\*	0+ i1
+ffff0000ffff0000 l       \*ABS\*	0+ i2
+0+ g     F .text	0+ Main
+Disassembly of section \.text:
+0+ <Main>:
+   0:	f2010000 	pushj \$1,0 <Main>
+			0: R_MMIX_PUSHJ_STUBBABLE	\*ABS\*\+0xffff0000ffff0000
+   4:	f2020000 	pushj \$2,4 <Main\+0x4>
+			4: R_MMIX_PUSHJ_STUBBABLE	i2
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ gas/mmix/reloclab-s.d	Sat Oct 18 16:31:11 2003
@@ -0,0 +1,36 @@
+#objdump: -dr
+#source: reloclab.s
+#as: -x
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0000000000000000 <Main>:
+   0:	f0000000 	jmp 0 <Main>
+			0: R_MMIX_JMP	foo\+0x8
+   4:	fd000000 	swym 0,0,0
+   8:	fd000000 	swym 0,0,0
+   c:	fd000000 	swym 0,0,0
+  10:	fd000000 	swym 0,0,0
+  14:	f0000004 	jmp 24 <here>
+  18:	f4080003 	geta \$8,24 <here>
+  1c:	46630002 	bod \$99,24 <here>
+  20:	fd000000 	swym 0,0,0
+0000000000000024 <here>:
+  24:	42de0000 	bz \$222,24 <here>
+			24: R_MMIX_CBRANCH	bar\+0x10
+  28:	fd000000 	swym 0,0,0
+  2c:	fd000000 	swym 0,0,0
+  30:	fd000000 	swym 0,0,0
+  34:	fd000000 	swym 0,0,0
+  38:	fd000000 	swym 0,0,0
+000000000000003c <there>:
+  3c:	f4040000 	geta \$4,3c <there>
+			3c: R_MMIX_GETA	baz
+  40:	fd000000 	swym 0,0,0
+  44:	fd000000 	swym 0,0,0
+  48:	fd000000 	swym 0,0,0
+  4c:	f2070000 	pushj \$7,4c <there\+0x10>
+			4c: R_MMIX_PUSHJ_STUBBABLE	foobar
+  50:	f1fffffb 	jmp 3c <there>
+  54:	f558fffa 	geta \$88,3c <there>
+  58:	476ffff9 	bod \$111,3c <there>
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ gas/mmix/relax2.s	Tue Sep 16 01:25:18 2003
@@ -0,0 +1,35 @@
+# PUSHJ stub border-cases: two with either or both stubs unreachable,
+# local symbols, ditto non-local labels, similar with three PUSHJs.
+
+Main	SWYM
+
+	.irp x,0,1,2,3,4,5,6,7,8,9,10,11,12
+
+	.section .text.a\x,"ax"
+aa\x:	.space 4,0
+a\x:	.space 65536*4,0
+	PUSHJ $33,aa\x
+	PUSHJ $22,a\x
+	.space 65535*4-4*\x
+
+	.section .text.b\x,"ax"
+bbb\x:	.space 4,0
+bb\x:	.space 4,0
+b\x:	.space 65535*4
+	PUSHJ $12,bbb\x
+	PUSHJ $13,bb\x
+	PUSHJ $14,b\x
+	.space 65535*4-4*\x
+
+	.section .text.c\x,"ax"
+c\x:	PUSHJ $100,ca\x
+	PUSHJ $101,cb\x
+	.space 65535*4-4*\x
+
+	.section .text.d\x,"ax"
+d\x:	PUSHJ $99,da\x
+	PUSHJ $98,db\x
+	PUSHJ $97,dc\x
+	.space 65535*4-4*\x
+
+	.endr
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ gas/mmix/relax2.d	Sat Oct 18 16:32:44 2003
@@ -0,0 +1,251 @@
+#objdump: -r
+#as: -x
+
+.*:     file format elf64-mmix
+R.* \[\.text\.a0\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.a0
+0+40018 R_MMIX_PUSHJ      \.text\.a0\+0x0+4
+R.* \[\.text\.b0\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b0
+0+40018 R_MMIX_PUSHJ      \.text\.b0\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b0\+0x0+8
+R.* \[\.text\.c0\]:
+O.*
+0+ R_MMIX_PUSHJ      ca0
+0+14 R_MMIX_PUSHJ      cb0
+R.* \[\.text\.d0\]:
+O.*
+0+ R_MMIX_PUSHJ      da0
+0+14 R_MMIX_PUSHJ      db0
+0+28 R_MMIX_PUSHJ      dc0
+R.* \[\.text\.a1\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.a1
+0+40018 R_MMIX_PUSHJ_STUBBABLE  \.text\.a1\+0x0+4
+R.* \[\.text\.b1\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b1
+0+40018 R_MMIX_PUSHJ      \.text\.b1\+0x0+4
+0+4002c R_MMIX_PUSHJ_STUBBABLE  \.text\.b1\+0x0+8
+R.* \[\.text\.c1\]:
+O.*
+0+ R_MMIX_PUSHJ      ca1
+0+14 R_MMIX_PUSHJ_STUBBABLE  cb1
+R.* \[\.text\.d1\]:
+O.*
+0+ R_MMIX_PUSHJ      da1
+0+14 R_MMIX_PUSHJ      db1
+0+28 R_MMIX_PUSHJ_STUBBABLE  dc1
+
+# The following shows a limitation of the PUSHJ relaxation code when
+# PUSHJ:s are close, and about 256k away from the section limit: On the
+# first relaxation iteration, the first (or second) PUSHJ looks like it
+# could reach a stub.  However, the last PUSHJ is expanded and on the
+# second iteration, the stubbed PUSHJ has to be expanded too because it
+# can't reach the stubs anymore.  This continues for the next iterations,
+# because the max stub size is five tetrabytes (4-bytes).  At the expense
+# of much more complex relaxation code (including the relaxation machinery
+# in write.c), this is fixable.  Anyway, as long as PUSHJ:s aren't closer
+# than five instructions, the existing code does suffice; we're just here
+# to check that the border case *works* and doesn't generate invalid code.
+
+R.* \[\.text\.a2\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.a2
+0+40018 R_MMIX_PUSHJ      \.text\.a2\+0x0+4
+R.* \[\.text\.b2\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b2
+0+40018 R_MMIX_PUSHJ      \.text\.b2\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b2\+0x0+8
+R.* \[\.text\.c2\]:
+O.*
+0+ R_MMIX_PUSHJ      ca2
+0+14 R_MMIX_PUSHJ      cb2
+R.* \[\.text\.d2\]:
+O.*
+0+ R_MMIX_PUSHJ      da2
+0+14 R_MMIX_PUSHJ      db2
+0+28 R_MMIX_PUSHJ      dc2
+R.* \[\.text\.a3\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.a3
+0+40018 R_MMIX_PUSHJ      \.text\.a3\+0x0+4
+R.* \[\.text\.b3\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b3
+0+40018 R_MMIX_PUSHJ      \.text\.b3\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b3\+0x0+8
+R.* \[\.text\.c3\]:
+O.*
+0+ R_MMIX_PUSHJ      ca3
+0+14 R_MMIX_PUSHJ      cb3
+R.* \[\.text\.d3\]:
+O.*
+0+ R_MMIX_PUSHJ      da3
+0+14 R_MMIX_PUSHJ      db3
+0+28 R_MMIX_PUSHJ      dc3
+R.* \[\.text\.a4\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.a4
+0+40018 R_MMIX_PUSHJ      \.text\.a4\+0x0+4
+R.* \[\.text\.b4\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b4
+0+40018 R_MMIX_PUSHJ      \.text\.b4\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b4\+0x0+8
+R.* \[\.text\.c4\]:
+O.*
+0+ R_MMIX_PUSHJ      ca4
+0+14 R_MMIX_PUSHJ      cb4
+R.* \[\.text\.d4\]:
+O.*
+0+ R_MMIX_PUSHJ      da4
+0+14 R_MMIX_PUSHJ      db4
+0+28 R_MMIX_PUSHJ      dc4
+R.* \[\.text\.a5\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.a5
+0+40018 R_MMIX_PUSHJ      \.text\.a5\+0x0+4
+R.* \[\.text\.b5\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b5
+0+40018 R_MMIX_PUSHJ      \.text\.b5\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b5\+0x0+8
+R.* \[\.text\.c5\]:
+O.*
+0+ R_MMIX_PUSHJ      ca5
+0+14 R_MMIX_PUSHJ      cb5
+R.* \[\.text\.d5\]:
+O.*
+0+ R_MMIX_PUSHJ      da5
+0+14 R_MMIX_PUSHJ      db5
+0+28 R_MMIX_PUSHJ      dc5
+R.* \[\.text\.a6\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.a6
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.a6\+0x0+4
+R.* \[\.text\.b6\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b6
+0+40018 R_MMIX_PUSHJ      \.text\.b6\+0x0+4
+0+4002c R_MMIX_PUSHJ_STUBBABLE  \.text\.b6\+0x0+8
+R.* \[\.text\.c6\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  ca6
+0+4 R_MMIX_PUSHJ_STUBBABLE  cb6
+R.* \[\.text\.d6\]:
+O.*
+0+ R_MMIX_PUSHJ      da6
+0+14 R_MMIX_PUSHJ      db6
+0+28 R_MMIX_PUSHJ_STUBBABLE  dc6
+R.* \[\.text\.a7\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.a7
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.a7\+0x0+4
+R.* \[\.text\.b7\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b7
+0+40018 R_MMIX_PUSHJ      \.text\.b7\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b7\+0x0+8
+R.* \[\.text\.c7\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  ca7
+0+4 R_MMIX_PUSHJ_STUBBABLE  cb7
+R.* \[\.text\.d7\]:
+O.*
+0+ R_MMIX_PUSHJ      da7
+0+14 R_MMIX_PUSHJ      db7
+0+28 R_MMIX_PUSHJ      dc7
+R.* \[\.text\.a8\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.a8
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.a8\+0x0+4
+R.* \[\.text\.b8\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b8
+0+40018 R_MMIX_PUSHJ      \.text\.b8\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b8\+0x0+8
+R.* \[\.text\.c8\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  ca8
+0+4 R_MMIX_PUSHJ_STUBBABLE  cb8
+R.* \[\.text\.d8\]:
+O.*
+0+ R_MMIX_PUSHJ      da8
+0+14 R_MMIX_PUSHJ      db8
+0+28 R_MMIX_PUSHJ      dc8
+R.* \[\.text\.a9\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.a9
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.a9\+0x0+4
+R.* \[\.text\.b9\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b9
+0+40018 R_MMIX_PUSHJ      \.text\.b9\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b9\+0x0+8
+R.* \[\.text\.c9\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  ca9
+0+4 R_MMIX_PUSHJ_STUBBABLE  cb9
+R.* \[\.text\.d9\]:
+O.*
+0+ R_MMIX_PUSHJ      da9
+0+14 R_MMIX_PUSHJ      db9
+0+28 R_MMIX_PUSHJ      dc9
+R.* \[\.text\.a10\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.a10
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.a10\+0x0+4
+R.* \[\.text\.b10\]:
+O.*
+0+40004 R_MMIX_PUSHJ      \.text\.b10
+0+40018 R_MMIX_PUSHJ      \.text\.b10\+0x0+4
+0+4002c R_MMIX_PUSHJ      \.text\.b10\+0x0+8
+R.* \[\.text\.c10\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  ca10
+0+4 R_MMIX_PUSHJ_STUBBABLE  cb10
+R.* \[\.text\.d10\]:
+O.*
+0+ R_MMIX_PUSHJ      da10
+0+14 R_MMIX_PUSHJ      db10
+0+28 R_MMIX_PUSHJ      dc10
+R.* \[\.text\.a11\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.a11
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.a11\+0x0+4
+R.* \[\.text\.b11\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.b11
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.b11\+0x0+4
+0+4000c R_MMIX_PUSHJ_STUBBABLE  \.text\.b11\+0x0+8
+R.* \[\.text\.c11\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  ca11
+0+4 R_MMIX_PUSHJ_STUBBABLE  cb11
+R.* \[\.text\.d11\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  da11
+0+4 R_MMIX_PUSHJ_STUBBABLE  db11
+0+8 R_MMIX_PUSHJ_STUBBABLE  dc11
+R.* \[\.text\.a12\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.a12
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.a12\+0x0+4
+R.* \[\.text\.b12\]:
+O.*
+0+40004 R_MMIX_PUSHJ_STUBBABLE  \.text\.b12
+0+40008 R_MMIX_PUSHJ_STUBBABLE  \.text\.b12\+0x0+4
+0+4000c R_MMIX_PUSHJ_STUBBABLE  \.text\.b12\+0x0+8
+R.* \[\.text\.c12\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  ca12
+0+4 R_MMIX_PUSHJ_STUBBABLE  cb12
+R.* \[\.text\.d12\]:
+O.*
+0+ R_MMIX_PUSHJ_STUBBABLE  da12
+0+4 R_MMIX_PUSHJ_STUBBABLE  db12
+0+8 R_MMIX_PUSHJ_STUBBABLE  dc12
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ gas/mmix/op-0-1s.d	Sat Oct 18 16:36:00 2003
@@ -0,0 +1,22 @@
+#objdump: -srt
+#source: op-0-1.s
+#as: -x
+
+.*:     file format elf64-mmix
+SYMBOL TABLE:
+0+ l    d  \.text	0+
+0+ l    d  \.data	0+
+0+ l    d  \.bss	0+
+0+ l       \*ABS\*	0+ zero0
+0+ l       \*ABS\*	0+ zero1
+0+ l       \*ABS\*	0+ zero2
+0+ g     F \.text	0+ Main
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET           TYPE              VALUE
+0+ R_MMIX_JMP        \*ABS\*
+0+14 R_MMIX_GETA       \*ABS\*
+0+24 R_MMIX_PUSHJ_STUBBABLE  \*ABS\*
+Contents of section \.text:
+ 0000 f0000000 fd000000 fd000000 fd000000  .*
+ 0010 fd000000 f4070000 fd000000 fd000000  .*
+ 0020 fd000000 f2080000                    .*
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ gas/mmix/reloclab-rs.d	Sat Oct 18 16:36:23 2003
@@ -0,0 +1,42 @@
+#objdump: -dr
+#as: -linkrelax -x
+#source: reloclab.s
+
+.*:     file format elf64-mmix
+Disassembly of section \.text:
+0000000000000000 <Main>:
+   0:	f0000000 	jmp 0 <Main>
+			0: R_MMIX_JMP	foo\+0x8
+   4:	fd000000 	swym 0,0,0
+   8:	fd000000 	swym 0,0,0
+   c:	fd000000 	swym 0,0,0
+  10:	fd000000 	swym 0,0,0
+  14:	f0000004 	jmp 24 <here>
+			14: R_MMIX_ADDR27	\.text\+0x24
+  18:	f4080003 	geta \$8,24 <here>
+			18: R_MMIX_ADDR19	\.text\+0x24
+  1c:	46630002 	bod \$99,24 <here>
+			1c: R_MMIX_ADDR19	\.text\+0x24
+  20:	fd000000 	swym 0,0,0
+0000000000000024 <here>:
+  24:	42de0000 	bz \$222,24 <here>
+			24: R_MMIX_CBRANCH	bar\+0x10
+  28:	fd000000 	swym 0,0,0
+  2c:	fd000000 	swym 0,0,0
+  30:	fd000000 	swym 0,0,0
+  34:	fd000000 	swym 0,0,0
+  38:	fd000000 	swym 0,0,0
+000000000000003c <there>:
+  3c:	f4040000 	geta \$4,3c <there>
+			3c: R_MMIX_GETA	baz
+  40:	fd000000 	swym 0,0,0
+  44:	fd000000 	swym 0,0,0
+  48:	fd000000 	swym 0,0,0
+  4c:	f2070000 	pushj \$7,4c <there\+0x10>
+			4c: R_MMIX_PUSHJ_STUBBABLE	foobar
+  50:	f1fffffb 	jmp 3c <there>
+			50: R_MMIX_ADDR27	\.text\+0x3c
+  54:	f558fffa 	geta \$88,3c <there>
+			54: R_MMIX_ADDR19	\.text\+0x3c
+  58:	476ffff9 	bod \$111,3c <there>
+			58: R_MMIX_ADDR19	\.text\+0x3c
--- /dev/null	Tue Jan  1 05:00:00 1980
+++ gas/mmix/weak1-s.d	Sat Oct 18 16:39:46 2003
@@ -0,0 +1,19 @@
+#as: -x
+#source: weak1.s
+#objdump: -str
+
+# Like weak1, but with PUSHJ stubs.
+
+.*:     file format elf64-mmix
+SYMBOL TABLE:
+0+ l    d  \.text	0+
+0+ l    d  \.data	0+
+0+ l    d  \.bss	0+
+0+  w      \.text	0+ foo
+0+4 g       \.text	0+ main
+RELOCATION RECORDS FOR \[\.text\]:
+OFFSET           TYPE              VALUE
+0+8 R_MMIX_64         foo
+0+4 R_MMIX_PUSHJ_STUBBABLE  foo
+Contents of section \.text:
+ 0000 f8010000 f20f0000 00000000 00000000  .*

brgds, H-P



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