OSDN Git Service

.plt stub for lazy linking, --stub-group-size=N ld switch,
authoramodra <amodra>
Wed, 27 Sep 2000 17:30:16 +0000 (17:30 +0000)
committeramodra <amodra>
Wed, 27 Sep 2000 17:30:16 +0000 (17:30 +0000)
import stub fix, extra DIR14F reloc to fix abort in tc_gen_reloc

bfd/ChangeLog
bfd/elf-hppa.h
bfd/elf32-hppa.c
bfd/elf32-hppa.h
gas/ChangeLog
include/elf/ChangeLog
include/elf/hppa.h
ld/ChangeLog
ld/emultempl/hppaelf.em
ld/ld.texinfo

index 0103b1d..16b6ac4 100644 (file)
@@ -1,3 +1,40 @@
+2000-09-27  Alan Modra  <alan@linuxcare.com.au>
+
+       * elf32-hppa.c (plt_stub): New.
+       (PLT_STUB_ENTRY): Define.
+       (elf32_hppa_link_hash_table): Change multi_subspace to packed
+       boolean.  Add need_plt_stub, has_12bit_branch and has_17bit_branch.
+       (elf32_hppa_link_hash_table_create): Init to suit.
+       (elf32_hppa_check_relocs): Set has_12bit_branch and
+       has_17bit_branch as appropriate.
+       (elf32_hppa_adjust_dynamic_symbol): Set need_plt_stub for
+       non-local functions.
+       (elf32_hppa_size_dynamic_sections): Correct setting of reltext.
+       Add space for plt_stub as needed.
+       (elf32_hppa_finish_dynamic_symbol): Point .plt entries for global
+       functions at plt_stub.
+       (elf32_hppa_finish_dynamic_sections): Write plt_stub.
+       (elf32_hppa_create_dynamic_sections): Leave .plt executable.
+
+       * elf32-hppa.h (elf32_hppa_size_stubs): Add group_size param.
+       * elf32-hppa.c (elf32_hppa_size_stubs): Likewise.  Use it instead
+       of fixed size, and if negative, disable handling of input sections
+       before stub section.  Set up default stub group size depending
+       on detected branch relocs.
+       (hppa_build_one_stub): Use lrsel and rrsel for import stubs to
+       ensure different offsets from sym_value aren't rounded to
+       different 2k blocks.  Use lrsel and rrsel for other stubs too for
+       consistency rather than necessity.
+       (elf32_hppa_check_relocs): Handle R_PARISC_DIR14F.
+       (final_link_relocate): Likewise.
+       (elf32_hppa_relocate_section): Likewise.
+
+       * elf-hppa.h (elf_hppa_howto_table): Add R_PARISC_DIR14F reloc.
+       (_bfd_elf_hppa_gen_reloc_type): Generate them.
+       (elf_hppa_final_link_relocate): Handle them.
+       (elf_hppa_relocate_insn): Likewise.
+       (_bfd_elf_hppa_gen_reloc_type): Add missing e_ldsel and e_rdsel cases.
+
 2000-09-26  Hans-Peter Nilsson  <hp@axis.com>
 
        * elfcode.h (elf_object_p): Preserve and clear abfd section
index 1cf89f3..1093cfa 100644 (file)
@@ -118,8 +118,8 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] =
     bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", false, 0, 0, false },
   { R_PARISC_DIR14R, 0, 0, 14, false, 0, complain_overflow_bitfield,
     bfd_elf_generic_reloc, "R_PARISC_DIR14R", false, 0, 0, false },
-  { R_PARISC_UNIMPLEMENTED, 0, 0, 0, false, 0, complain_overflow_bitfield,
-    bfd_elf_generic_reloc, "R_PARISC_UNIMPLEMENTED", false, 0, 0, false },
+  { R_PARISC_DIR14F, 0, 0, 14, false, 0, complain_overflow_bitfield,
+    bfd_elf_generic_reloc, "R_PARISC_DIR14F", false, 0, 0, false },
   /* 8 */
   { R_PARISC_PCREL12F, 0, 0, 12, true, 0, complain_overflow_bitfield,
     bfd_elf_generic_reloc, "R_PARISC_PCREL12F", false, 0, 0, false },
