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]

new alpha branch reloc


This is a feature that's been bubbling through my head for a while.

In the normal alpha calling sequence, $27 must be loaded with the
address of the called function, so that the function can easily
compute its $gp.  Within a single object file, the compiler knows
how to skip the redundant gp load by jumping past the computation.
It does this by setting up a separate symbol $foo..ng for every
function foo.

Between two object files, the compiler normally assumes that the
gp may differ, and so the full $27 load sequence is used.  In the
cases in which the gp happens to be the same this can be optimized
by linker relaxation, but we end up leaving nops in insn stream.

Specific applications (such as a kernel) may know that they will
never be (or must never be) large enough to require multiple gps
in the main body, but may in fact require gps for loaded modules.

Now, you can't simply emit a direct branch to a function because
the gp load is still there for the benefit of the module.  So 
how to get the branch past the gp load?

One solution would be to make the $foo..ng symbol global whenever
the foo symbol is global.  That seemed somewhat less than ideal.

The solution taken here is to have a special branch relocation that
takes care to adjust the destination address past the gp load.  It
also verifies that the gps for the two object files is the same,
which prevents any unwanted surprises.


r~


bfd/
+ 	* elf64-alpha.c (elf64_alpha_howto): Add R_ALPHA_BRSGP.
+ 	(elf64_alpha_reloc_map, elf64_alpha_check_relocs): Likewise.
+ 	(elf64_alpha_relocate_section): Likewise.
+ 	* reloc.c (BFD_RELOC_ALPHA_BRSGP): New.
+ 	* bfd-in2.h, libbfd.h: Rebuild.
  
gas/
+ 	* config/tc-alpha.c (O_samegp): New.
+ 	(USER_RELOC_P): Include it.
+ 	(alpha_reloc_op_tag, debug_exp, find_macro_match): Add it.
+ 	(md_apply_fix3): Handle BFD_RELOC_ALPHA_BRSGP.
+ 	(alpha_force_relocation, alpha_fix_adjustable): Likewise.
+ 	(alpha_validate_fix): New.
+ 	* config/tc-alpha.h (TC_VALIDATE_FIX): New.
  
gas/testsuite/
+ 	* gas/alpha/elf-reloc-5.s, gas/alpha/elf-reloc-5.d: New.
+ 	* gas/alpha/elf-reloc-6.s, gas/alpha/elf-reloc-6.l: New.
+ 	* gas/alpha/alpha.exp: Run them.
  
include/elf/
+ 	* alpha.h (R_ALPHA_BRSGP): New.
  
Index: bfd/elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.55
diff -c -p -d -r1.55 elf64-alpha.c
*** elf64-alpha.c	2002/01/26 08:41:30	1.55
--- elf64-alpha.c	2002/02/09 22:52:36
*************** static reloc_howto_type elf64_alpha_howt
*** 732,738 ****
  	 false,
  	 0,
  	 0,
! 	 true)
  };
  
  /* A relocation function which doesn't do anything.  */
--- 732,753 ----
  	 false,
  	 0,
  	 0,
! 	 true),
! 
!   /* A 21 bit branch that adjusts for gp loads.  */
!   HOWTO (R_ALPHA_BRSGP,		/* type */
! 	 2,			/* rightshift */
! 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
! 	 21,			/* bitsize */
! 	 true,			/* pc_relative */
! 	 0,			/* bitpos */
! 	 complain_overflow_signed, /* complain_on_overflow */
! 	 0,			/* special_function */
! 	 "BRSGP",		/* name */
! 	 false,			/* partial_inplace */
! 	 0x1fffff,		/* src_mask */
! 	 0x1fffff,		/* dst_mask */
! 	 true),			/* pcrel_offset */
  };
  
  /* A relocation function which doesn't do anything.  */
*************** static const struct elf_reloc_map elf64_
*** 886,891 ****
--- 901,907 ----
    {BFD_RELOC_ALPHA_GPREL_HI16,		R_ALPHA_GPRELHIGH},
    {BFD_RELOC_ALPHA_GPREL_LO16,		R_ALPHA_GPRELLOW},
    {BFD_RELOC_GPREL16,			R_ALPHA_GPREL16},
+   {BFD_RELOC_ALPHA_BRSGP,		R_ALPHA_BRSGP},
  };
  
  /* Given a BFD reloc type, return a HOWTO structure.  */
