/* Support for HPPA 64-bit ELF
- Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
/* The index of the (possibly local) symbol in the input bfd and its
associated BFD. Needed so that we can have relocs against local
symbols in shared libraries. */
- unsigned long sym_indx;
+ long sym_indx;
bfd *owner;
/* Dynamic symbols may need to have two different values. One for
PARAMS ((bfd *));
static boolean elf64_hppa_section_from_shdr
- PARAMS ((bfd *, Elf64_Internal_Shdr *, char *));
+ PARAMS ((bfd *, Elf64_Internal_Shdr *, const char *));
static void elf64_hppa_post_process_headers
PARAMS ((bfd *, struct bfd_link_info *));
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 *));
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;
{
struct elf64_hppa_link_hash_table *ret;
- ret = bfd_zalloc (abfd, sizeof (*ret));
+ ret = bfd_zalloc (abfd, (bfd_size_type) sizeof (*ret));
if (!ret)
return 0;
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
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
elf64_hppa_section_from_shdr (abfd, hdr, name)
bfd *abfd;
Elf64_Internal_Shdr *hdr;
- char *name;
+ const char *name;
{
asection *newsect;
struct elf64_hppa_dyn_reloc_entry *rent;
rent = (struct elf64_hppa_dyn_reloc_entry *)
- bfd_alloc (abfd, sizeof (*rent));
+ bfd_alloc (abfd, (bfd_size_type) sizeof (*rent));
if (!rent)
return false;
struct elf64_hppa_link_hash_table *hppa_info;
const Elf_Internal_Rela *relend;
Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Shdr *shndx_hdr;
const Elf_Internal_Rela *rel;
asection *dlt, *plt, *stubs;
char *buf;
if (info->shared && hppa_info->section_syms_bfd != abfd)
{
unsigned long i;
- int highest_shndx;
+ unsigned int highest_shndx;
Elf_Internal_Sym *local_syms, *isym;
Elf64_External_Sym *ext_syms, *esym;
+ Elf_External_Sym_Shndx *shndx_buf, *shndx;
+ bfd_size_type amt;
/* We're done with the old cache of section index to section symbol
index information. Free it.
free (hppa_info->section_syms);
/* Allocate memory for the internal and external symbols. */
- local_syms
- = (Elf_Internal_Sym *) bfd_malloc (symtab_hdr->sh_info
- * sizeof (Elf_Internal_Sym));
+ amt = symtab_hdr->sh_info;
+ amt *= sizeof (Elf_Internal_Sym);
+ local_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
if (local_syms == NULL)
return false;
- ext_syms
- = (Elf64_External_Sym *) bfd_malloc (symtab_hdr->sh_info
- * sizeof (Elf64_External_Sym));
+ amt = symtab_hdr->sh_info;
+ amt *= sizeof (Elf64_External_Sym);
+ ext_syms = (Elf64_External_Sym *) bfd_malloc (amt);
if (ext_syms == NULL)
{
free (local_syms);
/* Read in the local symbols. */
if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || bfd_read (ext_syms, 1,
- (symtab_hdr->sh_info
- * sizeof (Elf64_External_Sym)), abfd)
- != (symtab_hdr->sh_info * sizeof (Elf64_External_Sym)))
+ || bfd_bread (ext_syms, amt, abfd) != amt)
{
- free (local_syms);
free (ext_syms);
+ free (local_syms);
return false;
}
+ shndx_buf = NULL;
+ shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
+ if (shndx_hdr->sh_size != 0)
+ {
+ amt = symtab_hdr->sh_info;
+ amt *= sizeof (Elf_External_Sym_Shndx);
+ shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
+ if (shndx_buf == NULL)
+ {
+ free (ext_syms);
+ free (local_syms);
+ return false;
+ }
+
+ if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
+ || bfd_bread (shndx_buf, amt, abfd) != amt)
+ {
+ free (shndx_buf);
+ free (ext_syms);
+ free (local_syms);
+ return false;
+ }
+ }
+
/* Swap in the local symbols, also record the highest section index
referenced by the local symbols. */
- isym = local_syms;
- esym = ext_syms;
highest_shndx = 0;
- for (i = 0; i < symtab_hdr->sh_info; i++, esym++, isym++)
+ for (i = 0, isym = local_syms, esym = ext_syms, shndx = shndx_buf;
+ i < symtab_hdr->sh_info;
+ i++, esym++, isym++, shndx = (shndx != NULL ? shndx + 1 : NULL))
{
- bfd_elf64_swap_symbol_in (abfd, esym, isym);
+ bfd_elf64_swap_symbol_in (abfd, (const PTR) esym, (const PTR) shndx,
+ isym);
if (isym->st_shndx > highest_shndx)
highest_shndx = isym->st_shndx;
}
/* Now we can free the external symbols. */
+ free (shndx_buf);
free (ext_syms);
/* Allocate an array to hold the section index to section symbol index
mapping. Bump by one since we start counting at zero. */
highest_shndx++;
- hppa_info->section_syms = (int *) bfd_malloc (highest_shndx
- * sizeof (int));
+ amt = highest_shndx;
+ amt *= sizeof (int);
+ hppa_info->section_syms = (int *) bfd_malloc (amt);
/* Now walk the local symbols again. If we find a section symbol,
record the index of the symbol into the section_syms array. */
have yet been processed. Do something with what we know, as
this may help reduce memory usage and processing time later. */
maybe_dynamic = false;
- if (h && ((info->shared && ! info->symbolic)
+ if (h && ((info->shared
+ && (!info->symbolic || info->allow_shlib_undefined) )
|| ! (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
|| h->root.type == bfd_link_hash_defweak))
maybe_dynamic = true;
if (h->root.root.string[0] == '$' && h->root.root.string[1] == '$')
return false;
- if ((info->shared && !info->symbolic)
+ if ((info->shared && (!info->symbolic || info->allow_shlib_undefined))
|| ((h->elf_link_hash_flags
& (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR))
== (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
hppa_info = elf64_hppa_hash_table (info);
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
if (h
&& (h->root.type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)
bfd *owner;
owner = (h ? h->root.u.def.section->owner : dyn_h->owner);
- if (!_bfd_elf64_link_record_local_dynamic_symbol
- (x->info, owner, dyn_h->sym_indx))
+ if (! (_bfd_elf64_link_record_local_dynamic_symbol
+ (x->info, owner, dyn_h->sym_indx)))
return false;
}
}
/* Always create a DT_PLTGOT. It actually has nothing to do with
the PLT, it is how we communicate the __gp value of a load
module to the dynamic linker. */
- if (! bfd_elf64_add_dynamic_entry (info, DT_HP_DLD_FLAGS, 0)
- || ! bfd_elf64_add_dynamic_entry (info, DT_PLTGOT, 0))
+#define add_dynamic_entry(TAG, VAL) \
+ bfd_elf64_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
+ if (!add_dynamic_entry (DT_HP_DLD_FLAGS, 0)
+ || !add_dynamic_entry (DT_PLTGOT, 0))
return false;
/* Add some entries to the .dynamic section. We fill in the
dynamic linker and used by the debugger. */
if (! info->shared)
{
- if (! bfd_elf64_add_dynamic_entry (info, DT_DEBUG, 0)
- || ! bfd_elf64_add_dynamic_entry (info, DT_HP_DLD_HOOK, 0)
- || ! bfd_elf64_add_dynamic_entry (info, DT_HP_LOAD_MAP, 0))
+ if (!add_dynamic_entry (DT_DEBUG, 0)
+ || !add_dynamic_entry (DT_HP_DLD_HOOK, 0)
+ || !add_dynamic_entry (DT_HP_LOAD_MAP, 0))
return false;
}
if (plt)
{
- if (! bfd_elf64_add_dynamic_entry (info, DT_PLTRELSZ, 0)
- || ! bfd_elf64_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
- || ! bfd_elf64_add_dynamic_entry (info, DT_JMPREL, 0))
+ if (!add_dynamic_entry (DT_PLTRELSZ, 0)
+ || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+ || !add_dynamic_entry (DT_JMPREL, 0))
return false;
}
if (relocs)
{
- if (! bfd_elf64_add_dynamic_entry (info, DT_RELA, 0)
- || ! bfd_elf64_add_dynamic_entry (info, DT_RELASZ, 0)
- || ! bfd_elf64_add_dynamic_entry (info, DT_RELAENT,
- sizeof (Elf64_External_Rela)))
+ if (!add_dynamic_entry (DT_RELA, 0)
+ || !add_dynamic_entry (DT_RELASZ, 0)
+ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
return false;
}
if (reltext)
{
- if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
+ if (!add_dynamic_entry (DT_TEXTREL, 0))
return false;
info->flags |= DF_TEXTREL;
}
}
+#undef add_dynamic_entry
return true;
}
/* Wide mode allows 16 bit offsets. */
max_offset = 32768;
insn &= ~ 0xfff1;
- insn |= re_assemble_16 (value);
+ insn |= re_assemble_16 ((int) value);
}
else
{
max_offset = 8192;
insn &= ~ 0x3ff1;
- insn |= re_assemble_14 (value);
+ insn |= re_assemble_14 ((int) value);
}
if ((value & 7) || value + max_offset >= 2*max_offset - 8)
return false;
}
- bfd_put_32 (stub->owner, insn,
+ bfd_put_32 (stub->owner, (bfd_vma) insn,
stub->contents + dyn_h->stub_offset);
/* Fix up the second ldd instruction. */
if (output_bfd->arch_info->mach >= 25)
{
insn &= ~ 0xfff1;
- insn |= re_assemble_16 (value);
+ insn |= re_assemble_16 ((int) value);
}
else
{
insn &= ~ 0x3ff1;
- insn |= re_assemble_14 (value);
+ insn |= re_assemble_14 ((int) value);
}
- bfd_put_32 (stub->owner, insn,
+ bfd_put_32 (stub->owner, (bfd_vma) insn,
stub->contents + dyn_h->stub_offset + 8);
}
break;
if (m == NULL)
{
- m = (struct elf_segment_map *) bfd_zalloc (abfd, sizeof *m);
+ m = ((struct elf_segment_map *)
+ bfd_zalloc (abfd, (bfd_size_type) sizeof *m));
if (m == NULL)
return false;
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 =
bfd_elf64_write_out_phdrs,
bfd_elf64_write_shdrs_and_ehdr,
bfd_elf64_write_relocs,
+ bfd_elf64_swap_symbol_in,
bfd_elf64_swap_symbol_out,
bfd_elf64_slurp_reloc_table,
bfd_elf64_slurp_symbol_table,
#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
#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"