@@ -657,8 +657,12 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
        case 14:
          switch (field)
            {
+           case e_fsel:
+             final_type = R_PARISC_DIR14F;
+             break;
            case e_rsel:
            case e_rrsel:
+           case e_rdsel:
              final_type = R_PARISC_DIR14R;
              break;
            case e_rtsel:
@@ -686,6 +690,7 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
              break;
            case e_rsel:
            case e_rrsel:
+           case e_rdsel:
              final_type = R_PARISC_DIR17R;
              break;
            default:
@@ -698,6 +703,7 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
            {
            case e_lsel:
            case e_lrsel:
+           case e_ldsel:
            case e_nlsel:
            case e_nlrsel:
              final_type = R_PARISC_DIR21L;
@@ -763,6 +769,7 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
            {
            case e_rsel:
            case e_rrsel:
+           case e_rdsel:
              /* R_PARISC_DLTREL14R for elf64, R_PARISC_DPREL14R for elf32  */
              final_type = base_type + OFFSET_14R_FROM_21L;
              break;
@@ -780,6 +787,7 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
            {
            case e_lsel:
            case e_lrsel:
+           case e_ldsel:
            case e_nlsel:
            case e_nlrsel:
              /* R_PARISC_DLTREL21L for elf64, R_PARISC_DPREL21L for elf32  */
@@ -817,6 +825,7 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
            {
            case e_rsel:
            case e_rrsel:
+           case e_rdsel:
              final_type = R_PARISC_PCREL14R;
              break;
            case e_fsel:
@@ -832,6 +841,7 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
            {
            case e_rsel:
            case e_rrsel:
+           case e_rdsel:
              final_type = R_PARISC_PCREL17R;
              break;
            case e_fsel:
@@ -847,6 +857,7 @@ _bfd_elf_hppa_gen_reloc_type (abfd, base_type, format, field, ignore, sym)
            {
            case e_lsel:
            case e_lrsel:
+           case e_ldsel:
            case e_nlsel:
            case e_nlrsel:
              final_type = R_PARISC_PCREL21L;
@@ -1712,6 +1723,7 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
     case R_PARISC_DIR17R:
     case R_PARISC_DIR17F:
     case R_PARISC_DIR14R:
+    case R_PARISC_DIR14F:
     case R_PARISC_DIR14WR:
     case R_PARISC_DIR14DR:
     case R_PARISC_DIR16F:
@@ -1728,7 +1740,8 @@ elf_hppa_final_link_relocate (rel, input_bfd, output_bfd,
        else if (r_type == R_PARISC_DIR17F
                 || r_type == R_PARISC_DIR16F
                 || r_type == R_PARISC_DIR16WF
-                || r_type == R_PARISC_DIR16DF)
+                || r_type == R_PARISC_DIR16DF
+                || r_type == R_PARISC_DIR14F)
          value = hppa_field_adjust (value, addend, e_fsel);
        else
          value = hppa_field_adjust (value, addend, e_rrsel);
@@ -2055,6 +2068,7 @@ elf_hppa_relocate_insn (insn, sym_value, r_type)
     case R_PARISC_PLTOFF14F:
     case R_PARISC_PLTOFF16F:
     case R_PARISC_DIR14R:
+    case R_PARISC_DIR14F:
     case R_PARISC_DIR16F:
     case R_PARISC_LTOFF16F:
       return (insn & ~ 0x3fff) | low_sign_unext (sym_value, 14);
index 01e2611..0deec5a 100644 (file)
@@ -120,6 +120,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define GOT_ENTRY_SIZE 4
 #define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
 
+static const bfd_byte plt_stub[] =
+{
+  0x0e, 0x80, 0x10, 0x96,  /* 1: ldw   0(%r20),%r22            */
+  0xea, 0xc0, 0xc0, 0x00,  /*    bv    %r0(%r22)               */
+  0x0e, 0x88, 0x10, 0x95,  /*    ldw   4(%r20),%r21            */
+#define PLT_STUB_ENTRY (3*4)
+  0xea, 0x9f, 0x1f, 0xdd,  /*    b,l   1b,%r20                 */
+  0xd6, 0x80, 0x1c, 0x1e,  /*    depi  0,31,2,%r20             */
+  0x00, 0xc0, 0xff, 0xee,  /* 9: .word fixup_func              */
+  0xde, 0xad, 0xbe, 0xef   /*    .word fixup_ltp               */
+};
+
 /* Section name for stubs is the associated section name plus this
    string.  */
 #define STUB_SUFFIX ".stub"
@@ -240,9 +252,6 @@ struct elf32_hppa_link_hash_table {
   /* Linker stub bfd.  */
   bfd *stub_bfd;
 
-  /* Whether we support multiple sub-spaces for shared libs.  */
-  boolean multi_subspace;
-
   /* Linker call-backs.  */
   asection * (*add_stub_section) PARAMS ((const char *, asection *));
   void (*layout_sections_again) PARAMS ((void));
@@ -268,6 +277,17 @@ struct elf32_hppa_link_hash_table {
   asection *srelplt;
   asection *sdynbss;
   asection *srelbss;
+
+  /* Whether we support multiple sub-spaces for shared libs.  */
+  unsigned int multi_subspace:1;
+
+  /* Flags set when PCREL12F and PCREL17F branches detected.  Used to
+     select suitable defaults for the stub group size.  */
+  unsigned int has_12bit_branch:1;
+  unsigned int has_17bit_branch:1;
+
+  /* Set if we need a .plt stub to support lazy dynamic linking.  */
+  unsigned int need_plt_stub:1;
 };
 
 
@@ -498,7 +518,6 @@ elf32_hppa_link_hash_table_create (abfd)
     return NULL;
 
   ret->stub_bfd = NULL;
-  ret->multi_subspace = 0;
   ret->add_stub_section = NULL;
   ret->layout_sections_again = NULL;
   ret->stub_group = NULL;
@@ -508,6 +527,10 @@ elf32_hppa_link_hash_table_create (abfd)
   ret->srelplt = NULL;
   ret->sdynbss = NULL;
   ret->srelbss = NULL;
+  ret->multi_subspace = 0;
+  ret->has_12bit_branch = 0;
+  ret->has_17bit_branch = 0;
+  ret->need_plt_stub = 0;
 
   return &ret->root.root;
 }
@@ -896,11 +919,11 @@ hppa_build_one_stub (gen_entry, in_arg)
                    + stub_sec->output_section->vma);
 
       bfd_put_32 (stub_bfd, (bfd_vma) BL_R1, loc);
-      val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_lsel);
+      val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_lrsel);
       insn = hppa_rebuild_insn ((int) ADDIL_R1, val, 21);
       bfd_put_32 (stub_bfd, insn, loc + 4);
 
-      val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_rsel) >> 2;
+      val = hppa_field_adjust (sym_value, (bfd_signed_vma) -8, e_rrsel) >> 2;
       insn = hppa_rebuild_insn ((int) BE_SR4_R1, val, 17);
       bfd_put_32 (stub_bfd, insn, loc + 8);
       size = 12;
@@ -918,17 +941,22 @@ hppa_build_one_stub (gen_entry, in_arg)
       if (stub_entry->stub_type == hppa_stub_import_shared)
        insn = ADDIL_R19;
 #endif
-      val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_lsel),
+      val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_lrsel),
       insn = hppa_rebuild_insn ((int) insn, val, 21);
       bfd_put_32 (stub_bfd, insn, loc);
 
-      val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_rsel);
+      /* It is critical to use lrsel/rrsel here because we are using
+        two different offsets (+0 and +4) from sym_value.  If we use
+        lsel/rsel then with unfortunate sym_values we will round
+        sym_value+4 up to the next 2k block leading to a mis-match
+        between the lsel and rsel value.  */
+      val = hppa_field_adjust (sym_value, (bfd_signed_vma) 0, e_rrsel);
       insn = hppa_rebuild_insn ((int) LDW_R1_R21, val, 14);
       bfd_put_32 (stub_bfd, insn, loc + 4);
 
       if (hplink->multi_subspace)
        {
-         val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rsel);
+         val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rrsel);
          insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14);
          bfd_put_32 (stub_bfd, insn, loc + 8);
 
