Add lituse_jsrdirect relocation for alpha

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Add lituse_jsrdirect relocation for alpha

Richard Henderson-2
In the secureplt format, we clobber more registers than in the old
format, which means that we can not allow the special integer division
routines to be vectored through the plt.

For the most part this can be solved in libc, by not marking the division
routines STT_FUNC.  That works except in the case that the user builds a
shared library but does not link it against libc.  In that case, the linker
would have no information that __divq is special and would vector the call
through the plt anyway, leading to corruption.  While not linking against
all of the required libraries is A Highly Questionable Practice, it did
work before.

This adds a LITUSE form that requests relaxation as for a call, but does
not allow the linker to fall back to a plt entry.  This is backward
compatible with old linkers, in that LITUSE is, and has always been, a
hint, and we ignore forms that we don't recognize.  Indeed, we ignore
them to the extent that we won't process them for plt entries either,
which has the desired correctness effect as well.


r~


bfd/
        * elf64-alpha.c (ALPHA_ELF_LINK_HASH_LU_JSRDIRECT): New.
        (ALPHA_ELF_LINK_HASH_TLS_IE): Renumber to 0x80.
        (ALPHA_ELF_LINK_HASH_LU_PLT): Rename from ALPHA_ELF_LINK_HASH_LU_FUNC.
        (elf64_alpha_want_plt): Update to match.
        (elf64_alpha_check_relocs): Collect JSRDIRECT in gotent_flags.
        (elf64_alpha_relax_with_lituse): Likewise.  Handle JSRDIRECT.

binutils/
        * readelf.c (dump_relocations): Special case R_ALPHA_LITUSE.

gas/
        * config/tc-alpha.c (O_lituse_jsrdirect): New.
        (alpha_reloc_op): Add it.
        (debug_exp): Handle it.
        (DUMMY_RELOC_LITUSE_JSRDIRECT): New.
        (emit_insn): Handle it.
        * doc/c-alpha.texi (Alpha-Relocs): Document lituse_jsrdirect.

include/elf/
        * alpha.h (LITUSE_ALPHA_JSRDIRECT): New.


Index: bfd/elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.140
diff -u -p -d -r1.140 elf64-alpha.c
--- bfd/elf64-alpha.c 30 May 2005 21:22:40 -0000 1.140
+++ bfd/elf64-alpha.c 31 May 2005 22:37:03 -0000
@@ -112,14 +112,15 @@ struct alpha_elf_link_hash_entry
   int flags;
 
   /* Contexts in which a literal was referenced.  */
-#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01
-#define ALPHA_ELF_LINK_HASH_LU_MEM 0x02
-#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04
-#define ALPHA_ELF_LINK_HASH_LU_JSR 0x08
-#define ALPHA_ELF_LINK_HASH_LU_TLSGD 0x10
-#define ALPHA_ELF_LINK_HASH_LU_TLSLDM 0x20
-#define ALPHA_ELF_LINK_HASH_LU_FUNC 0x38
-#define ALPHA_ELF_LINK_HASH_TLS_IE 0x40
+#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01
+#define ALPHA_ELF_LINK_HASH_LU_MEM 0x02
+#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04
+#define ALPHA_ELF_LINK_HASH_LU_JSR 0x08
+#define ALPHA_ELF_LINK_HASH_LU_TLSGD 0x10
+#define ALPHA_ELF_LINK_HASH_LU_TLSLDM 0x20
+#define ALPHA_ELF_LINK_HASH_LU_JSRDIRECT 0x40
+#define ALPHA_ELF_LINK_HASH_LU_PLT 0x38
+#define ALPHA_ELF_LINK_HASH_TLS_IE 0x80
 
   /* Used to implement multiple .got subsections.  */
   struct alpha_elf_got_entry
