Patch to extend explicit reloc support in MIPS gas

Eric Christopher echristo@redhat.com
Mon Jan 27 20:27:00 GMT 2003


>   On the other hand, an error or warning might trap mistakes earlier.
>   I can add some new checking code if that's what folks prefer.
> 

Error checking code is always good, but not necessary for the patch.

> 
> OK to install?
> 

OK. Wonderful work. Thanks.

-eric

> gas/
> 	* config/tc-mips.c (enum small_ex_type): Remove.
> 	(imm_unmatched_hi): Remove.
> 	(md_assemble): Remove use of imm_unmatched_hi.  Remove the last
> 	argument from calls to append_insn.
> 	(append_insn): Remove unmatched_hi parameter; check reloc_type[0]
> 	instead.
> 	(macro_build): Update append_insn calls.
> 	(mips16_macro_build, macro_build_lui): Likewise.
> 	(mips_ip): Rework handling of small expressions.  Move explicit
> 	relocation handling into my_getSmallExpression.  Assume that the
> 	value of 'o' operands is zero if there is only one bracketed
> 	expression left.
> 	(percent_op): Make constant.  Record the BFD relocation code
> 	associated with each operator.
> 	(my_getSmallParser, my_getPercentOp): Remove.
> 	(parse_relocation): New function.
> 	(my_getSamllExpression): Rework.  Fill in relocations here
> 	rather than in mips_ip.
> 
> gas/testsuite
> 	* gas/mips/elf-rel8.[sd], gas/mips/elf-rel9.[sd],
> 	gas/mips/elf-rel10.[sd], gas/mips/elf-rel11.[sd]: New tests.
> 	* gas/mips/mips.exp: Run elf-rel8 and elf-rel9 for all elf
> 	targets.  Run elf-rel10 and elf-rel11 for NewABI targets.
> 
> Index: config/tc-mips.c
> ===================================================================
> RCS file: /cvs/src/src/gas/config/tc-mips.c,v
> retrieving revision 1.188
> diff -c -d -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.188 tc-mips.c
> *** config/tc-mips.c	23 Jan 2003 12:51:05 -0000	1.188
> --- config/tc-mips.c	26 Jan 2003 12:09:08 -0000
> *************** static void mips16_mark_labels
> *** 810,816 ****
>     PARAMS ((void));
>   static void append_insn
>     PARAMS ((char *place, struct mips_cl_insn * ip, expressionS * p,
> ! 	   bfd_reloc_code_real_type *r, bfd_boolean));
>   static void mips_no_prev_insn
>     PARAMS ((int));
>   static void mips_emit_delays
> --- 810,816 ----
>     PARAMS ((void));
>   static void append_insn
>     PARAMS ((char *place, struct mips_cl_insn * ip, expressionS * p,
> ! 	   bfd_reloc_code_real_type *r));
>   static void mips_no_prev_insn
>     PARAMS ((int));
>   static void mips_emit_delays
> *************** static void mips16_ip
> *** 856,867 ****
>   static void mips16_immed
>     PARAMS ((char *, unsigned int, int, offsetT, bfd_boolean, bfd_boolean,
>   	   bfd_boolean, unsigned long *, bfd_boolean *, unsigned short *));
> ! static int my_getPercentOp
> !   PARAMS ((char **, unsigned int *, int *));
> ! static int my_getSmallParser
> !   PARAMS ((char **, unsigned int *, int *));
> ! static int my_getSmallExpression
> !   PARAMS ((expressionS *, char *));
>   static void my_getExpression
>     PARAMS ((expressionS *, char *));
>   #ifdef OBJ_ELF
> --- 856,865 ----
>   static void mips16_immed
>     PARAMS ((char *, unsigned int, int, offsetT, bfd_boolean, bfd_boolean,
>   	   bfd_boolean, unsigned long *, bfd_boolean *, unsigned short *));
> ! static bfd_boolean parse_relocation
> !   PARAMS ((char **, bfd_reloc_code_real_type *));
> ! static size_t my_getSmallExpression
> !   PARAMS ((expressionS *, bfd_reloc_code_real_type *, char *));
>   static void my_getExpression
>     PARAMS ((expressionS *, char *));
>   #ifdef OBJ_ELF
> *************** static int mips_need_elf_addend_fixup
> *** 946,977 ****
>     PARAMS ((fixS *));
>   #endif
>   
> - /* Return values of my_getSmallExpression().  */
> - 
> - enum small_ex_type
> - {
> -   S_EX_NONE = 0,
> -   S_EX_REGISTER,
> - 
> -   /* Direct relocation creation by %percent_op().  */
> -   S_EX_HALF,
> -   S_EX_HI,
> -   S_EX_LO,
> -   S_EX_GP_REL,
> -   S_EX_GOT,
> -   S_EX_CALL16,
> -   S_EX_GOT_DISP,
> -   S_EX_GOT_PAGE,
> -   S_EX_GOT_OFST,
> -   S_EX_GOT_HI,
> -   S_EX_GOT_LO,
> -   S_EX_NEG,
> -   S_EX_HIGHER,
> -   S_EX_HIGHEST,
> -   S_EX_CALL_HI,
> -   S_EX_CALL_LO
> - };
> - 
>   /* Table and functions used to map between CPU/ISA names, and
>      ISA levels, and CPU numbers.  */
>   
> --- 944,949 ----
> *************** static bfd_reloc_code_real_type imm_relo
> *** 1136,1145 ****
>   static bfd_reloc_code_real_type offset_reloc[3]
>     = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
>   
> - /* This is set by mips_ip if imm_reloc is an unmatched HI16_S reloc.  */
> - 
> - static bfd_boolean imm_unmatched_hi;
> - 
>   /* These are set by mips16_ip if an explicit extension is used.  */
>   
>   static bfd_boolean mips16_small, mips16_ext;
> --- 1108,1113 ----
> *************** md_assemble (str)
> *** 1430,1436 ****
>       = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
>   
>     imm_expr.X_op = O_absent;
> -   imm_unmatched_hi = FALSE;
>     offset_expr.X_op = O_absent;
>     imm_reloc[0] = BFD_RELOC_UNUSED;
>     imm_reloc[1] = BFD_RELOC_UNUSED;
> --- 1398,1403 ----
> *************** md_assemble (str)
> *** 1464,1474 ****
>     else
>       {
>         if (imm_expr.X_op != O_absent)
> ! 	append_insn (NULL, &insn, &imm_expr, imm_reloc, imm_unmatched_hi);
>         else if (offset_expr.X_op != O_absent)
> ! 	append_insn (NULL, &insn, &offset_expr, offset_reloc, FALSE);
>         else
> ! 	append_insn (NULL, &insn, NULL, unused_reloc, FALSE);
>       }
>   }
>   
> --- 1431,1441 ----
>     else
>       {
>         if (imm_expr.X_op != O_absent)
> ! 	append_insn (NULL, &insn, &imm_expr, imm_reloc);
>         else if (offset_expr.X_op != O_absent)
> ! 	append_insn (NULL, &insn, &offset_expr, offset_reloc);
>         else
> ! 	append_insn (NULL, &insn, NULL, unused_reloc);
>       }
>   }
>   
> *************** mips16_mark_labels ()
> *** 1616,1638 ****
>      used with RELOC_TYPE.  */
>   
>   static void
> ! append_insn (place, ip, address_expr, reloc_type, unmatched_hi)
>        char *place;
>        struct mips_cl_insn *ip;
>        expressionS *address_expr;
>        bfd_reloc_code_real_type *reloc_type;
> -      bfd_boolean unmatched_hi;
>   {
>     register unsigned long prev_pinfo, pinfo;
>     char *f;
>     fixS *fixp[3];
>     int nops = 0;
>   
>     /* Mark instruction labels in mips16 mode.  */
>     mips16_mark_labels ();
>   
>     prev_pinfo = prev_insn.insn_mo->pinfo;
>     pinfo = ip->insn_mo->pinfo;
>   
>     if (place == NULL && (! mips_opts.noreorder || prev_nop_frag != NULL))
>       {
> --- 1583,1606 ----
>      used with RELOC_TYPE.  */
>   
>   static void
> ! append_insn (place, ip, address_expr, reloc_type)
>        char *place;
>        struct mips_cl_insn *ip;
>        expressionS *address_expr;
>        bfd_reloc_code_real_type *reloc_type;
>   {
>     register unsigned long prev_pinfo, pinfo;
>     char *f;
>     fixS *fixp[3];
>     int nops = 0;
> +   bfd_boolean unmatched_reloc_p;
>   
>     /* Mark instruction labels in mips16 mode.  */
>     mips16_mark_labels ();
>   
>     prev_pinfo = prev_insn.insn_mo->pinfo;
>     pinfo = ip->insn_mo->pinfo;
> +   unmatched_reloc_p = FALSE;
>   
>     if (place == NULL && (! mips_opts.noreorder || prev_nop_frag != NULL))
>       {
> *************** #define emit_nop()					\
> *** 2176,2192 ****
>   		   || *reloc_type == BFD_RELOC_MIPS_RELGOT))
>   		fixp[0]->fx_no_overflow = 1;
>   
> ! 	      if (unmatched_hi)
>   		{
>   		  struct mips_hi_fixup *hi_fixup;
>   
> - 		  assert (*reloc_type == BFD_RELOC_HI16_S);
>   		  hi_fixup = ((struct mips_hi_fixup *)
>   			      xmalloc (sizeof (struct mips_hi_fixup)));
>   		  hi_fixup->fixp = fixp[0];
>   		  hi_fixup->seg = now_seg;
>   		  hi_fixup->next = mips_hi_fixup_list;
>   		  mips_hi_fixup_list = hi_fixup;
>   		}
>   
>   	      if (reloc_type[1] != BFD_RELOC_UNUSED)
> --- 2144,2160 ----
>   		   || *reloc_type == BFD_RELOC_MIPS_RELGOT))
>   		fixp[0]->fx_no_overflow = 1;
>   
> ! 	      if (reloc_type[0] == BFD_RELOC_HI16_S)
>   		{
>   		  struct mips_hi_fixup *hi_fixup;
>   
>   		  hi_fixup = ((struct mips_hi_fixup *)
>   			      xmalloc (sizeof (struct mips_hi_fixup)));
>   		  hi_fixup->fixp = fixp[0];
>   		  hi_fixup->seg = now_seg;
>   		  hi_fixup->next = mips_hi_fixup_list;
>   		  mips_hi_fixup_list = hi_fixup;
> + 		  unmatched_reloc_p = TRUE;
>   		}
>   
>   	      if (reloc_type[1] != BFD_RELOC_UNUSED)
> *************** #define emit_nop()					\
> *** 2743,2749 ****
>        reloc does not become a variant frag.  Otherwise, the
>        rearrangement of %hi relocs in frob_file may confuse
>        tc_gen_reloc.  */
> !   if (unmatched_hi)
>       {
>         frag_wane (frag_now);
>         frag_new (0);
> --- 2711,2717 ----
>        reloc does not become a variant frag.  Otherwise, the
>        rearrangement of %hi relocs in frob_file may confuse
>        tc_gen_reloc.  */
> !   if (unmatched_reloc_p)
>       {
>         frag_wane (frag_now);
>         frag_new (0);
> *************** macro_build (place, counter, ep, name, f
> *** 3140,3146 ****
>     va_end (args);
>     assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
>   
> !   append_insn (place, &insn, ep, r, FALSE);
>   }
>   
>   static void
> --- 3108,3114 ----
>     va_end (args);
>     assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
>   
> !   append_insn (place, &insn, ep, r);
>   }
>   
>   static void
> *************** mips16_macro_build (place, counter, ep, 
> *** 3266,3272 ****
>   
>     assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
>   
> !   append_insn (place, &insn, ep, r, FALSE);
>   }
>   
>   /*
> --- 3234,3240 ----
>   
>     assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL);
>   
> !   append_insn (place, &insn, ep, r);
>   }
>   
>   /*
> *************** macro_build_lui (place, counter, ep, reg
> *** 3356,3365 ****
>     if (*r == BFD_RELOC_UNUSED)
>       {
>         insn.insn_opcode |= high_expr.X_add_number;
> !       append_insn (place, &insn, NULL, r, FALSE);
>       }
>     else
> !     append_insn (place, &insn, &high_expr, r, FALSE);
>   }
>   
>   /* Generate a sequence of instructions to do a load or store from a constant
> --- 3324,3333 ----
>     if (*r == BFD_RELOC_UNUSED)
>       {
>         insn.insn_opcode |= high_expr.X_add_number;
> !       append_insn (place, &insn, NULL, r);
>       }
>     else
> !     append_insn (place, &insn, &high_expr, r);
>   }
>   
>   /* Generate a sequence of instructions to do a load or store from a constant
> *************** mips_ip (str, ip)
> *** 9065,9186 ****
>   	    case 'i':		/* 16 bit unsigned immediate */
>   	    case 'j':		/* 16 bit signed immediate */
>   	      *imm_reloc = BFD_RELOC_LO16;
> ! 	      c = my_getSmallExpression (&imm_expr, s);
> ! 	      if (c != S_EX_NONE)
> ! 		{
> ! 		  if (c != S_EX_LO)
> ! 		    {
> ! 		      if (c == S_EX_HI)
> ! 			{
> ! 			  *imm_reloc = BFD_RELOC_HI16_S;
> ! 			  imm_unmatched_hi = TRUE;
> ! 			}
> ! #ifdef OBJ_ELF
> ! 		      else if (c == S_EX_HIGHEST)
> ! 			*imm_reloc = BFD_RELOC_MIPS_HIGHEST;
> ! 		      else if (c == S_EX_HIGHER)
> ! 			*imm_reloc = BFD_RELOC_MIPS_HIGHER;
> ! 		      else if (c == S_EX_GP_REL)
> ! 			{
> ! 			  /* This occurs in NewABI only.  */
> ! 			  c = my_getSmallExpression (&imm_expr, s);
> ! 			  if (c != S_EX_NEG)
> ! 			    as_bad (_("bad composition of relocations"));
> ! 			  else
> ! 			    {
> ! 			      c = my_getSmallExpression (&imm_expr, s);
> ! 			      if (c != S_EX_LO)
> ! 				as_bad (_("bad composition of relocations"));
> ! 			      else
> ! 				{
> ! 				  imm_reloc[0] = BFD_RELOC_GPREL16;
> ! 				  imm_reloc[1] = BFD_RELOC_MIPS_SUB;
> ! 				  imm_reloc[2] = BFD_RELOC_LO16;
> ! 				}
> ! 			    }
> ! 			}
> ! #endif
> ! 		      else
> ! 			*imm_reloc = BFD_RELOC_HI16;
> ! 		    }
> ! 		  else if (imm_expr.X_op == O_constant)
> ! 		    imm_expr.X_add_number &= 0xffff;
> ! 		}
> ! 	      if (*args == 'i')
> ! 		{
> ! 		  if ((c == S_EX_NONE && imm_expr.X_op != O_constant)
> ! 		      || ((imm_expr.X_add_number < 0
> ! 			   || imm_expr.X_add_number >= 0x10000)
> ! 			  && imm_expr.X_op == O_constant))
> ! 		    {
> ! 		      if (insn + 1 < &mips_opcodes[NUMOPCODES] &&
> ! 			  !strcmp (insn->name, insn[1].name))
> ! 			break;
> ! 		      if (imm_expr.X_op == O_constant
> ! 			  || imm_expr.X_op == O_big)
> ! 			as_bad (_("16 bit expression not in range 0..65535"));
> ! 		    }
> ! 		}
> ! 	      else
>   		{
>   		  int more;
> ! 		  offsetT max;
>   
> ! 		  /* The upper bound should be 0x8000, but
> ! 		     unfortunately the MIPS assembler accepts numbers
> ! 		     from 0x8000 to 0xffff and sign extends them, and
> ! 		     we want to be compatible.  We only permit this
> ! 		     extended range for an instruction which does not
> ! 		     provide any further alternates, since those
> ! 		     alternates may handle other cases.  People should
> ! 		     use the numbers they mean, rather than relying on
> ! 		     a mysterious sign extension.  */
> ! 		  more = (insn + 1 < &mips_opcodes[NUMOPCODES] &&
> ! 			  strcmp (insn->name, insn[1].name) == 0);
> ! 		  if (more)
> ! 		    max = 0x8000;
>   		  else
> ! 		    max = 0x10000;
> ! 		  if ((c == S_EX_NONE && imm_expr.X_op != O_constant)
> ! 		      || ((imm_expr.X_add_number < -0x8000
> ! 			   || imm_expr.X_add_number >= max)
> ! 			  && imm_expr.X_op == O_constant)
> ! 		      || (more
> ! 			  && imm_expr.X_add_number < 0
> ! 			  && HAVE_64BIT_GPRS
> ! 			  && imm_expr.X_unsigned
> ! 			  && sizeof (imm_expr.X_add_number) <= 4))
>   		    {
>   		      if (more)
>   			break;
>   		      if (imm_expr.X_op == O_constant
>   			  || imm_expr.X_op == O_big)
> ! 			as_bad (_("16 bit expression not in range -32768..32767"));
>   		    }
>   		}
>   	      s = expr_end;
>   	      continue;
>   
>   	    case 'o':		/* 16 bit offset */
> ! 	      c = my_getSmallExpression (&offset_expr, s);
>   
>   	      /* If this value won't fit into a 16 bit offset, then go
>   		 find a macro that will generate the 32 bit offset
>   		 code pattern.  */
> ! 	      if (c == S_EX_NONE
>   		  && (offset_expr.X_op != O_constant
>   		      || offset_expr.X_add_number >= 0x8000
>   		      || offset_expr.X_add_number < -0x8000))
>   		break;
>   
> - 	      if (c == S_EX_HI)
> - 		{
> - 		  if (offset_expr.X_op != O_constant)
> - 		    break;
> - 		  offset_expr.X_add_number =
> - 		    (offset_expr.X_add_number >> 16) & 0xffff;
> - 		}
> - 	      *offset_reloc = BFD_RELOC_LO16;
>   	      s = expr_end;
>   	      continue;
>   
> --- 9033,9102 ----
>   	    case 'i':		/* 16 bit unsigned immediate */
>   	    case 'j':		/* 16 bit signed immediate */
>   	      *imm_reloc = BFD_RELOC_LO16;
> ! 	      if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0)
>   		{
>   		  int more;
> ! 		  offsetT minval, maxval;
>   
> ! 		  more = (insn + 1 < &mips_opcodes[NUMOPCODES]
> ! 			  && strcmp (insn->name, insn[1].name) == 0);
> ! 
> ! 		  /* If the expression was written as an unsigned number,
> ! 		     only treat it as signed if there are no more
> ! 		     alternatives.  */
> ! 		  if (more
> ! 		      && *args == 'j'
> ! 		      && sizeof (imm_expr.X_add_number) <= 4
> ! 		      && imm_expr.X_op == O_constant
> ! 		      && imm_expr.X_add_number < 0
> ! 		      && imm_expr.X_unsigned
> ! 		      && HAVE_64BIT_GPRS)
> ! 		    break;
> ! 
> ! 		  /* For compatibility with older assemblers, we accept
> ! 		     0x8000-0xffff as signed 16-bit numbers when only
> ! 		     signed numbers are allowed.  */
> ! 		  if (*args == 'i')
> ! 		    minval = 0, maxval = 0xffff;
> ! 		  else if (more)
> ! 		    minval = -0x8000, maxval = 0x7fff;
>   		  else
> ! 		    minval = -0x8000, maxval = 0xffff;
> ! 
> ! 		  if (imm_expr.X_op != O_constant
> ! 		      || imm_expr.X_add_number < minval
> ! 		      || imm_expr.X_add_number > maxval)
>   		    {
>   		      if (more)
>   			break;
>   		      if (imm_expr.X_op == O_constant
>   			  || imm_expr.X_op == O_big)
> ! 			as_bad (_("expression out of range"));
>   		    }
>   		}
>   	      s = expr_end;
>   	      continue;
>   
>   	    case 'o':		/* 16 bit offset */
> ! 	      /* Check whether there is only a single bracketed expression
> ! 		 left.  If so, it must be the base register and the
> ! 		 constant must be zero.  */
> ! 	      if (*s == '(' && strchr (s + 1, '(') == 0)
> ! 		{
> ! 		  offset_expr.X_op = O_constant;
> ! 		  offset_expr.X_add_number = 0;
> ! 		  continue;
> ! 		}
>   
>   	      /* If this value won't fit into a 16 bit offset, then go
>   		 find a macro that will generate the 32 bit offset
>   		 code pattern.  */
> ! 	      if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0
>   		  && (offset_expr.X_op != O_constant
>   		      || offset_expr.X_add_number >= 0x8000
>   		      || offset_expr.X_add_number < -0x8000))
>   		break;
>   
>   	      s = expr_end;
>   	      continue;
>   
> *************** mips_ip (str, ip)
> *** 9191,9239 ****
>   	      continue;
>   
>   	    case 'u':		/* upper 16 bits */
> ! 	      c = my_getSmallExpression (&imm_expr, s);
> ! 	      *imm_reloc = BFD_RELOC_LO16;
> ! 	      if (c != S_EX_NONE)
> ! 		{
> ! 		  if (c != S_EX_LO)
> ! 		    {
> ! 		      if (c == S_EX_HI)
> ! 			{
> ! 			  *imm_reloc = BFD_RELOC_HI16_S;
> ! 			  imm_unmatched_hi = TRUE;
> ! 			}
> ! #ifdef OBJ_ELF
> ! 		      else if (c == S_EX_HIGHEST)
> ! 			*imm_reloc = BFD_RELOC_MIPS_HIGHEST;
> ! 		      else if (c == S_EX_GP_REL)
> ! 			{
> ! 			  /* This occurs in NewABI only.  */
> ! 			  c = my_getSmallExpression (&imm_expr, s);
> ! 			  if (c != S_EX_NEG)
> ! 			    as_bad (_("bad composition of relocations"));
> ! 			  else
> ! 			    {
> ! 			      c = my_getSmallExpression (&imm_expr, s);
> ! 			      if (c != S_EX_HI)
> ! 				as_bad (_("bad composition of relocations"));
> ! 			      else
> ! 				{
> ! 				  imm_reloc[0] = BFD_RELOC_GPREL16;
> ! 				  imm_reloc[1] = BFD_RELOC_MIPS_SUB;
> ! 				  imm_reloc[2] = BFD_RELOC_HI16_S;
> ! 				}
> ! 			    }
> ! 			}
> ! #endif
> ! 		      else
> ! 			*imm_reloc = BFD_RELOC_HI16;
> ! 		    }
> ! 		  else if (imm_expr.X_op == O_constant)
> ! 		    imm_expr.X_add_number &= 0xffff;
> ! 		}
> ! 	      else if (imm_expr.X_op == O_constant
> ! 		       && (imm_expr.X_add_number < 0
> ! 			   || imm_expr.X_add_number >= 0x10000))
>   		as_bad (_("lui expression not in range 0..65535"));
>   	      s = expr_end;
>   	      continue;
> --- 9107,9116 ----
>   	      continue;
>   
>   	    case 'u':		/* upper 16 bits */
> ! 	      if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0
> ! 		  && imm_expr.X_op == O_constant
> ! 		  && (imm_expr.X_add_number < 0
> ! 		      || imm_expr.X_add_number >= 0x10000))
>   		as_bad (_("lui expression not in range 0..65535"));
>   	      s = expr_end;
>   	      continue;
> *************** mips16_immed (file, line, type, val, war
> *** 10070,10291 ****
>       }
>   }
>   
> ! static struct percent_op_match
>   {
> !    const char *str;
> !    const enum small_ex_type type;
>   } percent_op[] =
>   {
> !   {"%lo", S_EX_LO},
>   #ifdef OBJ_ELF
> !   {"%call_hi", S_EX_CALL_HI},
> !   {"%call_lo", S_EX_CALL_LO},
> !   {"%call16", S_EX_CALL16},
> !   {"%got_disp", S_EX_GOT_DISP},
> !   {"%got_page", S_EX_GOT_PAGE},
> !   {"%got_ofst", S_EX_GOT_OFST},
> !   {"%got_hi", S_EX_GOT_HI},
> !   {"%got_lo", S_EX_GOT_LO},
> !   {"%got", S_EX_GOT},
> !   {"%gp_rel", S_EX_GP_REL},
> !   {"%half", S_EX_HALF},
> !   {"%highest", S_EX_HIGHEST},
> !   {"%higher", S_EX_HIGHER},
> !   {"%neg", S_EX_NEG},
>   #endif
> !   {"%hi", S_EX_HI}
>   };
>   
> - /* Parse small expression input.  STR gets adjusted to eat up whitespace.
> -    It detects valid "%percent_op(...)" and "($reg)" strings.  Percent_op's
> -    can be nested, this is handled by blanking the innermost, parsing the
> -    rest by subsequent calls.  */
>   
> ! static int
> ! my_getSmallParser (str, len, nestlevel)
>        char **str;
> !      unsigned int *len;
> !      int *nestlevel;
>   {
> !   *len = 0;
> !   *str += strspn (*str, " \t");
> !   /* Check for expression in parentheses.  */
> !   if (**str == '(')
> !     {
> !       char *b = *str + 1 + strspn (*str + 1, " \t");
> !       char *e;
> ! 
> !       /* Check for base register.  */
> !       if (b[0] == '$')
> ! 	{
> ! 	  if (strchr (b, ')')
> ! 	      && (e = b + strcspn (b, ") \t"))
> ! 	      && e - b > 1 && e - b < 4)
> ! 	    {
> ! 	      if ((e - b == 3
> ! 		   && ((b[1] == 'f' && b[2] == 'p')
> ! 		       || (b[1] == 's' && b[2] == 'p')
> ! 		       || (b[1] == 'g' && b[2] == 'p')
> ! 		       || (b[1] == 'a' && b[2] == 't')
> ! 		       || (ISDIGIT (b[1])
> ! 			   && ISDIGIT (b[2]))))
> ! 		  || (ISDIGIT (b[1])))
> ! 		{
> ! 		  *len = strcspn (*str, ")") + 1;
> ! 		  return S_EX_REGISTER;
> ! 		}
> ! 	    }
> ! 	}
> !       /* Check for percent_op (in parentheses).  */
> !       else if (b[0] == '%')
> ! 	{
> ! 	  *str = b;
> ! 	  return my_getPercentOp (str, len, nestlevel);
> ! 	}
>   
> !       /* Some other expression in the parentheses, which can contain
> ! 	 parentheses itself. Attempt to find the matching one.  */
>         {
> ! 	int pcnt = 1;
> ! 	char *s;
>   
> ! 	*len = 1;
> ! 	for (s = *str + 1; *s && pcnt; s++, (*len)++)
>   	  {
> ! 	    if (*s == '(')
> ! 	      ++pcnt;
> ! 	    else if (*s == ')')
> ! 	      --pcnt;
>   	  }
>         }
> !     }
> !   /* Check for percent_op (outside of parentheses).  */
> !   else if (*str[0] == '%')
> !     return my_getPercentOp (str, len, nestlevel);
> ! 
> !   /* Any other expression.  */
> !   return S_EX_NONE;
>   }
>   
> - static int
> - my_getPercentOp (str, len, nestlevel)
> -      char **str;
> -      unsigned int *len;
> -      int *nestlevel;
> - {
> -   char *tmp = *str + 1;
> -   unsigned int i = 0;
>   
> !   while (ISALPHA (*tmp) || *tmp == '_')
> !     {
> !       *tmp = TOLOWER (*tmp);
> !       tmp++;
> !     }
> !   while (i < (sizeof (percent_op) / sizeof (struct percent_op_match)))
> !     {
> !       if (strncmp (*str, percent_op[i].str, strlen (percent_op[i].str)))
> ! 	i++;
> !       else
> ! 	{
> ! 	  int type = percent_op[i].type;
> ! 
> ! 	  /* Only %hi and %lo are allowed for OldABI.  */
> ! 	  if (! HAVE_NEWABI && type != S_EX_HI && type != S_EX_LO)
> ! 	    return S_EX_NONE;
>   
> ! 	  *len = strlen (percent_op[i].str);
> ! 	  ++(*nestlevel);
> ! 	  return type;
> ! 	}
> !     }
> !   return S_EX_NONE;
> ! }
>   
> ! static int
> ! my_getSmallExpression (ep, str)
>        expressionS *ep;
>        char *str;
>   {
> !   static char *oldstr = NULL;
> !   int c = S_EX_NONE;
> !   int oldc;
> !   int nestlevel = -1;
> !   unsigned int len;
>   
> !   /* Don't update oldstr if the last call had nested percent_op's. We need
> !      it to parse the outer ones later.  */
> !   if (! oldstr)
> !     oldstr = str;
>   
> !   do
>       {
> !       oldc = c;
> !       c = my_getSmallParser (&str, &len, &nestlevel);
> !       if (c != S_EX_NONE && c != S_EX_REGISTER)
> ! 	str += len;
>       }
> -   while (c != S_EX_NONE && c != S_EX_REGISTER);
> - 
> -   if (nestlevel >= 0)
> -     {
> -       /* A percent_op was encountered.  Don't try to get an expression if
> - 	 it is already blanked out.  */
> -       if (*(str + strspn (str + 1, " )")) != ')')
> - 	{
> - 	  char save;
>   
> ! 	  /* Let my_getExpression() stop at the closing parenthesis.  */
> ! 	  save = *(str + len);
> ! 	  *(str + len) = '\0';
> ! 	  my_getExpression (ep, str);
> ! 	  *(str + len) = save;
> ! 	}
> !       if (nestlevel > 0)
> ! 	{
> ! 	  /* Blank out including the % sign and the proper matching
> ! 	     parenthesis.  */
> ! 	  int pcnt = 1;
> ! 	  char *s = strrchr (oldstr, '%');
> ! 	  char *end;
>   
> ! 	  for (end = strchr (s, '(') + 1; *end && pcnt; end++)
> ! 	    {
> ! 	      if (*end == '(')
> ! 		++pcnt;
> ! 	      else if (*end == ')')
> ! 		--pcnt;
> ! 	    }
>   
> ! 	  memset (s, ' ', end - s);
> ! 	  str = oldstr;
> ! 	}
> !       else
> ! 	expr_end = str + len;
>   
> !       c = oldc;
> !     }
> !   else if (c == S_EX_NONE)
> !     {
> !       my_getExpression (ep, str);
> !     }
> !   else if (c == S_EX_REGISTER)
> !     {
> !       ep->X_op = O_constant;
> !       expr_end = str;
> !       ep->X_add_symbol = NULL;
> !       ep->X_op_symbol = NULL;
> !       ep->X_add_number = 0;
> !     }
> !   else
> !     {
> !       as_fatal (_("internal error"));
> !     }
>   
> !   if (nestlevel <= 0)
> !     /* All percent_op's have been handled.  */
> !     oldstr = NULL;
>   
> !   return c;
>   }
>   
>   static void
> --- 9947,10064 ----
>       }
>   }
>   
> ! static const struct percent_op_match
>   {
> !   const char *str;
> !   bfd_reloc_code_real_type reloc;
>   } percent_op[] =
>   {
> !   {"%lo", BFD_RELOC_LO16},
>   #ifdef OBJ_ELF
> !   {"%call_hi", BFD_RELOC_MIPS_CALL_HI16},
> !   {"%call_lo", BFD_RELOC_MIPS_CALL_LO16},
> !   {"%call16", BFD_RELOC_MIPS_CALL16},
> !   {"%got_disp", BFD_RELOC_MIPS_GOT_DISP},
> !   {"%got_page", BFD_RELOC_MIPS_GOT_PAGE},
> !   {"%got_ofst", BFD_RELOC_MIPS_GOT_OFST},
> !   {"%got_hi", BFD_RELOC_MIPS_GOT_HI16},
> !   {"%got_lo", BFD_RELOC_MIPS_GOT_LO16},
> !   {"%got", BFD_RELOC_MIPS_GOT16},
> !   {"%gp_rel", BFD_RELOC_GPREL16},
> !   {"%half", BFD_RELOC_16},
> !   {"%highest", BFD_RELOC_MIPS_HIGHEST},
> !   {"%higher", BFD_RELOC_MIPS_HIGHER},
> !   {"%neg", BFD_RELOC_MIPS_SUB},
>   #endif
> !   {"%hi", BFD_RELOC_HI16_S}
>   };
>   
>   
> ! /* Return true if *STR points to a relocation operator.  When returning true,
> !    move *STR over the operator and store its relocation code in *RELOC.
> !    Leave both *STR and *RELOC alone when returning false.  */
> ! 
> ! static bfd_boolean
> ! parse_relocation (str, reloc)
>        char **str;
> !      bfd_reloc_code_real_type *reloc;
>   {
> !   size_t i;
>   
> !   for (i = 0; i < ARRAY_SIZE (percent_op); i++)
> !     if (strncasecmp (*str, percent_op[i].str, strlen (percent_op[i].str)) == 0)
>         {
> ! 	*str += strlen (percent_op[i].str);
> ! 	*reloc = percent_op[i].reloc;
>   
> ! 	/* Check whether the output BFD supports this relocation.
> ! 	   If not, issue an error and fall back on something safe.  */
> ! 	if (!bfd_reloc_type_lookup (stdoutput, percent_op[i].reloc))
>   	  {
> ! 	    as_bad ("relocation %s isn't supported by the current ABI",
> ! 		    percent_op[i].str);
> ! 	    *reloc = BFD_RELOC_LO16;
>   	  }
> + 	return TRUE;
>         }
> !   return FALSE;
>   }
>   
>   
> ! /* Parse string STR as a 16-bit relocatable operand.  Store the
> !    expression in *EP and the relocations in the array starting
> !    at RELOC.  Return the number of relocation operators used.
>   
> !    On exit, EXPR_END points to the first character after the expression.
> !    If no relocation operators are used, RELOC[0] is set to BFD_RELOC_LO16.  */
>   
> ! static size_t
> ! my_getSmallExpression (ep, reloc, str)
>        expressionS *ep;
> +      bfd_reloc_code_real_type *reloc;
>        char *str;
>   {
> !   bfd_reloc_code_real_type reversed_reloc[3];
> !   size_t reloc_index, i;
> !   int bracket_depth;
>   
> !   reloc_index = 0;
> !   bracket_depth = 0;
>   
> !   /* Search for the start of the main expression, recoding relocations
> !      in REVERSED_RELOC.  */
> !   for (;;)
>       {
> !       if (*str == '(')
> ! 	bracket_depth++, str++;
> !       else if (*str == ' ' || *str == '\t')
> ! 	str++;
> !       else if (*str == '%'
> ! 	       && reloc_index < (HAVE_NEWABI ? 3 : 1)
> ! 	       && parse_relocation (&str, &reversed_reloc[reloc_index]))
> ! 	reloc_index++;
> !       else
> ! 	break;
>       }
>   
> !   my_getExpression (ep, str);
> !   str = expr_end;
>   
> !   /* Match every open bracket.  */
> !   while (bracket_depth > 0 && (*str == ')' || *str == ' ' || *str == '\t'))
> !     if (*str++ == ')')
> !       bracket_depth--;
>   
> !   if (bracket_depth > 0)
> !     as_bad ("unclosed '('");
>   
> !   expr_end = str;
>   
> !   reloc[0] = BFD_RELOC_LO16;
> !   for (i = 0; i < reloc_index; i++)
> !     reloc[i] = reversed_reloc[reloc_index - 1 - i];
>   
> !   return reloc_index;
>   }
>   
>   static void
> Index: testsuite/gas/mips/mips.exp
> ===================================================================
> RCS file: /cvs/src/src/gas/testsuite/gas/mips/mips.exp,v
> retrieving revision 1.57
> diff -c -d -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.57 mips.exp
> *** testsuite/gas/mips/mips.exp	31 Dec 2002 08:11:17 -0000	1.57
> --- testsuite/gas/mips/mips.exp	26 Jan 2003 12:09:08 -0000
> *************** if { [istarget mips*-*-*] } then {
> *** 376,381 ****
> --- 376,383 ----
>       set ilocks [istarget mipstx39*-*-*]
>       set gpr_ilocks [expr [istarget mipstx39*-*-*]]
>       set addr32 [expr [istarget mipstx39*-*-*]]
> +     set have_newabi [expr [istarget mips-*-irix6*] \
> + 			  || [istarget mips64*-*-linux*]]
>   
>       if { [istarget "mips*-*-*linux*"] } then {
>   	set tmips "t"
> *************** if { [istarget mips*-*-*] } then {
> *** 601,606 ****
> --- 603,614 ----
>   	run_dump_test "elf-rel5"
>   	run_dump_test "elf-rel6"
>   	run_dump_test "elf-rel7"
> + 	run_dump_test "elf-rel8"
> + 	run_dump_test "elf-rel9"
> + 	if {$have_newabi} {
> + 	    run_dump_test "elf-rel10"
> + 	    run_dump_test "elf-rel11"
> + 	}
>   	run_dump_test "${tmips}${el}empic"
>   	run_dump_test "empic2"
>   	run_dump_test "empic3_e"
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel8.d	Sat Jan 25 15:32:10 2003
> ***************
> *** 0 ****
> --- 1,57 ----
> + #as: -march=mips2 -mabi=32
> + #objdump: -M gpr-names=numeric -dr
> + #name: MIPS ELF reloc 8
> + 
> + .*:     file format .*
> + 
> + Disassembly of section \.text:
> + 
> + 0+00 <foo>:
> +    0:	3c040000 	lui	\$4,0x0
> + 			0: R_MIPS_HI16	gvar
> +    4:	24840000 	addiu	\$4,\$4,0
> + 			4: R_MIPS_LO16	gvar
> +    8:	8ca40000 	lw	\$4,0\(\$5\)
> + 			8: R_MIPS_LO16	gvar
> +    c:	8fc40002 	lw	\$4,2\(\$30\)
> +   10:	3c040000 	lui	\$4,0x0
> + 			10: R_MIPS_CALL_HI16	gfunc
> +   14:	009c2021 	addu	\$4,\$4,\$28
> +   18:	8c990000 	lw	\$25,0\(\$4\)
> + 			18: R_MIPS_CALL_LO16	gfunc
> +   1c:	3c040000 	lui	\$4,0x0
> + 			1c: R_MIPS_GOT_HI16	gvar
> +   20:	009c2021 	addu	\$4,\$4,\$28
> +   24:	8c850000 	lw	\$5,0\(\$4\)
> + 			24: R_MIPS_GOT_LO16	gvar
> +   28:	8f840000 	lw	\$4,0\(\$28\)
> + 			28: R_MIPS_GOT16	\.data
> +   2c:	a0850000 	sb	\$5,0\(\$4\)
> + 			2c: R_MIPS_LO16	\.data
> +   30:	3c040000 	lui	\$4,0x0
> + 			30: R_MIPS_CALL_HI16	gfunc
> +   34:	24840000 	addiu	\$4,\$4,0
> + 			34: R_MIPS_CALL_LO16	gfunc
> +   38:	3c040000 	lui	\$4,0x0
> + 			38: R_MIPS_GOT_HI16	gvar
> +   3c:	24840000 	addiu	\$4,\$4,0
> + 			3c: R_MIPS_GOT_LO16	gvar
> +   40:	8f840000 	lw	\$4,0\(\$28\)
> + 			40: R_MIPS_GOT16	\.data
> +   44:	24840000 	addiu	\$4,\$4,0
> + 			44: R_MIPS_LO16	\.data
> +   48:	8f990000 	lw	\$25,0\(\$28\)
> + 			48: R_MIPS_CALL16	gfunc
> +   4c:	27840000 	addiu	\$4,\$28,0
> + 			4c: R_MIPS_CALL16	gfunc
> +   50:	8f840000 	lw	\$4,0\(\$28\)
> + 			50: R_MIPS_GOT_DISP	gvar
> +   54:	27840000 	addiu	\$4,\$28,0
> + 			54: R_MIPS_GOT_DISP	gvar
> +   58:	8f840000 	lw	\$4,0\(\$28\)
> + 			58: R_MIPS_GPREL16	gvar
> +   5c:	af840000 	sw	\$4,0\(\$28\)
> + 			5c: R_MIPS_GPREL16	gvar
> +   60:	27840000 	addiu	\$4,\$28,0
> + 			60: R_MIPS_GPREL16	gvar
> + 	\.\.\.
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel8.s	Sat Jan 25 17:01:55 2003
> ***************
> *** 0 ****
> --- 1,53 ----
> + 	.equ	$fprel, 2
> + 
> + 	.ent	foo
> + foo:
> + 	# Test various forms of relocation syntax.
> + 
> + 	lui	$4,(%hi gvar)
> + 	addiu	$4,$4,(%lo (gvar))
> + 	lw	$4,%lo gvar($5)
> + 
> + 	# Check that registers aren't confused with $ identifiers.
> + 
> + 	lw	$4,($fprel)($fp)
> + 
> + 	# Check various forms of paired relocations.
> + 
> + 	lui	$4,%call_hi(gfunc)
> + 	addu	$4,$4,$gp
> + 	lw	$25,%call_lo(gfunc)($4)
> + 
> + 	lui	$4,%got_hi(gvar)
> + 	addu	$4,$4,$gp
> + 	lw	$5,%got_lo(gvar)($4)
> + 
> + 	lw	$4,%got(lvar)($28)
> + 	sb	$5,%lo(lvar)($4)
> + 
> + 	lui	$4,%call_hi(gfunc)
> + 	addiu	$4,$4,%call_lo(gfunc)
> + 
> + 	lui	$4,%got_hi(gvar)
> + 	addiu	$4,$4,%got_lo(gvar)
> + 
> + 	lw	$4,%got(lvar)($28)
> + 	addiu	$4,$4,%lo(lvar)
> + 
> + 	# Check individual relocations.
> + 
> + 	lw	$25,%call16(gfunc)($28)
> + 	addiu	$4,$28,%call16(gfunc)
> + 
> + 	lw	$4,%got_disp(gvar)($28)
> + 	addiu	$4,$28,%got_disp(gvar)
> + 
> + 	lw	$4,%gp_rel(gvar)($28)
> + 	sw	$4,%gp_rel(gvar)($28)
> + 	addiu	$4,$28,%gp_rel(gvar)
> + 
> + 	.space	64
> + 	.end	foo
> + 
> + 	.data
> + lvar:	.word	1,2
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel9.d	Sat Jan 25 15:31:55 2003
> ***************
> *** 0 ****
> --- 1,68 ----
> + #as: -march=mips2 -mabi=32
> + #objdump: -M gpr-names=numeric -dr
> + #name: MIPS ELF reloc 9
> + 
> + .*:     file format .*
> + 
> + Disassembly of section \.text:
> + 
> + 0+00 <foo>:
> +    0:	8f840000 	lw	\$4,0\(\$28\)
> + 			0: R_MIPS_GOT16	\.data
> +    4:	24840010 	addiu	\$4,\$4,16
> + 			4: R_MIPS_LO16	\.data
> +    8:	8f840000 	lw	\$4,0\(\$28\)
> + 			8: R_MIPS_GOT16	\.data
> +    c:	24840020 	addiu	\$4,\$4,32
> + 			c: R_MIPS_LO16	\.data
> +   10:	8f840000 	lw	\$4,0\(\$28\)
> + 			10: R_MIPS_GOT16	\.data
> +   14:	24847ffc 	addiu	\$4,\$4,32764
> + 			14: R_MIPS_LO16	\.data
> +   18:	8f840001 	lw	\$4,1\(\$28\)
> + 			18: R_MIPS_GOT16	\.data
> +   1c:	24848000 	addiu	\$4,\$4,-32768
> + 			1c: R_MIPS_LO16	\.data
> +   20:	8f840001 	lw	\$4,1\(\$28\)
> + 			20: R_MIPS_GOT16	\.data
> +   24:	2484fffc 	addiu	\$4,\$4,-4
> + 			24: R_MIPS_LO16	\.data
> +   28:	8f840001 	lw	\$4,1\(\$28\)
> + 			28: R_MIPS_GOT16	\.data
> +   2c:	24840000 	addiu	\$4,\$4,0
> + 			2c: R_MIPS_LO16	\.data
> +   30:	8f840002 	lw	\$4,2\(\$28\)
> + 			30: R_MIPS_GOT16	\.data
> +   34:	24848010 	addiu	\$4,\$4,-32752
> + 			34: R_MIPS_LO16	\.data
> +   38:	8f840002 	lw	\$4,2\(\$28\)
> + 			38: R_MIPS_GOT16	\.data
> +   3c:	2484f000 	addiu	\$4,\$4,-4096
> + 			3c: R_MIPS_LO16	\.data
> +   40:	8f840002 	lw	\$4,2\(\$28\)
> + 			40: R_MIPS_GOT16	\.data
> +   44:	2484ffff 	addiu	\$4,\$4,-1
> + 			44: R_MIPS_LO16	\.data
> +   48:	8f840002 	lw	\$4,2\(\$28\)
> + 			48: R_MIPS_GOT16	\.data
> +   4c:	2484f100 	addiu	\$4,\$4,-3840
> + 			4c: R_MIPS_LO16	\.data
> +   50:	8f840003 	lw	\$4,3\(\$28\)
> + 			50: R_MIPS_GOT16	\.data
> +   54:	24841345 	addiu	\$4,\$4,4933
> + 			54: R_MIPS_LO16	\.data
> +   58:	8f84c000 	lw	\$4,-16384\(\$28\)
> + 			58: R_MIPS_GPREL16	\.sdata\+0x4000
> +   5c:	8f84c004 	lw	\$4,-16380\(\$28\)
> + 			5c: R_MIPS_GPREL16	\.sdata\+0x4000
> +   60:	8f84c004 	lw	\$4,-16380\(\$28\)
> + 			60: R_MIPS_GPREL16	\.sdata\+0x4000
> +   64:	8f84c008 	lw	\$4,-16376\(\$28\)
> + 			64: R_MIPS_GPREL16	\.sdata\+0x4000
> +   68:	8f84c00c 	lw	\$4,-16372\(\$28\)
> + 			68: R_MIPS_GPREL16	\.sdata\+0x4000
> +   6c:	8f84c014 	lw	\$4,-16364\(\$28\)
> + 			6c: R_MIPS_GPREL16	\.sdata\+0x4000
> +   70:	8f84c018 	lw	\$4,-16360\(\$28\)
> + 			70: R_MIPS_GPREL16	\.sdata\+0x4000
> + 	\.\.\.
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel9.s	Sat Jan 25 14:42:36 2003
> ***************
> *** 0 ****
> --- 1,57 ----
> + 	.ent	foo
> + foo:
> + 	lw	$4,%got(l1)($28)
> + 	addiu	$4,$4,%lo(l1)
> + 
> + 	lw	$4,%got(l1 + 16)($28)
> + 	addiu	$4,$4,%lo(l1 + 16)
> + 
> + 	lw	$4,%got(l1 + 0x7fec)($28)
> + 	addiu	$4,$4,%lo(l1 + 0x7fec)
> + 
> + 	lw	$4,%got(l1 + 0x7ff0)($28)
> + 	addiu	$4,$4,%lo(l1 + 0x7ff0)
> + 
> + 	lw	$4,%got(l1 + 0xffec)($28)
> + 	addiu	$4,$4,%lo(l1 + 0xffec)
> + 
> + 	lw	$4,%got(l1 + 0xfff0)($28)
> + 	addiu	$4,$4,%lo(l1 + 0xfff0)
> + 
> + 	lw	$4,%got(l1 + 0x18000)($28)
> + 	addiu	$4,$4,%lo(l1 + 0x18000)
> + 
> + 	lw	$4,%got(l2)($28)
> + 	addiu	$4,$4,%lo(l2)
> + 
> + 	lw	$4,%got(l2 + 0xfff)($28)
> + 	addiu	$4,$4,%lo(l2 + 0xfff)
> + 
> + 	lw	$4,%got(l2 + 0x1000)($28)
> + 	addiu	$4,$4,%lo(l2 + 0x100)
> + 
> + 	lw	$4,%got(l2 + 0x12345)($28)
> + 	addiu	$4,$4,%lo(l2 + 0x12345)
> + 
> + 	lw	$4,%gp_rel(l3)($28)
> + 	lw	$4,%gp_rel(l3 + 4)($28)
> + 	lw	$4,%gp_rel(l4)($28)
> + 	lw	$4,%gp_rel(l4 + 4)($28)
> + 	lw	$4,%gp_rel(l5)($28)
> + 	lw	$4,%gp_rel(l5 + 8)($28)
> + 	lw	$4,%gp_rel(l5 + 12)($28)
> + 
> + 	.space	64
> + 	.end	foo
> + 
> + 	.data
> + 	.word	1,2,3,4
> + l1:	.word	4,5
> + 	.space	0x1f000 - 24
> + l2:	.word	7,8
> + 
> + 	.sdata
> + l3:	.word	1
> + l4:	.word	2
> + 	.word	3
> + l5:	.word	4
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel10.d	Sat Jan 25 20:29:39 2003
> ***************
> *** 0 ****
> --- 1,29 ----
> + #as: -march=mips3 -mabi=n32 -KPIC
> + #readelf: --relocs
> + #name: MIPS ELF reloc 10
> + 
> + Relocation section '\.rela\.text' at offset .* contains 22 entries:
> +  *Offset * Info * Type * Sym\.Value * Sym\. Name \+ Addend
> + 0+0000 * 0+..07 * R_MIPS_GPREL16 * 0+0000 * foo \+ 0
> + 0+0000 * 0+0018 * R_MIPS_SUB * 0+0000
> + 0+0000 * 0+0005 * R_MIPS_HI16 * 0+0000
> + 0+0004 * 0+..07 * R_MIPS_GPREL16 * 0+0000 * foo \+ 0
> + 0+0004 * 0+0018 * R_MIPS_SUB * 0+0000
> + 0+0004 * 0+0006 * R_MIPS_LO16 * 0+0000
> + 0+000c * 0+..07 * R_MIPS_GPREL16 * 0+0000 * \.text \+ c
> + 0+000c * 0+0018 * R_MIPS_SUB * 0+0000
> + 0+000c * 0+0005 * R_MIPS_HI16 * 0+0000
> + 0+0010 * 0+..07 * R_MIPS_GPREL16 * 0+0000 * \.text \+ c
> + 0+0010 * 0+0018 * R_MIPS_SUB * 0+0000
> + 0+0010 * 0+0006 * R_MIPS_LO16 * 0+0000
> + 0+0018 * 0+..14 * R_MIPS_GOT_PAGE * 0+0000 * foo \+ 0
> + 0+001c * 0+..15 * R_MIPS_GOT_OFST * 0+0000 * foo \+ 0
> + 0+0020 * 0+..14 * R_MIPS_GOT_PAGE * 0+0000 * foo \+ 1234
> + 0+0024 * 0+..15 * R_MIPS_GOT_OFST * 0+0000 * foo \+ 1234
> + 0+0028 * 0+..14 * R_MIPS_GOT_PAGE * 0+0000 * \.text \+ c
> + 0+002c * 0+..15 * R_MIPS_GOT_OFST * 0+0000 * \.text \+ c
> + 0+0030 * 0+..14 * R_MIPS_GOT_PAGE * 0+0000 * \.text \+ 33221d
> + 0+0034 * 0+..15 * R_MIPS_GOT_OFST * 0+0000 * \.text \+ 33221d
> + 0+0038 * 0+..14 * R_MIPS_GOT_PAGE * 0+0000 * frob \+ 0
> + 0+003c * 0+..15 * R_MIPS_GOT_OFST * 0+0000 * frob \+ 0
> + #pass
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel10.s	Sat Jan 25 17:13:28 2003
> ***************
> *** 0 ****
> --- 1,31 ----
> + 	.globl	foo
> + 	.ent	foo
> + foo:
> + 	lui	$gp,%hi(%neg(%gp_rel(foo)))
> + 	addiu	$gp,$gp,%lo(%neg(%gp_rel(foo)))
> + 	daddu	$gp,$gp,$25
> + 	.end	foo
> + 
> + 	.ent	bar
> + bar:
> + 	lui	$gp,%hi(%neg(%gp_rel(bar)))
> + 	addiu	$gp,$gp,%lo(%neg(%gp_rel(bar)))
> + 	daddu	$gp,$gp,$25
> + 	.end	bar
> + 
> + 	.ent	frob
> + 	lw	$4,%got_page(foo)($gp)
> + 	addiu	$4,$4,%got_ofst(foo)
> + 
> + 	lw	$4,%got_page(foo + 0x1234)($gp)
> + 	addiu	$4,$4,%got_ofst(foo + 0x1234)
> + 
> + 	lw	$4,%got_page(bar)($gp)
> + 	addiu	$4,$4,%got_ofst(bar)
> + 
> + 	lw	$4,%got_page(bar + 0x332211)($gp)
> + 	addiu	$4,$4,%got_ofst(bar + 0x332211)
> + 
> + 	lw	$4,%got_page(frob)($gp)
> + 	addiu	$4,$4,%got_ofst(frob)
> + 	.end	frob
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel11.d	Sat Jan 25 21:54:02 2003
> ***************
> *** 0 ****
> --- 1,43 ----
> + #as: -march=mips3 -mabi=64
> + #readelf: --relocs
> + #name: MIPS ELF reloc 11
> + 
> + Relocation section '\.rela\.text' at offset .* contains 12 entries:
> +  *Offset * Info * Type * Sym\. Value * Sym\. Name \+ Addend
> + 0+0000 * 0+..0000001d * R_MIPS_HIGHEST * 0+0000 * bar \+ 0
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0008 * 0+..0000001c * R_MIPS_HIGHER * 0+0000 * bar \+ 0
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0004 * 0+..00000005 * R_MIPS_HI16 * 0+0000 * bar \+ 0
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+000c * 0+..00000006 * R_MIPS_LO16 * 0+0000 * bar \+ 0
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0018 * 0+..0000001d * R_MIPS_HIGHEST * 0+0000 * bar \+ 12345678
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0020 * 0+..0000001c * R_MIPS_HIGHER * 0+0000 * bar \+ 12345678
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+001c * 0+..00000005 * R_MIPS_HI16 * 0+0000 * bar \+ 12345678
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0024 * 0+..00000006 * R_MIPS_LO16 * 0+0000 * bar \+ 12345678
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0030 * 0+..0000001d * R_MIPS_HIGHEST * 0+0000 * \.data \+ 10
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0034 * 0+..0000001c * R_MIPS_HIGHER * 0+0000 * \.data \+ 10
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+003c * 0+..00000005 * R_MIPS_HI16 * 0+0000 * \.data \+ 10
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + 0+0044 * 0+..00000006 * R_MIPS_LO16 * 0+0000 * \.data \+ 10
> +  * Type2: R_MIPS_NONE *
> +  * Type3: R_MIPS_NONE *
> + #pass
> *** /dev/null	Thu Apr 11 15:25:15 2002
> --- testsuite/gas/mips/elf-rel11.s	Sat Jan 25 21:07:29 2003
> ***************
> *** 0 ****
> --- 1,27 ----
> + 	.ent	foo
> + foo:
> + 	lui	$4,%highest(bar)
> + 	lui	$5,%hi(bar)
> + 	daddiu	$4,$4,%higher(bar)
> + 	daddiu	$5,$5,%lo(bar)
> + 	dsll32	$4,$4,0
> + 	daddu	$4,$4,$5
> + 
> + 	lui	$4,%highest(bar + 0x12345678)
> + 	lui	$5,%hi(bar + 0x12345678)
> + 	daddiu	$4,$4,%higher(bar + 0x12345678)
> + 	daddiu	$5,$5,%lo(bar + 0x12345678)
> + 	dsll32	$4,$4,0
> + 	daddu	$4,$4,$5
> + 
> + 	lui	$4,%highest(l1)
> + 	daddiu	$4,$4,%higher(l1)
> + 	dsll	$4,$4,16
> + 	daddiu	$4,$4,%hi(l1)
> + 	dsll	$4,$4,16
> + 	lw	$4,%lo(l1)($4)
> + 	.end	foo
> + 
> + 	.data
> + 	.word	1,2,3,4
> + l1:	.word	4,5
-- 
Strapping on the jetpack...



More information about the Binutils mailing list