@@ -942,7 +970,7 @@ hppa_build_one_stub (gen_entry, in_arg)
       else
        {
          bfd_put_32 (stub_bfd, (bfd_vma) BV_R0_R21, loc + 8);
-         val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rsel);
+         val = hppa_field_adjust (sym_value, (bfd_signed_vma) 4, e_rrsel);
          insn = hppa_rebuild_insn ((int) LDW_R1_DLT, val, 14);
          bfd_put_32 (stub_bfd, insn, loc + 12);
 
@@ -1146,8 +1174,6 @@ elf32_hppa_create_dynamic_sections (abfd, info)
      bfd *abfd;
      struct bfd_link_info *info;
 {
-  flagword flags;
-  asection *s;
   struct elf32_hppa_link_hash_table *hplink;
 
   /* Don't try to create the .plt and .got twice.  */
@@ -1159,14 +1185,7 @@ elf32_hppa_create_dynamic_sections (abfd, info)
   if (! _bfd_elf_create_dynamic_sections (abfd, info))
     return false;
 
-  /* Our .plt just contains pointers.  I suppose we should be using
-     .plt.got but .plt.got doesn't make too much sense without a .plt
-     section.  Set the flags to say the .plt isn't executable.  */
-  s = bfd_get_section_by_name (abfd, ".plt");
-  flags = bfd_get_section_flags (abfd, s);
-  if (! bfd_set_section_flags (abfd, s, flags & ~SEC_CODE))
-    return false;
-  hplink->splt = s;
+  hplink->splt = bfd_get_section_by_name (abfd, ".plt");
   hplink->srelplt = bfd_get_section_by_name (abfd, ".rela.plt");
 
   hplink->sgot = bfd_get_section_by_name (abfd, ".got");
@@ -1278,11 +1297,15 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs)
          break;
 
        case R_PARISC_PCREL12F:
