* ld.texinfo: Document that fill values now use the four least
[deliverable/binutils-gdb.git] / bfd / elf64-hppa.c
index b90b47878f00c7f28a3ee44df8cb8bed8ab5cbe1..12a164160a820e2b87f5b3325129d5d2bc01db19 100644 (file)
@@ -1,5 +1,5 @@
-/* Generic support for 64-bit ELF
-   Copyright 1999, 2000 Free Software Foundation, Inc.
+/* Support for HPPA 64-bit ELF
+   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of BFD, the Binary File Descriptor library.
 
@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#include "alloca-conf.h"
 #include "bfd.h"
 #include "sysdep.h"
 #include "libbfd.h"
@@ -29,7 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define PLT_ENTRY_SIZE 0x10
 #define DLT_ENTRY_SIZE 0x8
 #define OPD_ENTRY_SIZE 0x20
+
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/pa20_64/dld.sl"
 
 /* The stub is supposed to load the target address and target's DP
@@ -168,19 +169,17 @@ static struct elf64_hppa_dyn_hash_entry *elf64_hppa_dyn_hash_lookup
           boolean create, boolean copy));
 static void elf64_hppa_dyn_hash_traverse
   PARAMS ((struct elf64_hppa_dyn_hash_table *table,
-          boolean (*func)(struct elf64_hppa_dyn_hash_entry *, PTR),
+          boolean (*func) (struct elf64_hppa_dyn_hash_entry *, PTR),
           PTR info));
 
 static const char *get_dyn_name
   PARAMS ((asection *, struct elf_link_hash_entry *,
           const Elf_Internal_Rela *, char **, size_t *));
 
-
 /* This must follow the definitions of the various derived linker
    hash tables and shared functions.  */
 #include "elf-hppa.h"
 
-
 static boolean elf64_hppa_object_p
   PARAMS ((bfd *));
 
@@ -199,10 +198,18 @@ static boolean elf64_hppa_adjust_dynamic_symbol
 static boolean elf64_hppa_size_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 
+static boolean elf64_hppa_link_output_symbol_hook
+PARAMS ((bfd *abfd, struct bfd_link_info *, const char *,
+        Elf_Internal_Sym *, asection *input_sec));
+
 static boolean elf64_hppa_finish_dynamic_symbol
   PARAMS ((bfd *, struct bfd_link_info *,
           struct elf_link_hash_entry *, Elf_Internal_Sym *));
-       
+
+static int elf64_hppa_additional_program_headers PARAMS ((bfd *));
+
+static boolean elf64_hppa_modify_segment_map PARAMS ((bfd *));
+
 static boolean elf64_hppa_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 
@@ -259,13 +266,16 @@ static boolean get_dlt
 static boolean get_stub
   PARAMS ((bfd *, struct bfd_link_info *, struct elf64_hppa_link_hash_table *));
 
+static int elf64_hppa_elf_get_symbol_type
+  PARAMS ((Elf_Internal_Sym *, int));
+
 static boolean
 elf64_hppa_dyn_hash_table_init (ht, abfd, new)
      struct elf64_hppa_dyn_hash_table *ht;
      bfd *abfd ATTRIBUTE_UNUSED;
      new_hash_entry_func new;
 {
-  memset (ht, 0, sizeof(*ht));
+  memset (ht, 0, sizeof (*ht));
   return bfd_hash_table_init (&ht->root, new);
 }
 
@@ -288,7 +298,7 @@ elf64_hppa_new_dyn_hash_entry (entry, table, string)
 
   /* Initialize our local data.  All zeros, and definitely easier
      than setting 8 bit fields.  */
