X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-hppa.c;h=defd72d18a5253bea3710b090be797a966a1085c;hb=2c73f9d86113b392342ec5a8cff8a42be78bd429;hp=22a6f9ee7c30a0f6356157f7028ca4b0d0283e94;hpb=fe8bc63d5e88ca758de39b16649861c36e8b470a;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-hppa.c b/bfd/elf64-hppa.c index 22a6f9ee7c..defd72d18a 100644 --- a/bfd/elf64-hppa.c +++ b/bfd/elf64-hppa.c @@ -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. @@ -62,7 +62,7 @@ struct elf64_hppa_dyn_hash_entry /* 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 @@ -198,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 *)); @@ -258,6 +266,9 @@ 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; @@ -306,7 +317,7 @@ elf64_hppa_hash_table_create (abfd) { 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, @@ -355,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 @@ -519,7 +557,7 @@ count_dyn_reloc (abfd, dyn_h, type, sec, sec_symndx, offset, addend) 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; @@ -547,6 +585,7 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs) 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; @@ -573,9 +612,11 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs) 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. @@ -586,15 +627,15 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs) 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); @@ -603,36 +644,59 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs) /* 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, esym, 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. */ @@ -709,7 +773,8 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs) 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; @@ -936,7 +1001,7 @@ elf64_hppa_dynamic_symbol_p (h, info) 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))) @@ -1009,8 +1074,8 @@ allocate_global_data_dlt (dyn_h, data) 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; } } @@ -1166,8 +1231,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 @@ -1756,8 +1828,11 @@ elf64_hppa_size_dynamic_sections (output_bfd, info) /* 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 @@ -1767,36 +1842,36 @@ elf64_hppa_size_dynamic_sections (output_bfd, info) 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; } @@ -1954,6 +2029,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. @@ -1975,22 +2051,45 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym) 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 ((int) value); + } + else + { + max_offset = 8192; + insn &= ~ 0x3ff1; + insn |= re_assemble_14 ((int) 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, (bfd_vma) 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 ((int) value); + } + else + { + insn &= ~ 0x3ff1; + insn |= re_assemble_14 ((int) value); + } + bfd_put_32 (stub->owner, (bfd_vma) insn, stub->contents + dyn_h->stub_offset + 8); } @@ -2502,7 +2601,8 @@ elf64_hppa_modify_segment_map (abfd) 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; @@ -2538,6 +2638,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 = @@ -2584,7 +2697,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 @@ -2631,5 +2744,14 @@ const struct elf_size_info hppa64_elf_size_info = #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"