+         hplink->has_12bit_branch = 1;
+         /* Fall thru.  */
        case R_PARISC_PCREL17C:
        case R_PARISC_PCREL17F:
+         hplink->has_17bit_branch = 1;
+         /* Fall thru.  */
        case R_PARISC_PCREL22F:
-         /* Handle calls, and function pointers as they might need to
-            go through the .plt, and might require long branch stubs.  */
+         /* Function calls might need to go through the .plt, and
+            might require long branch stubs.  */
          if (h == NULL)
            {
              /* We know local syms won't need a .plt entry, and if
@@ -1329,7 +1352,8 @@ elf32_hppa_check_relocs (abfd, info, sec, relocs)
 
        case R_PARISC_DIR17F: /* Used for external branches.  */
        case R_PARISC_DIR17R:
-       case R_PARISC_DIR14R: /* Used for load/store from absolute locn.  */
+       case R_PARISC_DIR14F: /* Used for load/store from absolute locn.  */
+       case R_PARISC_DIR14R:
        case R_PARISC_DIR21L: /* As above, and for ext branches too.  */
 #if 1
          /* Help debug shared library creation.  Any of the above
@@ -1932,6 +1956,8 @@ elf32_hppa_adjust_dynamic_symbol (info, h)
          /* We also need to make an entry in the .rela.plt section.  */
          s = hplink->srelplt;
          s->_raw_size += sizeof (Elf32_External_Rela);
+
+         hplink->need_plt_stub = 1;
        }
       return true;
     }
@@ -2295,28 +2321,22 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
          if (s->_raw_size != 0)
            {
              asection *target;
+             const char *outname;
 
              /* Remember whether there are any reloc sections other
                 than .rela.plt.  */
              if (strcmp (name+5, ".plt") != 0)
-               {
-                 const char *outname;
-
-                 relocs = true;
-
-                 /* If this relocation section applies to a read only
-                    section, then we probably need a DT_TEXTREL
-                    entry.  The entries in the .rela.plt section
-                    really apply to the .got section, which we
-                    created ourselves and so know is not readonly.  */
-                 outname = bfd_get_section_name (output_bfd,
-                                                 s->output_section);
-                 target = bfd_get_section_by_name (output_bfd, outname + 5);
-                 if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0
-                     && (target->flags & SEC_ALLOC) != 0)
-                   reltext = true;
-               }
+               relocs = true;
+
+             /* If this relocation section applies to a read only
+                section, then we probably need a DT_TEXTREL entry.  */
+             outname = bfd_get_section_name (output_bfd,
+                                             s->output_section);
+             target = bfd_get_section_by_name (output_bfd, outname + 5);
+             if (target != NULL
+                 && (target->flags & SEC_READONLY) != 0
+                 && (target->flags & SEC_ALLOC) != 0)
+               reltext = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -2324,7 +2344,22 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
            }
        }
       else if (strcmp (name, ".plt") == 0)