*************** elf64_alpha_check_relocs (abfd, info, se
*** 2414,2419 ****
--- 2430,2436 ----
  	case R_ALPHA_GPREL32:
  	case R_ALPHA_GPRELHIGH:
  	case R_ALPHA_GPRELLOW:
+ 	case R_ALPHA_BRSGP:
  	  /* We don't actually use the .got here, but the sections must
  	     be created before the linker maps input sections to output
  	     sections.  */
*************** elf64_alpha_relocate_section (output_bfd
*** 3554,3559 ****
--- 3571,3640 ----
  	     the instruction rather than the end.  */
  	  addend -= 4;
  	  goto default_reloc;
+ 
+ 	case R_ALPHA_BRSGP:
+ 	  {
+ 	    int other;
+ 	    const char *name;
+ 
+ 	    /* The regular PC-relative stuff measures from the start of
+ 	       the instruction rather than the end.  */
+ 	    addend -= 4;
+ 
+ 	    /* The source and destination gp must be the same.  */
+ 	    if (h != NULL
+ 		&& gotobj != alpha_elf_tdata (sec->owner)->gotobj)
+ 	      {
+ 		if (h != NULL)
+ 		  name = h->root.root.root.string;
+ 		else
+ 		  {
+ 		    name = (bfd_elf_string_from_elf_section
+ 			    (input_bfd, symtab_hdr->sh_link, sym->st_name));
+ 		    if (name == NULL)
+ 		      name = _("<unknown>");
+ 		    else if (name[0] == 0)
+ 		      name = bfd_section_name (input_bfd, sec);
+ 		  }
+ 		(*_bfd_error_handler)
+ 		  (_("%s: change in gp: BRSGP %s"),
+ 		   bfd_archive_filename (input_bfd), name);
+ 		ret_val = false;
+ 	      }
+ 
+ 	    /* The symbol should be marked either NOPV or STD_GPLOAD.  */
+ 	    if (h != NULL)
+ 	      other = h->root.other;
+ 	    else
+ 	      other = sym->st_other;
+ 	    switch (other & STO_ALPHA_STD_GPLOAD)
+ 	      {
+ 	      case STO_ALPHA_NOPV:
+ 	        break;
+ 	      case STO_ALPHA_STD_GPLOAD:
+ 		addend += 8;
+ 		break;
+ 	      default:
+ 		if (h != NULL)
+ 		  name = h->root.root.root.string;
+ 		else
+ 		  {
+ 		    name = (bfd_elf_string_from_elf_section
+ 			    (input_bfd, symtab_hdr->sh_link, sym->st_name));
+ 		    if (name == NULL)
+ 		      name = _("<unknown>");
+ 		    else if (name[0] == 0)
+ 		      name = bfd_section_name (input_bfd, sec);
+ 		  }
+ 		(*_bfd_error_handler)
+ 		  (_("%s: !samegp reloc against symbol without .prologue: %s"),
+ 		   bfd_archive_filename (input_bfd), name);
+ 		ret_val = false;
+ 		break;
+ 	      }
+ 
+ 	    goto default_reloc;
+ 	  }
  
  	case R_ALPHA_REFLONG:
  	case R_ALPHA_REFQUAD:
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.54
diff -c -p -d -r1.54 reloc.c
*** reloc.c	2002/02/08 05:33:23	1.54
--- reloc.c	2002/02/09 22:52:36
*************** ENUMDOC
*** 1956,1961 ****
--- 1956,1968 ----
       GP register.
  
  ENUM
+   BFD_RELOC_ALPHA_BRSGP
+ ENUMDOC
+   Like BFD_RELOC_23_PCREL_S2, except that the source and target must
+   share a common GP, and the target address is adjusted for 
+   STO_ALPHA_STD_GPLOAD.
+ 
+ ENUM
    BFD_RELOC_MIPS_JMP
  ENUMDOC
    Bits 27..2 of the relocation address shifted right 2 bits;
Index: gas/config/tc-alpha.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-alpha.c,v
retrieving revision 1.36
diff -c -p -d -r1.36 tc-alpha.c
*** tc-alpha.c	2002/02/08 10:03:01	1.36
--- tc-alpha.c	2002/02/09 22:52:37
*************** struct alpha_macro {
*** 117,122 ****
--- 117,123 ----
  #define O_gprelhigh	O_md9	/* !gprelhigh relocation */
  #define O_gprellow	O_md10	/* !gprellow relocation */
  #define O_gprel		O_md11	/* !gprel relocation */
+ #define O_samegp	O_md12	/* !samegp relocation */
  
  #define DUMMY_RELOC_LITUSE_ADDR		(BFD_RELOC_UNUSED + 1)
  #define DUMMY_RELOC_LITUSE_BASE		(BFD_RELOC_UNUSED + 2)
*************** struct alpha_macro {
*** 128,134 ****
  #define LITUSE_BYTOFF	2
  #define LITUSE_JSR	3
  
! #define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_gprel)
  
  /* Macros for extracting the type and number of encoded register tokens */
  
--- 129,135 ----
  #define LITUSE_BYTOFF	2
  #define LITUSE_JSR	3
  
! #define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_samegp)
  
  /* Macros for extracting the type and number of encoded register tokens */
  
*************** static const struct alpha_reloc_op_tag {
*** 498,504 ****
    DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1),
    DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0),
    DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0),
!   DEF(gprel, BFD_RELOC_GPREL16, 0, 0)
  };
  
  #undef DEF
--- 499,506 ----
    DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1),
    DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0),
    DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0),