@@ -1729,8 +1730,8 @@ elf64_alpha_want_plt (struct alpha_elf_l
   return ((ah->root.type == STT_FUNC
   || ah->root.root.type == bfd_link_hash_undefweak
   || ah->root.root.type == bfd_link_hash_undefined)
-  && (ah->flags & ALPHA_ELF_LINK_HASH_LU_FUNC) != 0
-  && (ah->flags & ~ALPHA_ELF_LINK_HASH_LU_FUNC) == 0);
+  && (ah->flags & ALPHA_ELF_LINK_HASH_LU_PLT) != 0
+  && (ah->flags & ~ALPHA_ELF_LINK_HASH_LU_PLT) == 0);
 }
 
 /* Handle dynamic relocations when doing an Alpha ELF link.  */
@@ -1826,7 +1827,7 @@ elf64_alpha_check_relocs (bfd *abfd, str
      This will be important when it comes to decide if we can
      create a .plt entry for a function symbol.  */
   while (++rel < relend && ELF64_R_TYPE (rel->r_info) == R_ALPHA_LITUSE)
-    if (rel->r_addend >= 1 && rel->r_addend <= 5)
+    if (rel->r_addend >= 1 && rel->r_addend <= 6)
       gotent_flags |= 1 << rel->r_addend;
   --rel;
 
@@ -3137,7 +3138,7 @@ elf64_alpha_relax_with_lituse (struct al
     {
       if (ELF64_R_TYPE (urel->r_info) != R_ALPHA_LITUSE)
  break;
-      if (urel->r_addend <= 3)
+      if (urel->r_addend <= 6)
  flags |= 1 << urel->r_addend;
     }
 
@@ -3232,6 +3233,7 @@ elf64_alpha_relax_with_lituse (struct al
  case LITUSE_ALPHA_JSR:
  case LITUSE_ALPHA_TLSGD:
  case LITUSE_ALPHA_TLSLDM:
+ case LITUSE_ALPHA_JSRDIRECT:
   {
     bfd_vma optdest, org;
     bfd_signed_vma odisp;
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.298
diff -u -p -d -r1.298 readelf.c
--- binutils/readelf.c 29 May 2005 23:18:51 -0000 1.298
+++ binutils/readelf.c 31 May 2005 22:37:07 -0000
@@ -1243,7 +1243,31 @@ dump_relocations (FILE *file,
       else
  printf (do_wide ? "%-22.22s" : "%-17.17s", rtype);
 
-      if (symtab_index)
+      if (elf_header.e_machine == EM_ALPHA
+  && streq (rtype, "R_ALPHA_LITUSE")
+  && is_rela)
+ {
+  switch (rels[i].r_addend)
+    {
+    case LITUSE_ALPHA_ADDR:   rtype = "ADDR";   break;
+    case LITUSE_ALPHA_BASE:   rtype = "BASE";   break;
+    case LITUSE_ALPHA_BYTOFF: rtype = "BYTOFF"; break;
+    case LITUSE_ALPHA_JSR:    rtype = "JSR";    break;
+    case LITUSE_ALPHA_TLSGD:  rtype = "TLSGD";  break;
+    case LITUSE_ALPHA_TLSLDM: rtype = "TLSLDM"; break;
+    case LITUSE_ALPHA_JSRDIRECT: rtype = "JSRDIRECT"; break;
+    default: rtype = NULL;
+    }
+  if (rtype)
+    printf (" (%s)", rtype);
+  else
+    {
+      putchar (' ');
+      printf (_("<unknown addend: %lx>"),
+      (unsigned long) rels[i].r_addend);
+    }
+ }
+      else if (symtab_index)
  {
   if (symtab == NULL || symtab_index >= nsyms)
     printf (" bad symbol index: %08lx", (unsigned long) symtab_index);
@@ -1309,8 +1333,7 @@ dump_relocations (FILE *file,
   print_vma (rels[i].r_addend, LONG_HEX);
  }
 
-      if (elf_header.e_machine == EM_SPARCV9
-  && streq (rtype, "R_SPARC_OLO10"))
+      if (elf_header.e_machine == EM_SPARCV9 && streq (rtype, "R_SPARC_OLO10"))
  printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info));
 
       putchar ('\n');
Index: gas/config/tc-alpha.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-alpha.c,v
retrieving revision 1.67
diff -u -p -d -r1.67 tc-alpha.c
--- gas/config/tc-alpha.c 5 May 2005 09:12:53 -0000 1.67
+++ gas/config/tc-alpha.c 31 May 2005 22:37:08 -0000
@@ -109,28 +109,29 @@ struct alpha_macro
 #define O_cpregister O_md2 /* + a leading comma.  */
 
 /* The alpha_reloc_op table below depends on the ordering of these.  */
-#define O_literal O_md3 /* !literal relocation.  */
-#define O_lituse_addr O_md4 /* !lituse_addr relocation.  */
-#define O_lituse_base O_md5 /* !lituse_base relocation.  */
-#define O_lituse_bytoff O_md6 /* !lituse_bytoff relocation.  */
-#define O_lituse_jsr O_md7 /* !lituse_jsr relocation.  */
-#define O_lituse_tlsgd O_md8 /* !lituse_tlsgd relocation.  */
-#define O_lituse_tlsldm O_md9 /* !lituse_tlsldm relocation.  */
-#define O_gpdisp O_md10 /* !gpdisp relocation.  */
-#define O_gprelhigh O_md11 /* !gprelhigh relocation.  */
-#define O_gprellow O_md12 /* !gprellow relocation.  */
-#define O_gprel O_md13 /* !gprel relocation.  */
-#define O_samegp O_md14 /* !samegp relocation.  */
-#define O_tlsgd O_md15 /* !tlsgd relocation.  */
-#define O_tlsldm O_md16 /* !tlsldm relocation.  */
-#define O_gotdtprel O_md17 /* !gotdtprel relocation.  */
-#define O_dtprelhi O_md18 /* !dtprelhi relocation.  */
-#define O_dtprello O_md19 /* !dtprello relocation.  */
-#define O_dtprel O_md20 /* !dtprel relocation.  */
-#define O_gottprel O_md21 /* !gottprel relocation.  */
-#define O_tprelhi O_md22 /* !tprelhi relocation.  */
-#define O_tprello O_md23 /* !tprello relocation.  */
-#define O_tprel O_md24 /* !tprel relocation.  */
+#define O_literal O_md3 /* !literal relocation.  */
+#define O_lituse_addr O_md4 /* !lituse_addr relocation.  */
+#define O_lituse_base O_md5 /* !lituse_base relocation.  */
+#define O_lituse_bytoff O_md6 /* !lituse_bytoff relocation.  */
+#define O_lituse_jsr O_md7 /* !lituse_jsr relocation.  */
+#define O_lituse_tlsgd O_md8 /* !lituse_tlsgd relocation.  */
+#define O_lituse_tlsldm O_md9 /* !lituse_tlsldm relocation.  */
+#define O_lituse_jsrdirect O_md10 /* !lituse_jsrdirect relocation.  */
+#define O_gpdisp O_md11 /* !gpdisp relocation.  */
+#define O_gprelhigh O_md12 /* !gprelhigh relocation.  */
+#define O_gprellow O_md13 /* !gprellow relocation.  */
+#define O_gprel O_md14 /* !gprel relocation.  */
+#define O_samegp O_md15 /* !samegp relocation.  */
+#define O_tlsgd O_md16 /* !tlsgd relocation.  */
+#define O_tlsldm O_md17 /* !tlsldm relocation.  */
+#define O_gotdtprel O_md18 /* !gotdtprel relocation.  */
+#define O_dtprelhi O_md19 /* !dtprelhi relocation.  */
+#define O_dtprello O_md20 /* !dtprello relocation.  */
+#define O_dtprel O_md21 /* !dtprel relocation.  */
+#define O_gottprel O_md22 /* !gottprel relocation.  */
+#define O_tprelhi O_md23 /* !tprelhi relocation.  */
+#define O_tprello O_md24 /* !tprello relocation.  */
+#define O_tprel O_md25 /* !tprel relocation.  */
 
 #define DUMMY_RELOC_LITUSE_ADDR (BFD_RELOC_UNUSED + 1)
 #define DUMMY_RELOC_LITUSE_BASE (BFD_RELOC_UNUSED + 2)
@@ -138,6 +139,7 @@ struct alpha_macro
 #define DUMMY_RELOC_LITUSE_JSR (BFD_RELOC_UNUSED + 4)
 #define DUMMY_RELOC_LITUSE_TLSGD (BFD_RELOC_UNUSED + 5)
 #define DUMMY_RELOC_LITUSE_TLSLDM (BFD_RELOC_UNUSED + 6)
+#define DUMMY_RELOC_LITUSE_JSRDIRECT (BFD_RELOC_UNUSED + 7)
 
 #define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel)
 
@@ -418,6 +420,7 @@ alpha_reloc_op[] =
   DEF (lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1),
   DEF (lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1),
   DEF (lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1),
+  DEF (lituse_jsrdirect, DUMMY_RELOC_LITUSE_JSRDIRECT, 1, 1),
   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),
@@ -770,6 +773,7 @@ debug_exp (expressionS tok[], int ntok)
  case O_lituse_jsr: name = "O_lituse_jsr"; break;
  case O_lituse_tlsgd: name = "O_lituse_tlsgd"; break;
  case O_lituse_tlsldm: name = "O_lituse_tlsldm"; break;
+ case O_lituse_jsrdirect: name = "O_lituse_jsrdirect"; break;
  case O_gpdisp: name = "O_gpdisp"; break;
  case O_gprelhigh: name = "O_gprelhigh"; break;
  case O_gprellow: name = "O_gprellow"; break;
@@ -1720,6 +1724,9 @@ emit_insn (struct alpha_insn *insn)
  case DUMMY_RELOC_LITUSE_TLSLDM:
   fixP->fx_offset = LITUSE_ALPHA_TLSLDM;
   goto do_lituse;
+ case DUMMY_RELOC_LITUSE_JSRDIRECT:
+  fixP->fx_offset = LITUSE_ALPHA_JSRDIRECT;
+  goto do_lituse;
  do_lituse:
   fixP->fx_addsy = section_symbol (now_seg);
   fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE;
Index: include/elf/alpha.h
===================================================================
RCS file: /cvs/src/src/include/elf/alpha.h,v
retrieving revision 1.11
diff -u -p -d -r1.11 alpha.h
--- include/elf/alpha.h 29 May 2005 23:18:26 -0000 1.11
+++ include/elf/alpha.h 31 May 2005 22:37:09 -0000
@@ -125,5 +125,6 @@ END_RELOC_NUMBERS (R_ALPHA_max)
 #define LITUSE_ALPHA_JSR 3
 #define LITUSE_ALPHA_TLSGD 4
 #define LITUSE_ALPHA_TLSLDM 5
+#define LITUSE_ALPHA_JSRDIRECT 6
 
 #endif /* _ELF_ALPHA_H */
? gas/doc/as.info
Index: gas/doc/c-alpha.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-alpha.texi,v
retrieving revision 1.7
diff -u -p -d -r1.7 c-alpha.texi
--- gas/doc/c-alpha.texi 3 Mar 2005 01:29:53 -0000 1.7
+++ gas/doc/c-alpha.texi 31 May 2005 22:50:57 -0000
@@ -203,6 +203,12 @@ Used with a register branch format instr
 indicate that the literal is used for a call.  During relaxation, the
 code may be altered to use a direct branch (e.g.@: @code{bsr}).
 
+@item !lituse_jsrdirect!@var{N}
+Similar to @code{lituse_jsr}, but also that this call cannot be vectored
+through a PLT entry.  This is useful for functions with special calling
+conventions which do not allow the normal call-clobbered registers to be
+clobbered.
+
 @item !lituse_bytoff!@var{N}
 Used with a byte mask instruction (e.g.@: @code{extbl}) to indicate
 that only the low 3 bits of the address are relevant.  During relaxation,