-       ;
+       {
+         if (hplink->need_plt_stub)
+           {
+             /* Make space for the plt stub at the end of the .plt
+                section.  We want this stub right at the end, up
+                against the .got section.  */
+             int gotalign = bfd_section_alignment (dynobj, hplink->sgot);
+             int pltalign = bfd_section_alignment (dynobj, s);
+             bfd_size_type mask;
+
+             if (gotalign > pltalign)
+               bfd_set_section_alignment (dynobj, s, gotalign);
+             mask = ((bfd_size_type) 1 << gotalign) - 1;
+             s->_raw_size = (s->_raw_size + sizeof (plt_stub) + mask) & ~mask;
+           }
+       }
       else if (strcmp (name, ".got") == 0)
        ;
       else
@@ -2413,12 +2448,13 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
    instruction.  */
 
 boolean
-elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
+elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
                       add_stub_section, layout_sections_again)
      bfd *output_bfd;
      bfd *stub_bfd;
      struct bfd_link_info *info;
      boolean multi_subspace;
+     bfd_signed_vma group_size;
      asection * (*add_stub_section) PARAMS ((const char *, asection *));
      void (*layout_sections_again) PARAMS ((void));
 {
@@ -2429,6 +2465,8 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
   unsigned int bfd_indx, bfd_count;
   int top_id, top_index;
   struct elf32_hppa_link_hash_table *hplink;
+  bfd_size_type stub_group_size;
+  boolean stubs_always_before_branch;
   boolean stub_changed = 0;
   boolean ret = 0;
 
@@ -2439,6 +2477,20 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
   hplink->multi_subspace = multi_subspace;
   hplink->add_stub_section = add_stub_section;
   hplink->layout_sections_again = layout_sections_again;
+  stubs_always_before_branch = group_size < 0;
+  if (group_size < 0)
+    stub_group_size = -group_size;
+  else
+    stub_group_size = group_size;
+  if (stub_group_size == 1)
+    {
+      /* Default values.  */
+      stub_group_size = 8000000;
+      if (hplink->has_17bit_branch || hplink->multi_subspace)
+       stub_group_size = 250000;
+      if (hplink->has_12bit_branch)
+       stub_group_size = 7812;
+    }
 
   /* Count the number of input BFDs and find the top input section id.  */
   for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
@@ -2490,7 +2542,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
        section != NULL;
        section = section->next)
     {
-      if ((section->flags & SEC_CODE) != 0 && section->index <= top_index)
+      if ((section->flags & SEC_CODE) != 0)
        input_list[section->index] = NULL;
     }
 
@@ -2546,7 +2598,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
            total = tail->_raw_size;
          while ((prev = PREV_SEC (curr)) != NULL
                 && ((total += curr->output_offset - prev->output_offset)
-                    < 250000))
+                    < stub_group_size))
            curr = prev;
 
          /* OK, the size from the start of CURR to the end is less
@@ -2570,14 +2622,17 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace,
 
          /* But wait, there's more!  Input sections up to 250000
             bytes before the stub section can be handled by it too.  */
-         total = 0;
-         while (prev != NULL
-                && ((total += tail->output_offset - prev->output_offset)
-                    < 250000))
+         if (!stubs_always_before_branch)
            {
-             tail = prev;
-             prev = PREV_SEC (tail);
-             hplink->stub_group[tail->id].link_sec = curr;
+             total = 0;
+             while (prev != NULL
+                    && ((total += tail->output_offset - prev->output_offset)
+                        < stub_group_size))
+               {
+                 tail = prev;
+                 prev = PREV_SEC (tail);
+                 hplink->stub_group[tail->id].link_sec = curr;
+               }
            }
          tail = prev;
        }