-  memset (ret, 0, sizeof(*ret));
+  memset (ret, 0, sizeof (*ret));
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct elf64_hppa_dyn_hash_entry *)
@@ -356,8 +366,35 @@ static boolean
 elf64_hppa_object_p (abfd)
      bfd *abfd;
 {
-  /* Set the right machine number for an HPPA ELF file.  */
-  return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 25);
+  Elf_Internal_Ehdr * i_ehdrp;
+  unsigned int flags;
+
+  i_ehdrp = elf_elfheader (abfd);
+  if (strcmp (bfd_get_target (abfd), "elf64-hppa-linux") == 0)
+    {
+      if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_LINUX)
+       return false;
+    }
+  else
+    {
+      if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_HPUX)
+       return false;
+    }
+
+  flags = i_ehdrp->e_flags;
+  switch (flags & (EF_PARISC_ARCH | EF_PARISC_WIDE))
+    {
+    case EFA_PARISC_1_0:
+      return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 10);
+    case EFA_PARISC_1_1:
+      return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 11);
+    case EFA_PARISC_2_0:
+      return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 20);
+    case EFA_PARISC_2_0 | EF_PARISC_WIDE:
+      return bfd_default_set_arch_mach (abfd, bfd_arch_hppa, 25);
+    }
+  /* Don't be fussy.  */
+  return true;
 }
 
 /* Given section type (hdr->sh_type), return a boolean indicating
@@ -393,9 +430,8 @@ elf64_hppa_section_from_shdr (abfd, hdr, name)
   return true;
 }
 
-
 /* Construct a string for use in the elf64_hppa_dyn_hash_table.  The
-   name describes what was once potentially anonymous memory.  We 
+   name describes what was once potentially anonymous memory.  We
    allocate memory as necessary, possibly reusing PBUF/PLEN.  */
 
 static const char *
@@ -502,7 +538,7 @@ get_reloc_section (abfd, hppa_info, sec)
   return true;
 }
 
-/* Add a new entry to the list of dynamic relocations against DYN_H. 
+/* Add a new entry to the list of dynamic relocations against DYN_H.
 
    We use this to keep a record of all the FPTR relocations against a
    particular symbol so that we can create FPTR relocations in the
@@ -571,10 +607,10 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
 
   /* If necessary, build a new table holding section symbols indices
      for this BFD.  This is disgusting.  */
+
   if (info->shared && hppa_info->section_syms_bfd != abfd)
     {
-      unsigned int i;
+      unsigned long i;
       int highest_shndx;
       Elf_Internal_Sym *local_syms, *isym;
       Elf64_External_Sym *ext_syms, *esym;
@@ -668,7 +704,7 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
     }
   else
     sec_symndx = 0;
+
   dlt = plt = stubs = NULL;
   buf = NULL;
   buf_len = 0;
@@ -748,6 +784,7 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
        /* These are function calls.  Depending on their precise target we
           may need to make a stub for them.  The stub uses the PLT, so we
           need to create PLT entries for these symbols too.  */
+       case R_PARISC_PCREL12F:
        case R_PARISC_PCREL17F:
        case R_PARISC_PCREL22F:
        case R_PARISC_PCREL32:
@@ -867,7 +904,7 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
 
          /* FPTRs are not allocated by the dynamic linker for PA64, though
             it is possible that will change in the future.  */
-           
+
          /* This could be a local function that had its address taken, in
             which case H will be NULL.  */
          if (h)
@@ -978,6 +1015,8 @@ elf64_hppa_mark_exported_functions (h, data)
        return false;
 
       dyn_h->want_opd = 1;
+      /* Put a flag here for output_symbol_hook.  */
+      dyn_h->st_shndx = -1;
       h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
     }
 