!   DEF(gprel, BFD_RELOC_GPREL16, 0, 0),
!   DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0)
  };
  
  #undef DEF
*************** md_apply_fix3 (fixP, valP, seg)
*** 1219,1224 ****
--- 1221,1231 ----
  	}
        return;
  
+ #ifdef OBJ_ELF
+     case BFD_RELOC_ALPHA_BRSGP:
+       return;
+ #endif
+ 
  #ifdef OBJ_ECOFF
      case BFD_RELOC_ALPHA_LITERAL:
        md_number_to_chars (fixpos, value, 2);
*************** alpha_define_label (sym)
*** 1364,1369 ****
--- 1371,1419 ----
    alpha_insn_label = sym;
  }
  
+ /* If we have a BRSGP reloc to a local symbol, adjust it to BRADDR and
+    let it get resolved at assembly time.  */
+ 
+ void
+ alpha_validate_fix (f)
+      fixS *f;
+ {
+ #ifdef OBJ_ELF
+   int offset = 0;
+   const char *name;
+ 
+   if (f->fx_r_type != BFD_RELOC_ALPHA_BRSGP)
+     return;
+ 
+   if (! S_IS_DEFINED (f->fx_addsy))
+     return;
+ 
+   switch (S_GET_OTHER (f->fx_addsy) & STO_ALPHA_STD_GPLOAD)
+     {
+     case STO_ALPHA_NOPV:
+       break;
+     case STO_ALPHA_STD_GPLOAD:
+       offset = 8;
+       break;
+     default:
+       if (S_IS_LOCAL (f->fx_addsy))
+ 	name = "<local>";
+       else
+ 	name = S_GET_NAME (f->fx_addsy);
+       as_bad_where (f->fx_file, f->fx_line,
+ 		    _("!samegp reloc against symbol without .prologue: %s"),
+ 		    name);
+       break;
+     }
+ 
+   if (! (S_IS_EXTERN (f->fx_addsy) || S_IS_WEAK (f->fx_addsy)))
+     {
+       f->fx_r_type = BFD_RELOC_23_PCREL_S2;
+       f->fx_offset += offset;
+     }
+ #endif
+ }
+ 
  /* Return true if we must always emit a reloc for a type and false if
     there is some hope of resolving it at assembly time.  */
  
*************** alpha_force_relocation (f)
*** 1388,1393 ****
--- 1438,1444 ----
      case BFD_RELOC_ALPHA_GPREL_LO16:
      case BFD_RELOC_ALPHA_LINKAGE:
      case BFD_RELOC_ALPHA_CODEADDR:
+     case BFD_RELOC_ALPHA_BRSGP:
      case BFD_RELOC_VTABLE_INHERIT:
      case BFD_RELOC_VTABLE_ENTRY:
        return 1;
*************** alpha_fix_adjustable (f)
*** 1422,1427 ****
--- 1473,1479 ----
      case BFD_RELOC_ALPHA_GPDISP_HI16:
      case BFD_RELOC_ALPHA_GPDISP_LO16:
      case BFD_RELOC_ALPHA_GPDISP:
+     case BFD_RELOC_ALPHA_BRSGP:
        return 0;
  
      case BFD_RELOC_ALPHA_LITERAL:
*************** debug_exp (tok, ntok)
*** 1763,1768 ****
--- 1815,1821 ----
  	case O_pregister:		name = "O_pregister";		break;
  	case O_cpregister:		name = "O_cpregister";		break;
  	case O_literal:			name = "O_literal";		break;