@@ -3256,6 +3311,7 @@ final_link_relocate (input_section, contents, rel, value, hplink, sym_sec, h)
   switch (r_type)
     {
     case R_PARISC_DIR32:
+    case R_PARISC_DIR14F:
     case R_PARISC_DIR17F:
     case R_PARISC_PCREL17C:
     case R_PARISC_PCREL14F:
@@ -3688,6 +3744,7 @@ elf32_hppa_relocate_section (output_bfd, info, input_bfd, input_section,
 
        case R_PARISC_DIR17F:
        case R_PARISC_DIR17R:
+       case R_PARISC_DIR14F:
        case R_PARISC_DIR14R:
        case R_PARISC_DIR21L:
        case R_PARISC_DPREL14F:
@@ -3871,7 +3928,6 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
   if (h->plt.offset != (bfd_vma) -1)
     {
       bfd_vma value;
-      Elf_Internal_Rela rel;
 
       /* This symbol has an entry in the procedure linkage table.  Set
         it up.
@@ -3879,15 +3935,7 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
         The format of a plt entry is
         <funcaddr>
         <__gp>
-        <used by ld.so>
-
-        The last field is present only for plt entries that are used
-        by global plabels.  */
-
-      /* We do not actually care about the value in the PLT entry if
-        we are creating a shared library and the symbol is still
-        undefined;  We create a dynamic relocation to fill in the
-        correct value.  */
+      */
       value = 0;
       if (h->root.type == bfd_link_hash_defined
          || h->root.type == bfd_link_hash_defweak)
@@ -3898,22 +3946,10 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
                      + h->root.u.def.section->output_section->vma);
        }
 
-      bfd_put_32 (hplink->splt->owner,
-                 value,
-                 hplink->splt->contents + h->plt.offset);
-      bfd_put_32 (hplink->splt->owner,
-                 elf_gp (hplink->splt->output_section->owner),
-                 hplink->splt->contents + h->plt.offset + 4);
-      if (PLABEL_PLT_ENTRY_SIZE != PLT_ENTRY_SIZE
-         && ((struct elf32_hppa_link_hash_entry *) h)->plabel
-         && h->dynindx != -1)
-       {
-         memset (hplink->splt->contents + h->plt.offset + 8,
-                 0, PLABEL_PLT_ENTRY_SIZE - PLT_ENTRY_SIZE);
-       }
-
       if (! ((struct elf32_hppa_link_hash_entry *) h)->pic_call)
        {
+         Elf_Internal_Rela rel;
+
          /* Create a dynamic IPLT relocation for this entry.  */
          rel.r_offset = (h->plt.offset
                          + hplink->splt->output_offset
@@ -3921,6 +3957,15 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
          if (! ((struct elf32_hppa_link_hash_entry *) h)->plt_abs
              && h->dynindx != -1)
            {
+             /* To support lazy linking, the function pointer is
+                initialised to point to a special stub stored at the
+                end of the .plt.  This is only done for plt entries
+                with a non-*ABS* dynamic relocation.  */
+             value = (hplink->splt->output_offset
+                      + hplink->splt->output_section->vma
+                      + hplink->splt->_raw_size
+                      - sizeof (plt_stub)
+                      + PLT_STUB_ENTRY);
              rel.r_info = ELF32_R_INFO (h->dynindx, R_PARISC_IPLT);
              rel.r_addend = 0;
            }
@@ -3940,6 +3985,20 @@ elf32_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
          hplink->srelplt->reloc_count++;
        }
 
+      bfd_put_32 (hplink->splt->owner,
+                 value,
+                 hplink->splt->contents + h->plt.offset);
+      bfd_put_32 (hplink->splt->owner,
+                 elf_gp (hplink->splt->output_section->owner),
+                 hplink->splt->contents + h->plt.offset + 4);
+      if (PLABEL_PLT_ENTRY_SIZE != PLT_ENTRY_SIZE
+         && ((struct elf32_hppa_link_hash_entry *) h)->plabel
+         && h->dynindx != -1)
+       {
+         memset (hplink->splt->contents + h->plt.offset + 8,
+                 0, PLABEL_PLT_ENTRY_SIZE - PLT_ENTRY_SIZE);
+       }
+
       if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
        {
          /* Mark the symbol as undefined, rather than as defined in
@@ -4122,17 +4181,38 @@ elf32_hppa_finish_dynamic_sections (output_bfd, info)
                  hplink->sgot->contents);
 
       /* The second entry is reserved for use by the dynamic linker.  */
-      bfd_put_32 (output_bfd, (bfd_vma) 0, hplink->sgot->contents + 4);
+      memset (hplink->sgot->contents + GOT_ENTRY_SIZE, 0, GOT_ENTRY_SIZE);
 
       /* Set .got entry size.  */
       elf_section_data (hplink->sgot->output_section)
        ->this_hdr.sh_entsize = GOT_ENTRY_SIZE;
     }
 
-  /* Set plt entry size.  */
   if (hplink->splt->_raw_size != 0)
-    elf_section_data (hplink->splt->output_section)
-      ->this_hdr.sh_entsize = PLT_ENTRY_SIZE;
+    {
+      /* Set plt entry size.  */
+      elf_section_data (hplink->splt->output_section)
+       ->this_hdr.sh_entsize = PLT_ENTRY_SIZE;
+
+      if (hplink->need_plt_stub)
+       {
+         /* Set up the .plt stub.  */
+         memcpy (hplink->splt->contents
+                 + hplink->splt->_raw_size - sizeof (plt_stub),
+                 plt_stub, sizeof (plt_stub));
+
+         if ((hplink->splt->output_offset
+              + hplink->splt->output_section->vma
+              + hplink->splt->_raw_size)
+             != (hplink->sgot->output_offset
+                 + hplink->sgot->output_section->vma))
+           {
+             (*_bfd_error_handler)
+               (_(".got section not immediately after .plt section"));
+             return false;
+           }
+       }
+    }
 
   return true;
 }
index db500df..b7b59e6 100644 (file)
@@ -37,7 +37,7 @@
 #include "elf/hppa.h"
 
 boolean elf32_hppa_size_stubs
-  PARAMS ((bfd *, bfd *, struct bfd_link_info *, boolean,
+  PARAMS ((bfd *, bfd *, struct bfd_link_info *, boolean, bfd_signed_vma,
           asection * (*) PARAMS ((const char *, asection *)),
           void (*) PARAMS ((void))));
 
index 60bdf65..44d501d 100644 (file)
@@ -6,6 +6,8 @@
        (hppa_fix_adjustable): Undo 2000-09-23 change.
        (hppa_force_relocation): Likewise.  Add fx_addsy assertion.
        Correct distance calculation.
+       (tc_gen_reloc): Print the file name and line number if we can't
+       handle a fixup.
 
        From John David Anglin <dave@hiauly1.hia.nrc.ca>
        * config/tc-hppa.c (nonzero_dibits): Define.
index d69ac30..5431e8e 100644 (file)
@@ -1,3 +1,7 @@
+2000-09-27  Alan Modra  <alan@linuxcare.com.au>
+
+       * hppa.h (R_PARISC_DIR14F): Add.
+
 2000-09-14  Alexandre Oliva  <aoliva@redhat.com>
 
        * sh.h (R_SH_GOT32, R_SH_PLT32, R_SH_COPY, R_SH_GLOB_DAT,
index 1169447..82b4db8 100644 (file)
@@ -121,6 +121,9 @@ RELOC_NUMBER (R_PARISC_DIR17F,               4)
 RELOC_NUMBER (R_PARISC_DIR14R,          6)
 /*             load/store (1)             RR(symbol, addend)             */
 
+RELOC_NUMBER (R_PARISC_DIR14F,          7)
+/*             load/store (1)             symbol, addend                 */
+
 /* PC-relative relocation types
    Typically used for calls.
    Note PCREL17C and PCREL17F differ only in overflow handling.
index 3ae3e01..c4b2a3a 100644 (file)
@@ -1,3 +1,15 @@
+2000-09-28  Alan Modra  <alan@linuxcare.com.au>
+
+       * ld.texinfo (HPPA ELF32): New section.
+
+       * emultempl/hppaelf.em (group_size): New.
+       (hppaelf_finish): Pass group_size to elf32_hppa_size_stubs.
+       (PARSE_AND_LIST_PROLOGUE): Add OPTION_STUBGROUP_SIZE.
+       (PARSE_AND_LIST_LONGOPTS): Add --stub-group-size.  Duplicate
+       options to prevent abbreviations matching.
+       (PARSE_AND_LIST_OPTIONS): Describe the above.  Reformat.
+       (PARSE_AND_LIST_ARGS_CASES): Handle it.
+
 2000-09-21  Michael Sokolov  <msokolov@ivan.Harhan.ORG>
 
        * emultempl/m68kelf.em: Conditionalise the embedded relocs feature
index 3455cc8..065bcdd 100644 (file)
@@ -44,6 +44,10 @@ static lang_input_statement_type *stub_file;
    stubs.  */
 static int multi_subspace = 0;
 
+/* Maximum size of a group of input sections that can be handled by
+   one stub section.  A value of +/-1 indicates the bfd back-end
+   should use a suitable default size.  */
+static bfd_signed_vma group_size = 1;
 
 /* This is called before the input files are opened.  We create a new
    fake input file to hold the stub sections.  */
@@ -292,6 +296,7 @@ hppaelf_finish ()
                               stub_file->the_bfd,
                               &link_info,
                               multi_subspace,
+                              group_size,
                               &hppaelf_add_stub_section,
                               &hppaelf_layaout_sections_again))
     {
@@ -349,16 +354,31 @@ EOF
 #
 PARSE_AND_LIST_PROLOGUE='
 #define OPTION_MULTI_SUBSPACE          301
+#define OPTION_STUBGROUP_SIZE          (OPTION_MULTI_SUBSPACE + 1)
 '
 
+# The options are repeated below so that no abbreviations are allowed.
+# Otherwise -s matches stub-group-size
 PARSE_AND_LIST_LONGOPTS='
-  { "multi-subspace", no_argument, NULL, OPTION_MULTI_SUBSPACE},
+  { "multi-subspace", no_argument, NULL, OPTION_MULTI_SUBSPACE },
+  { "multi-subspace", no_argument, NULL, OPTION_MULTI_SUBSPACE },
+  { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
+  { "stub-group-size", required_argument, NULL, OPTION_STUBGROUP_SIZE },
 '
 
 PARSE_AND_LIST_OPTIONS='
   fprintf (file, _("\
-  --multi-subspace            Generate import and export stubs to support\n\
-                              multiple sub-space shared libraries\n"
+  --multi-subspace    Generate import and export stubs to support\n\
+                        multiple sub-space shared libraries\n"
+                  ));
+  fprintf (file, _("\
+  --stub-group-size=N Maximum size of a group of input sections that can be\n\
+                        handled by one stub section.  A negative value\n\
+                        locates all stubs before their branches (with a\n\
+                        group size of -N), while a positive value allows\n\
+                        two groups of input sections, one before, and one\n\
+                        after each stub section.  Values of +/-1 indicate\n\
+                        the linker should choose suitable defaults."
                   ));
 '
 
@@ -366,6 +386,15 @@ PARSE_AND_LIST_ARGS_CASES='
     case OPTION_MULTI_SUBSPACE:
       multi_subspace = 1;
       break;
+
+    case OPTION_STUBGROUP_SIZE:
+      {
+       const char *end;
+        group_size = bfd_scan_vma (optarg, &end, 0);
+        if (*end)
+         einfo (_("%P%F: invalid number `%s'\''\n"), optarg);
+      }
+      break;
 '
 
 # Put these extra hppaelf routines in ld_${EMULATION_NAME}_emulation
index e907e30..0b898ec 100644 (file)
@@ -3904,6 +3904,7 @@ functionality are not listed.
 * H8/300::                      @code{ld} and the H8/300
 * i960::                        @code{ld} and the Intel 960 family
 * ARM::                                @code{ld} and the ARM family
+* HPPA ELF32::                  @code{ld} and HPPA 32-bit ELF
 @ifset TICOFF
 * TI COFF::                     @code{ld} and TI COFF
 @end ifset
@@ -4047,6 +4048,38 @@ But it also sets the bottom bit of the address, so that it can be
 branched to using a BX instruction, and the program will start
 executing in Thumb mode straight away.
 
+@node HPPA ELF32
+@section @code{ld} and HPPA 32-bit ELF support
+@cindex HPPA multiple sub-space stubs
+@kindex --multi-subspace
+When generating a shared library, @code{ld} will by default generate
+import stubs suitable for use with a single sub-space application.
+The @samp{--multi-subspace} switch causes @code{ld} to generate export
+stubs, and different (larger) import stubs suitable for use with
+multiple sub-spaces.
+
+@cindex HPPA stub grouping
+@kindex --stub-group-size=@var{N}
+Long branch stubs and import/export stubs are placed by @code{ld} in
+stub sections located between groups of input sections.
+@samp{--stub-group-size} specifies the maximum size of a group of input
+sections handled by one stub section.  Since branch offsets are signed,
+a stub section may serve two groups of input sections, one group before
+the stub section, and one group after it.  However, when using
+conditional branches that require stubs, it may be better (for branch
+prediction) that stub sections only serve one group of input sections.
+A negative value for @samp{N} chooses this scheme, ensuring that
+branches to stubs always use a negative offset.  Two special values of
+@samp{N} are recognized, @samp{1} and @samp{-1}.  These both instruct
+@code{ld} to automatically size input section groups for the branch types
+detected, with the same behaviour regarding stub placement as other
+positive or negative values of @samp{N} respectively.
+
+Note that @samp{--stub-group-size} does not split input sections.  A
+single input section larger than the group size specified will of course
+create a larger group (of one section).  If input sections are too
+large, it may not be possible for a branch to reach its stub.
+
 @ifset TICOFF
 @node TI COFF
 @section @code{ld}'s support for various TI COFF versions