@@ -1081,7 +1120,7 @@ allocate_global_data_opd (dyn_h, data)
   if (dyn_h->want_opd)
     {
       struct elf_link_hash_entry *h = dyn_h->h;
-      
+
       if (h)
        while (h->root.type == bfd_link_hash_indirect
               || h->root.type == bfd_link_hash_warning)
@@ -1165,8 +1204,15 @@ elf64_hppa_post_process_headers (abfd, link_info)
 
   i_ehdrp = elf_elfheader (abfd);
 
-  i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_HPUX;
-  i_ehdrp->e_ident[EI_ABIVERSION] = 1;
+  if (strcmp (bfd_get_target (abfd), "elf64-hppa-linux") == 0)
+    {
+      i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_LINUX;
+    }
+  else
+    {
+      i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_HPUX;
+      i_ehdrp->e_ident[EI_ABIVERSION] = 1;
+    }
 }
 
 /* Create function descriptor section (.opd).  This section is called .opd
@@ -1358,7 +1404,7 @@ get_stub (abfd, info, hppa_info)
        Should contain dynamic IPLT (and EPLT?) relocations.
 
    .opd:
-       FPTRS 
+       FPTRS
 
    .rela.opd:
        EPLT relocations for symbols exported from shared libraries.  */
@@ -1737,10 +1783,14 @@ elf64_hppa_size_dynamic_sections (output_bfd, info)
        }
 
       /* Allocate memory for the section contents if it has not
-        been allocated already.  */
+        been allocated already.  We use bfd_zalloc here in case
+        unused entries are not reclaimed before the section's
+        contents are written out.  This should not happen, but this
+        way if it does, we get a R_PARISC_NONE reloc instead of
+        garbage.  */
       if (s->contents == NULL)
        {
-         s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
+         s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
          if (s->contents == NULL && s->_raw_size != 0)
            return false;
        }
@@ -1789,6 +1839,7 @@ elf64_hppa_size_dynamic_sections (output_bfd, info)
        {
          if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
            return false;
+         info->flags |= DF_TEXTREL;
        }
     }
 
@@ -1825,13 +1876,18 @@ elf64_hppa_link_output_symbol_hook (abfd, info, name, sym, input_sec)
   dyn_h = elf64_hppa_dyn_hash_lookup (&hppa_info->dyn_hash_table,
                                      name, false, false);
 
-  /* Function symbols for which we created .opd entries were munged
-     by finish_dynamic_symbol and have to be un-munged here.  */
-  if (dyn_h && dyn_h->want_opd)
+  /* Function symbols for which we created .opd entries *may* have been
+     munged by finish_dynamic_symbol and have to be un-munged here.
+
+     Note that finish_dynamic_symbol sometimes turns dynamic symbols
+     into non-dynamic ones, so we initialize st_shndx to -1 in
+     mark_exported_functions and check to see if it was overwritten
+     here instead of just checking dyn_h->h->dynindx.  */
+  if (dyn_h && dyn_h->want_opd && dyn_h->st_shndx != -1)
     {
       /* Restore the saved value and section index.  */
       sym->st_value = dyn_h->st_value;
-      sym->st_shndx = dyn_h->st_shndx; 
+      sym->st_shndx = dyn_h->st_shndx;
     }
 
   return true;
@@ -1904,13 +1960,13 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
       else
        value = (h->root.u.def.value + h->root.u.def.section->vma);
 
-      /* Fill in the entry in the procedure linkage table. 
+      /* Fill in the entry in the procedure linkage table.
 
         The format of a plt entry is
-        <funcaddr> <__gp>. 
+        <funcaddr> <__gp>.
 
         plt_offset is the offset within the PLT section at which to
-        install the PLT entry. 
+        install the PLT entry.
 
         We are modifying the in-memory PLT contents here, so we do not add
         in the output_offset of the PLT section.  */