+ 	case O_lituse_addr:		name = "O_lituse_addr";		break;
  	case O_lituse_base:		name = "O_lituse_base";		break;
  	case O_lituse_bytoff:		name = "O_lituse_bytoff";	break;
  	case O_lituse_jsr:		name = "O_lituse_jsr";		break;
*************** debug_exp (tok, ntok)
*** 1770,1777 ****
  	case O_gprelhigh:		name = "O_gprelhigh";		break;
  	case O_gprellow:		name = "O_gprellow";		break;
  	case O_gprel:			name = "O_gprel";		break;
! 	case O_md11:			name = "O_md11";		break;
! 	case O_md12:			name = "O_md12";		break;
  	case O_md13:			name = "O_md13";		break;
  	case O_md14:			name = "O_md14";		break;
  	case O_md15:			name = "O_md15";		break;
--- 1823,1829 ----
  	case O_gprelhigh:		name = "O_gprelhigh";		break;
  	case O_gprellow:		name = "O_gprellow";		break;
  	case O_gprel:			name = "O_gprel";		break;
! 	case O_samegp:			name = "O_samegp";		break;
  	case O_md13:			name = "O_md13";		break;
  	case O_md14:			name = "O_md14";		break;
  	case O_md15:			name = "O_md15";		break;
*************** find_macro_match (first_macro, tok, pnto
*** 2166,2171 ****
--- 2218,2224 ----
  		case O_gprelhigh:
  		case O_gprellow:
  		case O_gprel:
+ 		case O_samegp:
  		  goto match_failed;
  
  		default:
Index: gas/config/tc-alpha.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-alpha.h,v
retrieving revision 1.11
diff -c -p -d -r1.11 tc-alpha.h
*** tc-alpha.h	2001/11/15 21:28:54	1.11
--- tc-alpha.h	2002/02/09 22:52:37
***************
*** 39,50 ****
--- 39,52 ----
  #define NEED_LITERAL_POOL
  #define REPEAT_CONS_EXPRESSIONS
  
+ extern void alpha_validate_fix PARAMS ((struct fix *));
  extern int alpha_force_relocation PARAMS ((struct fix *));
  extern int alpha_fix_adjustable PARAMS ((struct fix *));
  
  extern unsigned long alpha_gprmask, alpha_fprmask;
  extern valueT alpha_gp_value;
  
+ #define TC_VALIDATE_FIX(FIXP,SEGTYPE,SKIP) alpha_validate_fix (FIXP)
  #define TC_FORCE_RELOCATION(FIXP)	alpha_force_relocation (FIXP)
  #define tc_fix_adjustable(FIXP)		alpha_fix_adjustable (FIXP)
  #define RELOC_REQUIRES_SYMBOL
Index: gas/testsuite/gas/alpha/alpha.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/alpha/alpha.exp,v
retrieving revision 1.2
diff -c -p -d -r1.2 alpha.exp
*** alpha.exp	2002/01/22 09:45:49	1.2
--- alpha.exp	2002/02/09 22:52:37
*************** if { [istarget alpha*-*-*] } then {
*** 27,32 ****
--- 27,34 ----
  	run_list_test "elf-reloc-2" ""
  	run_list_test "elf-reloc-3" ""
  	run_dump_test "elf-reloc-4"
+ 	run_dump_test "elf-reloc-5"
+ 	run_list_test "elf-reloc-6" ""
      }
  
      run_dump_test "fp"
Index: include/elf/alpha.h
===================================================================
RCS file: /cvs/src/src/include/elf/alpha.h,v
retrieving revision 1.5
diff -c -p -d -r1.5 alpha.h
*** alpha.h	2001/09/05 02:54:37	1.5
--- alpha.h	2002/02/09 22:52:44
*************** START_RELOC_NUMBERS (elf_alpha_reloc_typ
*** 94,99 ****
--- 94,104 ----
    RELOC_NUMBER (R_ALPHA_JMP_SLOT, 26)	/* Create PLT entry */
    RELOC_NUMBER (R_ALPHA_RELATIVE, 27)	/* Adjust by program base */
  
+   /* Like BRADDR, but assert that the source and target object file
+      share the same GP value, and adjust the target address for 
+      STO_ALPHA_STD_GPLOAD.  */
+   RELOC_NUMBER (R_ALPHA_BRSGP, 28)
+ 
  END_RELOC_NUMBERS (R_ALPHA_max)
  
  #endif /* _ELF_ALPHA_H */


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