@@ -1943,6 +1999,7 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
     {
       bfd_vma value;
       int insn;
+      unsigned int max_offset;
 
       /* Install the generic stub template.
 
@@ -1953,7 +2010,7 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
       /* Fix up the first ldd instruction.
 
         We are modifying the contents of the STUB section in memory,
-        so we do not need to include its output offset in this computation. 
+        so we do not need to include its output offset in this computation.
 
         Note the plt_offset value is the value of the PLT entry relative to
         the start of the PLT section.  These instructions will reference
@@ -1962,24 +2019,47 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
 
         gp_offset contains the offset of __gp within the PLT section.  */
       value = dyn_h->plt_offset - hppa_info->gp_offset;
-      
+
       insn = bfd_get_32 (stub->owner, stub->contents + dyn_h->stub_offset);
-      insn &= 0xffffc00e;
-      insn |= ((value & 0x2000) >> 13);
-      value &= 0x1ff8;
-      value <<= 1;
-      bfd_put_32 (stub->owner, (insn | value),
+      if (output_bfd->arch_info->mach >= 25)
+       {
+         /* Wide mode allows 16 bit offsets.  */
+         max_offset = 32768;
+         insn &= ~ 0xfff1;
+         insn |= re_assemble_16 (value);
+       }
+      else
+       {
+         max_offset = 8192;
+         insn &= ~ 0x3ff1;
+         insn |= re_assemble_14 (value);
+       }
+
+      if ((value & 7) || value + max_offset >= 2*max_offset - 8)
+       {
+         (*_bfd_error_handler) (_("stub entry for %s cannot load .plt, dp offset = %ld"),
+                                dyn_h->root.string,
+                                (long) value);
+         return false;
+       }
+
+      bfd_put_32 (stub->owner, insn,
                  stub->contents + dyn_h->stub_offset);
 
       /* Fix up the second ldd instruction.  */
-      value = dyn_h->plt_offset - hppa_info->gp_offset + 8;
-      
+      value += 8;
       insn = bfd_get_32 (stub->owner, stub->contents + dyn_h->stub_offset + 8);
-      insn &= 0xffffc00e;
-      insn |= ((value & 0x2000) >> 13);
-      value &= 0x1ff8;
-      value <<= 1;
-      bfd_put_32 (stub->owner, (insn | value),
+      if (output_bfd->arch_info->mach >= 25)
+       {
+         insn &= ~ 0xfff1;
+         insn |= re_assemble_16 (value);
+       }
+      else
+       {
+         insn &= ~ 0x3ff1;
+         insn |= re_assemble_14 (value);
+       }
+      bfd_put_32 (stub->owner, insn,
                  stub->contents + dyn_h->stub_offset + 8);
     }
 
@@ -2013,7 +2093,7 @@ elf64_hppa_finalize_opd (dyn_h, data)
     {
       bfd_vma value;
 
-      /* The first two words of an .opd entry are zero. 
+      /* The first two words of an .opd entry are zero.
 
         We are modifying the contents of the OPD section in memory, so we
         do not need to include its output offset in this computation.  */
@@ -2066,7 +2146,7 @@ elf64_hppa_finalize_opd (dyn_h, data)
         (if we did, the data in the .opd would reference itself rather
         than the actual address of the function).  Instead we have to use
         a new dynamic symbol which has the same value as the original global
-        function symbol. 
+        function symbol.
 
         We prefix the original symbol with a "." and use the new symbol in
         the EPLT relocation.  This new symbol has already been recorded in
@@ -2138,7 +2218,7 @@ elf64_hppa_finalize_dlt (dyn_h, data)
       bfd_vma value;
 
       /* If we had an LTOFF_FPTR style relocation we want the DLT entry
-        to point to the FPTR entry in the .opd section. 
+        to point to the FPTR entry in the .opd section.
 
         We include the OPD's output offset in this computation as
         we are referring to an absolute address in the resulting
@@ -2183,7 +2263,6 @@ elf64_hppa_finalize_dlt (dyn_h, data)
          = _bfd_elf_link_lookup_local_dynindx (info, dyn_h->owner,
                                                dyn_h->sym_indx);
 
-
       /* Create a dynamic relocation for this entry.  Do include the output
         offset of the DLT entry since we need an absolute address in the
         resulting object file.  */
@@ -2255,7 +2334,7 @@ elf64_hppa_finalize_dynreloc (dyn_h, data)
              break;
            }
 
-         /* Create a dynamic relocation for this entry. 
+         /* Create a dynamic relocation for this entry.
 
             We need the output offset for the reloc's section because
             we are creating an absolute address in the resulting object
@@ -2278,7 +2357,7 @@ elf64_hppa_finalize_dynreloc (dyn_h, data)
             the .opd entry.  At least that seems sensible until you
             realize there's no local dynamic symbols we can use for that
             purpose.  Thus the hair in the check_relocs routine.
-       
+
             We use a section symbol recorded by check_relocs as the
             base symbol for the relocation.  The addend is the difference
             between the section symbol and the address of the .opd entry.  */
@@ -2299,7 +2378,7 @@ elf64_hppa_finalize_dynreloc (dyn_h, data)
              /* Compute the difference between the start of the section
                 with the relocation and the opd entry.  */
              value -= value2;
-               
+
              /* The result becomes the addend of the relocation.  */
              rel.r_addend = value;
 
@@ -2356,7 +2435,6 @@ elf64_hppa_finish_dynamic_sections (output_bfd, info)
                                elf64_hppa_finalize_dlt,
                                info);
 
-
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -2439,11 +2517,10 @@ elf64_hppa_finish_dynamic_sections (output_bfd, info)
   return true;
 }
 
-
 /* Return the number of additional phdrs we will need.
 
    The generic ELF code only creates PT_PHDRs for executables.  The HP
-   dynamic linker requires PT_PHDRs for dynamic libraries too. 
+   dynamic linker requires PT_PHDRs for dynamic libraries too.
 
    This routine indicates that the backend needs one additional program
    header for that case.
@@ -2470,10 +2547,10 @@ elf64_hppa_additional_program_headers (abfd)
    specific backend.
 
    The generic ELF code only creates PT_PHDRs for executables.  The HP
-   dynamic linker requires PT_PHDRs for dynamic libraries too. 
+   dynamic linker requires PT_PHDRs for dynamic libraries too.
 
    This allocates the PT_PHDR and initializes it in a manner suitable
-   for the HP linker. 
+   for the HP linker.
 
    Note we do not have access to the link info structure here, so we have
    to guess whether or not we are building a shared library based on the
@@ -2530,6 +2607,19 @@ elf64_hppa_modify_segment_map (abfd)
   return true;
 }
 
+/* Called when writing out an object file to decide the type of a
+   symbol.  */
+static int
+elf64_hppa_elf_get_symbol_type (elf_sym, type)
+     Elf_Internal_Sym *elf_sym;
+     int type;
+{
+  if (ELF_ST_TYPE (elf_sym->st_info) == STT_PARISC_MILLI)
+    return STT_PARISC_MILLI;
+  else
+    return type;
+}
+
 /* The hash bucket size is the standard one, namely 4.  */
 
 const struct elf_size_info hppa64_elf_size_info =
@@ -2576,7 +2666,7 @@ const struct elf_size_info hppa64_elf_size_info =
 #define elf_backend_object_p           elf64_hppa_object_p
 #define elf_backend_final_write_processing \
                                        elf_hppa_final_write_processing
-#define elf_backend_fake_sections      elf_hppa_fake_sections
+#define elf_backend_fake_sections      elf_hppa_fake_sections
 #define elf_backend_add_symbol_hook    elf_hppa_add_symbol_hook
 
 #define elf_backend_relocate_section       elf_hppa_relocate_section
@@ -2617,12 +2707,20 @@ const struct elf_size_info hppa64_elf_size_info =
 #define elf_backend_link_output_symbol_hook \
        elf64_hppa_link_output_symbol_hook
 
-
 #define elf_backend_want_got_plt       0
 #define elf_backend_plt_readonly       0
 #define elf_backend_want_plt_sym       0
 #define elf_backend_got_header_size     0
 #define elf_backend_plt_header_size     0
 #define elf_backend_type_change_ok true
+#define elf_backend_get_symbol_type         elf64_hppa_elf_get_symbol_type
+
+#include "elf64-target.h"
+
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM                 bfd_elf64_hppa_linux_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME                        "elf64-hppa-linux"
 
+#define INCLUDED_TARGET_FILE 1
 #include "elf64-target.h"
This page took 0.030215 seconds and 4 git commands to generate.