X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-ia64.c;h=878511bb828c3f14baadb4e89ea52faa09014a39;hb=de9811afe23bbdd0cb72c7c05d7136aebf9e75c9;hp=f98e4ee188d10f1c8bf241b8249a117ea4930d88;hpb=02e6ad56bfb2c9360a3932d17e6c834ab99a3666;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index f98e4ee188..878511bb82 100644 --- a/bfd/elfxx-ia64.c +++ b/bfd/elfxx-ia64.c @@ -24,6 +24,8 @@ #include "elf-bfd.h" #include "opcode/ia64.h" #include "elf/ia64.h" +#include "objalloc.h" +#include "hashtab.h" /* THE RULES for all the stuff the linker creates -- @@ -51,7 +53,7 @@ descriptor for a MIN_PLT entry, and requires one IPLT reloc. MIN_PLT Created by PLTOFF entries against dynamic symbols. This - does not reqire dynamic relocations. */ + does not require dynamic relocations. */ #define NELEMS(a) ((int) (sizeof (a) / sizeof ((a)[0]))) @@ -79,7 +81,7 @@ struct elfNN_ia64_dyn_sym_info bfd_vma dtpmod_offset; bfd_vma dtprel_offset; - /* The symbol table entry, if any, that this was derrived from. */ + /* The symbol table entry, if any, that this was derived from. */ struct elf_link_hash_entry *h; /* Used to count non-got, non-plt relocations for delayed sizing @@ -90,6 +92,9 @@ struct elfNN_ia64_dyn_sym_info asection *srel; int type; int count; + + /* Is this reloc against readonly section? */ + bfd_boolean reltext; } *reloc_entries; /* TRUE when the section contents have been updated. */ @@ -115,7 +120,8 @@ struct elfNN_ia64_dyn_sym_info struct elfNN_ia64_local_hash_entry { - struct bfd_hash_entry root; + int id; + unsigned int r_sym; struct elfNN_ia64_dyn_sym_info *info; /* TRUE if this hash entry's addends was translated for @@ -123,12 +129,6 @@ struct elfNN_ia64_local_hash_entry unsigned sec_merge_done : 1; }; -struct elfNN_ia64_local_hash_table -{ - struct bfd_hash_table root; - /* No additional fields for now. */ -}; - struct elfNN_ia64_link_hash_entry { struct elf_link_hash_entry root; @@ -153,7 +153,8 @@ struct elfNN_ia64_link_hash_table unsigned self_dtpmod_done : 1;/* has self DTPMOD entry been finished? */ bfd_vma self_dtpmod_offset; /* .got offset to self DTPMOD entry */ - struct elfNN_ia64_local_hash_table loc_hash_table; + htab_t loc_hash_table; + void *loc_hash_memory; }; struct elfNN_ia64_allocate_data @@ -196,34 +197,30 @@ static bfd_boolean elfNN_ia64_add_symbol_hook static int elfNN_ia64_additional_program_headers PARAMS ((bfd *abfd)); static bfd_boolean elfNN_ia64_modify_segment_map - PARAMS ((bfd *)); + PARAMS ((bfd *, struct bfd_link_info *)); static bfd_boolean elfNN_ia64_is_local_label_name PARAMS ((bfd *abfd, const char *name)); static bfd_boolean elfNN_ia64_dynamic_symbol_p - PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info)); -static bfd_boolean elfNN_ia64_local_hash_table_init - PARAMS ((struct elfNN_ia64_local_hash_table *ht, bfd *abfd, - new_hash_entry_func new)); -static struct bfd_hash_entry *elfNN_ia64_new_loc_hash_entry - PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table, - const char *string)); + PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info, int)); static struct bfd_hash_entry *elfNN_ia64_new_elf_hash_entry PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table, const char *string)); static void elfNN_ia64_hash_copy_indirect - PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *, + PARAMS ((const struct elf_backend_data *, struct elf_link_hash_entry *, struct elf_link_hash_entry *)); static void elfNN_ia64_hash_hide_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean)); +static hashval_t elfNN_ia64_local_htab_hash PARAMS ((const void *)); +static int elfNN_ia64_local_htab_eq PARAMS ((const void *ptr1, + const void *ptr2)); static struct bfd_link_hash_table *elfNN_ia64_hash_table_create PARAMS ((bfd *abfd)); -static struct elfNN_ia64_local_hash_entry *elfNN_ia64_local_hash_lookup - PARAMS ((struct elfNN_ia64_local_hash_table *table, const char *string, - bfd_boolean create, bfd_boolean copy)); +static void elfNN_ia64_hash_table_free + PARAMS ((struct bfd_link_hash_table *hash)); static bfd_boolean elfNN_ia64_global_dyn_sym_thunk PARAMS ((struct bfd_hash_entry *, PTR)); -static bfd_boolean elfNN_ia64_local_dyn_sym_thunk - PARAMS ((struct bfd_hash_entry *, PTR)); +static int elfNN_ia64_local_dyn_sym_thunk + PARAMS ((void **, PTR)); static void elfNN_ia64_dyn_sym_traverse PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, bfd_boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR), @@ -249,9 +246,6 @@ static asection *get_pltoff static asection *get_reloc_section PARAMS ((bfd *abfd, struct elfNN_ia64_link_hash_table *ia64_info, asection *sec, bfd_boolean create)); -static bfd_boolean count_dyn_reloc - PARAMS ((bfd *abfd, struct elfNN_ia64_dyn_sym_info *dyn_i, - asection *srel, int type)); static bfd_boolean elfNN_ia64_check_relocs PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec, const Elf_Internal_Rela *relocs)); @@ -446,21 +440,21 @@ static reloc_howto_type ia64_howto_table[] = IA64_HOWTO (R_IA64_TPREL14, "TPREL14", 0, FALSE, FALSE), IA64_HOWTO (R_IA64_TPREL22, "TPREL22", 0, FALSE, FALSE), IA64_HOWTO (R_IA64_TPREL64I, "TPREL64I", 0, FALSE, FALSE), - IA64_HOWTO (R_IA64_TPREL64MSB, "TPREL64MSB", 8, FALSE, FALSE), - IA64_HOWTO (R_IA64_TPREL64LSB, "TPREL64LSB", 8, FALSE, FALSE), + IA64_HOWTO (R_IA64_TPREL64MSB, "TPREL64MSB", 4, FALSE, FALSE), + IA64_HOWTO (R_IA64_TPREL64LSB, "TPREL64LSB", 4, FALSE, FALSE), IA64_HOWTO (R_IA64_LTOFF_TPREL22, "LTOFF_TPREL22", 0, FALSE, FALSE), - IA64_HOWTO (R_IA64_DTPMOD64MSB, "TPREL64MSB", 8, FALSE, FALSE), - IA64_HOWTO (R_IA64_DTPMOD64LSB, "TPREL64LSB", 8, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPMOD64MSB, "TPREL64MSB", 4, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPMOD64LSB, "TPREL64LSB", 4, FALSE, FALSE), IA64_HOWTO (R_IA64_LTOFF_DTPMOD22, "LTOFF_DTPMOD22", 0, FALSE, FALSE), IA64_HOWTO (R_IA64_DTPREL14, "DTPREL14", 0, FALSE, FALSE), IA64_HOWTO (R_IA64_DTPREL22, "DTPREL22", 0, FALSE, FALSE), IA64_HOWTO (R_IA64_DTPREL64I, "DTPREL64I", 0, FALSE, FALSE), - IA64_HOWTO (R_IA64_DTPREL32MSB, "DTPREL32MSB", 4, FALSE, FALSE), - IA64_HOWTO (R_IA64_DTPREL32LSB, "DTPREL32LSB", 4, FALSE, FALSE), - IA64_HOWTO (R_IA64_DTPREL64MSB, "DTPREL64MSB", 8, FALSE, FALSE), - IA64_HOWTO (R_IA64_DTPREL64LSB, "DTPREL64LSB", 8, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPREL32MSB, "DTPREL32MSB", 2, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPREL32LSB, "DTPREL32LSB", 2, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPREL64MSB, "DTPREL64MSB", 4, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPREL64LSB, "DTPREL64LSB", 4, FALSE, FALSE), IA64_HOWTO (R_IA64_LTOFF_DTPREL22, "LTOFF_DTPREL22", 0, FALSE, FALSE), }; @@ -656,6 +650,58 @@ static const bfd_byte oor_brl[16] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* brl.sptk.few tgt;; */ 0x00, 0x00, 0x00, 0xc0 }; + +static const bfd_byte oor_ip[48] = +{ + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, /* movl r15=0 */ + 0x01, 0x00, 0x00, 0x60, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MII] nop.m 0 */ + 0x00, 0x01, 0x00, 0x60, 0x00, 0x00, /* mov r16=ip;; */ + 0xf2, 0x80, 0x00, 0x80, /* add r16=r15,r16;; */ + 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MIB] nop.m 0 */ + 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */ + 0x60, 0x00, 0x80, 0x00 /* br b6;; */ +}; + +static size_t oor_branch_size = sizeof (oor_brl); + +void +bfd_elfNN_ia64_after_parse (int itanium) +{ + oor_branch_size = itanium ? sizeof (oor_ip) : sizeof (oor_brl); +} + +static void +elfNN_ia64_relax_brl (bfd *abfd, bfd_byte *contents, bfd_vma off) +{ + int template; + bfd_byte *hit_addr; + bfd_vma t0, t1, i0, i1, i2; + + hit_addr = (bfd_byte *) (contents + off); + hit_addr -= (long) hit_addr & 0x3; + t0 = bfd_get_64 (abfd, hit_addr); + t1 = bfd_get_64 (abfd, hit_addr + 8); + + /* Keep the instruction in slot 0. */ + i0 = (t0 >> 5) & 0x1ffffffffffLL; + /* Use nop.b for slot 1. */ + i1 = 0x4000000000LL; + /* For slot 2, turn brl into br by masking out bit 40. */ + i2 = (t1 >> 23) & 0x0ffffffffffLL; + + /* Turn a MLX bundle into a MBB bundle with the same stop-bit + variety. */ + template = 0x12; + if ((t0 & 0x1fLL) == 5) + template += 1; + t0 = (i1 << 46) | (i0 << 5) | template; + t1 = (i2 << 23) | (i1 >> 18); + + bfd_put_64 (abfd, t0, hit_addr); + bfd_put_64 (abfd, t1, hit_addr + 8); +} /* These functions do relaxation for IA-64 ELF. */ @@ -691,14 +737,14 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) *again = FALSE; /* Don't even try to relax for non-ELF outputs. */ - if (link_info->hash->creator->flavour != bfd_target_elf_flavour) + if (!is_elf_hash_table (link_info->hash)) return FALSE; /* Nothing to do if there are no relocations or there is no need for the relax finalize pass. */ if ((sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0 - || (link_info->relax_finalizing + || (!link_info->need_relax_finalize && sec->need_finalize_relax == 0)) return TRUE; @@ -749,14 +795,31 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) case R_IA64_PCREL21BI: case R_IA64_PCREL21M: case R_IA64_PCREL21F: - if (link_info->relax_finalizing) + /* In the finalize pass, all br relaxations are done. We can + skip it. */ + if (!link_info->need_relax_finalize) continue; is_branch = TRUE; break; + case R_IA64_PCREL60B: + /* We can't optimize brl to br before the finalize pass since + br relaxations will increase the code size. Defer it to + the finalize pass. */ + if (link_info->need_relax_finalize) + { + sec->need_finalize_relax = 1; + continue; + } + is_branch = TRUE; + break; + case R_IA64_LTOFF22X: case R_IA64_LDXMOV: - if (!link_info->relax_finalizing) + /* We can't relax ldx/mov before the finalize pass since + br relaxations will increase the code size. Defer it to + the finalize pass. */ + if (link_info->need_relax_finalize) { sec->need_finalize_relax = 1; continue; @@ -788,7 +851,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) isym = isymbuf + ELFNN_R_SYM (irel->r_info); if (isym->st_shndx == SHN_UNDEF) - continue; /* We can't do anthing with undefined symbols. */ + continue; /* We can't do anything with undefined symbols. */ else if (isym->st_shndx == SHN_ABS) tsec = bfd_abs_section_ptr; else if (isym->st_shndx == SHN_COMMON) @@ -831,12 +894,12 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) } /* Can't do anything else with dynamic symbols. */ - else if (elfNN_ia64_dynamic_symbol_p (h, link_info)) + else if (elfNN_ia64_dynamic_symbol_p (h, link_info, r_type)) continue; else { - /* We can't do anthing with undefined symbols. */ + /* We can't do anything with undefined symbols. */ if (h->root.type == bfd_link_hash_undefined || h->root.type == bfd_link_hash_undefweak) continue; @@ -860,6 +923,8 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) if (is_branch) { + bfd_signed_vma offset; + reladdr = (sec->output_section->vma + sec->output_offset + roff) & (bfd_vma) -4; @@ -867,6 +932,25 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) /* If the branch is in range, no need to do anything. */ if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000 && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0) + { + /* If the 60-bit branch is in 21-bit range, optimize it. */ + if (r_type == R_IA64_PCREL60B) + { + elfNN_ia64_relax_brl (abfd, contents, roff); + + irel->r_info + = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), + R_IA64_PCREL21B); + + /* If the original relocation offset points to slot + 1, change it to slot 2. */ + if ((irel->r_offset & 3) == 1) + irel->r_offset += 1; + } + + continue; + } + else if (r_type == R_IA64_PCREL60B) continue; /* If the branch and target are in the same section, you've @@ -891,12 +975,17 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) if (tsec == ia64_info->plt_sec) size = sizeof (plt_full_entry); else - { - size = sizeof (oor_brl); - } + size = oor_branch_size; /* Resize the current section to make room for the new branch. */ trampoff = (sec->_cooked_size + 15) & (bfd_vma) -16; + + /* If trampoline is out of range, there is nothing we + can do. */ + offset = trampoff - (roff & (bfd_vma) -4); + if (offset < -0x1000000 || offset > 0x0FFFFF0) + continue; + amt = trampoff + size; contents = (bfd_byte *) bfd_realloc (contents, amt); if (contents == NULL) @@ -914,10 +1003,22 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) } else { - memcpy (contents + trampoff, oor_brl, size); - irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), - R_IA64_PCREL60B); - irel->r_offset = trampoff + 2; + if (size == sizeof (oor_ip)) + { + memcpy (contents + trampoff, oor_ip, size); + irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), + R_IA64_PCREL64I); + irel->r_addend -= 16; + irel->r_offset = trampoff + 2; + } + else + { + memcpy (contents + trampoff, oor_brl, size); + irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), + R_IA64_PCREL60B); + irel->r_offset = trampoff + 2; + } + } /* Record the fixup so we don't do it again this section. */ @@ -931,14 +1032,18 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) } else { + /* If trampoline is out of range, there is nothing we + can do. */ + offset = f->trampoff - (roff & (bfd_vma) -4); + if (offset < -0x1000000 || offset > 0x0FFFFF0) + continue; + /* Nop out the reloc, since we're finalizing things here. */ irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE); } - /* Fix up the existing branch to hit the trampoline. Hope like - hell this doesn't overflow too. */ - if (elfNN_ia64_install_value (abfd, contents + roff, - f->trampoff - (roff & (bfd_vma) -4), + /* Fix up the existing branch to hit the trampoline. */ + if (elfNN_ia64_install_value (abfd, contents + roff, offset, r_type) != bfd_reloc_ok) goto error_return; @@ -1047,7 +1152,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) /* ??? Resize .rela.got too. */ } - if (link_info->relax_finalizing) + if (!link_info->need_relax_finalize) sec->need_finalize_relax = 0; *again = changed_contents || changed_relocs; @@ -1379,8 +1484,9 @@ elfNN_ia64_additional_program_headers (abfd) } static bfd_boolean -elfNN_ia64_modify_segment_map (abfd) +elfNN_ia64_modify_segment_map (abfd, info) bfd *abfd; + struct bfd_link_info *info ATTRIBUTE_UNUSED; { struct elf_segment_map *m, **pm; Elf_Internal_Shdr *hdr; @@ -1508,78 +1614,18 @@ elfNN_ia64_is_local_label_name (abfd, name) /* Should we do dynamic things to this symbol? */ static bfd_boolean -elfNN_ia64_dynamic_symbol_p (h, info) +elfNN_ia64_dynamic_symbol_p (h, info, r_type) struct elf_link_hash_entry *h; struct bfd_link_info *info; + int r_type; { - if (h == NULL) - return FALSE; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - if (h->dynindx == -1) - return FALSE; - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - return FALSE; - default: - break; - } + bfd_boolean ignore_protected + = ((r_type & 0xf8) == 0x40 /* FPTR relocs */ + || (r_type & 0xf8) == 0x50); /* LTOFF_FPTR relocs */ - if (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_defweak) - return TRUE; - - /* If it isn't defined locally, then clearly it's dynamic. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) - return TRUE; - - /* Identify the cases where name binding rules say it resolves local. */ - return !(info->executable || info->symbolic); + return _bfd_elf_dynamic_symbol_p (h, info, ignore_protected); } -static bfd_boolean -elfNN_ia64_local_hash_table_init (ht, abfd, new) - struct elfNN_ia64_local_hash_table *ht; - bfd *abfd ATTRIBUTE_UNUSED; - new_hash_entry_func new; -{ - memset (ht, 0, sizeof (*ht)); - return bfd_hash_table_init (&ht->root, new); -} - -static struct bfd_hash_entry* -elfNN_ia64_new_loc_hash_entry (entry, table, string) - struct bfd_hash_entry *entry; - struct bfd_hash_table *table; - const char *string; -{ - struct elfNN_ia64_local_hash_entry *ret; - ret = (struct elfNN_ia64_local_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (!ret) - ret = bfd_hash_allocate (table, sizeof (*ret)); - - if (!ret) - return 0; - - /* Initialize our local data. All zeros, and definitely easier - than setting a handful of bit fields. */ - memset (ret, 0, sizeof (*ret)); - - /* Call the allocation method of the superclass. */ - ret = ((struct elfNN_ia64_local_hash_entry *) - bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); - - return (struct bfd_hash_entry *) ret; -} - static struct bfd_hash_entry* elfNN_ia64_new_elf_hash_entry (entry, table, string) struct bfd_hash_entry *entry; @@ -1611,7 +1657,7 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string) static void elfNN_ia64_hash_copy_indirect (bed, xdir, xind) - struct elf_backend_data *bed ATTRIBUTE_UNUSED; + const struct elf_backend_data *bed ATTRIBUTE_UNUSED; struct elf_link_hash_entry *xdir, *xind; { struct elfNN_ia64_link_hash_entry *dir, *ind; @@ -1626,7 +1672,8 @@ elfNN_ia64_hash_copy_indirect (bed, xdir, xind) (ind->root.elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK)); + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_HASH_NEEDS_PLT)); if (ind->root.root.type != bfd_link_hash_indirect) return; @@ -1679,6 +1726,33 @@ elfNN_ia64_hash_hide_symbol (info, xh, force_local) } } +/* Compute a hash of a local hash entry. */ + +static hashval_t +elfNN_ia64_local_htab_hash (ptr) + const void *ptr; +{ + struct elfNN_ia64_local_hash_entry *entry + = (struct elfNN_ia64_local_hash_entry *) ptr; + + return (((entry->id & 0xff) << 24) | ((entry->id & 0xff00) << 8)) + ^ entry->r_sym ^ (entry->id >> 16); +} + +/* Compare local hash entries. */ + +static int +elfNN_ia64_local_htab_eq (ptr1, ptr2) + const void *ptr1, *ptr2; +{ + struct elfNN_ia64_local_hash_entry *entry1 + = (struct elfNN_ia64_local_hash_entry *) ptr1; + struct elfNN_ia64_local_hash_entry *entry2 + = (struct elfNN_ia64_local_hash_entry *) ptr2; + + return entry1->id == entry2->id && entry1->r_sym == entry2->r_sym; +} + /* Create the derived linker hash table. The IA-64 ELF port uses this derived hash table to keep information specific to the IA-64 ElF linker (without using static variables). */ @@ -1700,8 +1774,10 @@ elfNN_ia64_hash_table_create (abfd) return 0; } - if (!elfNN_ia64_local_hash_table_init (&ret->loc_hash_table, abfd, - elfNN_ia64_new_loc_hash_entry)) + ret->loc_hash_table = htab_try_create (1024, elfNN_ia64_local_htab_hash, + elfNN_ia64_local_htab_eq, NULL); + ret->loc_hash_memory = objalloc_create (); + if (!ret->loc_hash_table || !ret->loc_hash_memory) { free (ret); return 0; @@ -1710,16 +1786,19 @@ elfNN_ia64_hash_table_create (abfd) return &ret->root.root; } -/* Look up an entry in a Alpha ELF linker hash table. */ +/* Destroy IA-64 linker hash table. */ -static INLINE struct elfNN_ia64_local_hash_entry * -elfNN_ia64_local_hash_lookup(table, string, create, copy) - struct elfNN_ia64_local_hash_table *table; - const char *string; - bfd_boolean create, copy; +static void +elfNN_ia64_hash_table_free (hash) + struct bfd_link_hash_table *hash; { - return ((struct elfNN_ia64_local_hash_entry *) - bfd_hash_lookup (&table->root, string, create, copy)); + struct elfNN_ia64_link_hash_table *ia64_info + = (struct elfNN_ia64_link_hash_table *) hash; + if (ia64_info->loc_hash_table) + htab_delete (ia64_info->loc_hash_table); + if (ia64_info->loc_hash_memory) + objalloc_free ((struct objalloc *) ia64_info->loc_hash_memory); + _bfd_generic_link_hash_table_free (hash); } /* Traverse both local and global hash tables. */ @@ -1751,20 +1830,20 @@ elfNN_ia64_global_dyn_sym_thunk (xentry, xdata) } static bfd_boolean -elfNN_ia64_local_dyn_sym_thunk (xentry, xdata) - struct bfd_hash_entry *xentry; +elfNN_ia64_local_dyn_sym_thunk (slot, xdata) + void **slot; PTR xdata; { struct elfNN_ia64_local_hash_entry *entry - = (struct elfNN_ia64_local_hash_entry *) xentry; + = (struct elfNN_ia64_local_hash_entry *) *slot; struct elfNN_ia64_dyn_sym_traverse_data *data = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata; struct elfNN_ia64_dyn_sym_info *dyn_i; for (dyn_i = entry->info; dyn_i; dyn_i = dyn_i->next) if (! (*data->func) (dyn_i, data->data)) - return FALSE; - return TRUE; + return 0; + return 1; } static void @@ -1780,8 +1859,8 @@ elfNN_ia64_dyn_sym_traverse (ia64_info, func, data) elf_link_hash_traverse (&ia64_info->root, elfNN_ia64_global_dyn_sym_thunk, &xdata); - bfd_hash_traverse (&ia64_info->loc_hash_table.root, - elfNN_ia64_local_dyn_sym_thunk, &xdata); + htab_traverse (ia64_info->loc_hash_table, + elfNN_ia64_local_dyn_sym_thunk, &xdata); } static bfd_boolean @@ -1803,6 +1882,8 @@ elfNN_ia64_create_dynamic_sections (abfd, info) { flagword flags = bfd_get_section_flags (abfd, ia64_info->got_sec); bfd_set_section_flags (abfd, ia64_info->got_sec, SEC_SMALL_DATA | flags); + /* The .got section is always aligned at 8 bytes. */ + bfd_set_section_alignment (abfd, ia64_info->got_sec, 3); } if (!get_pltoff (abfd, info, ia64_info)) @@ -1841,22 +1922,33 @@ get_local_sym_hash (ia64_info, abfd, rel, create) const Elf_Internal_Rela *rel; bfd_boolean create; { - struct elfNN_ia64_local_hash_entry *ret; + struct elfNN_ia64_local_hash_entry e, *ret; asection *sec = abfd->sections; - char addr_name [34]; + hashval_t h = (((sec->id & 0xff) << 24) | ((sec->id & 0xff00) << 8)) + ^ ELFNN_R_SYM (rel->r_info) ^ (sec->id >> 16); + void **slot; - BFD_ASSERT ((sizeof (sec->id)*2 + 1 + sizeof (unsigned long)*2 + 1) <= 34); - BFD_ASSERT (sec); + e.id = sec->id; + e.r_sym = ELFNN_R_SYM (rel->r_info); + slot = htab_find_slot_with_hash (ia64_info->loc_hash_table, &e, h, + create ? INSERT : NO_INSERT); - /* Construct a string for use in the elfNN_ia64_local_hash_table. - name describes what was once anonymous memory. */ + if (!slot) + return NULL; - sprintf (addr_name, "%x:%lx", - sec->id, (unsigned long) ELFNN_R_SYM (rel->r_info)); + if (*slot) + return (struct elfNN_ia64_local_hash_entry *) *slot; - /* Collect the canonical entry data for this address. */ - ret = elfNN_ia64_local_hash_lookup (&ia64_info->loc_hash_table, - addr_name, create, create); + ret = (struct elfNN_ia64_local_hash_entry *) + objalloc_alloc ((struct objalloc *) ia64_info->loc_hash_memory, + sizeof (struct elfNN_ia64_local_hash_entry)); + if (ret) + { + memset (ret, 0, sizeof (*ret)); + ret->id = sec->id; + ret->r_sym = ELFNN_R_SYM (rel->r_info); + *slot = ret; + } return ret; } @@ -1929,6 +2021,10 @@ get_got (abfd, info, ia64_info) BFD_ASSERT (got); ia64_info->got_sec = got; + /* The .got section is always aligned at 8 bytes. */ + if (!bfd_set_section_alignment (abfd, got, 3)) + return 0; + flags = bfd_get_section_flags (abfd, got); bfd_set_section_flags (abfd, got, SEC_SMALL_DATA | flags); } @@ -1937,7 +2033,7 @@ get_got (abfd, info, ia64_info) } /* Create function descriptor section (.opd). This section is called .opd - because it contains "official prodecure descriptors". The "official" + because it contains "official procedure descriptors". The "official" refers to the fact that these descriptors are used when taking the address of a procedure, thus ensuring a unique address for each procedure. */ @@ -1977,9 +2073,9 @@ get_fptr (abfd, info, ia64_info) if (info->pie) { asection *fptr_rel; - fptr_rel = bfd_make_section(abfd, ".rela.opd"); + fptr_rel = bfd_make_section(dynobj, ".rela.opd"); if (fptr_rel == NULL - || !bfd_set_section_flags (abfd, fptr_rel, + || !bfd_set_section_flags (dynobj, fptr_rel, (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY @@ -2079,18 +2175,12 @@ get_reloc_section (abfd, ia64_info, sec, create) return NULL; } - if (sec->flags & SEC_READONLY) - ia64_info->reltext = 1; - return srel; } static bfd_boolean -count_dyn_reloc (abfd, dyn_i, srel, type) - bfd *abfd; - struct elfNN_ia64_dyn_sym_info *dyn_i; - asection *srel; - int type; +count_dyn_reloc (bfd *abfd, struct elfNN_ia64_dyn_sym_info *dyn_i, + asection *srel, int type, bfd_boolean reltext) { struct elfNN_ia64_dyn_reloc_entry *rent; @@ -2111,6 +2201,7 @@ count_dyn_reloc (abfd, dyn_i, srel, type) rent->count = 0; dyn_i->reloc_entries = rent; } + rent->reltext = reltext; rent->count++; return TRUE; @@ -2180,7 +2271,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) this may help reduce memory usage and processing time later. */ maybe_dynamic = FALSE; if (h && ((!info->executable - && (!info->symbolic || info->allow_shlib_undefined)) + && (!info->symbolic || info->unresolved_syms_in_shared_libs == RM_IGNORE)) || ! (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) || h->root.type == bfd_link_hash_defweak)) maybe_dynamic = TRUE; @@ -2395,7 +2486,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) if (!srel) return FALSE; } - if (!count_dyn_reloc (abfd, dyn_i, srel, dynrel_type)) + if (!count_dyn_reloc (abfd, dyn_i, srel, dynrel_type, + (sec->flags & SEC_READONLY) != 0)) return FALSE; } } @@ -2415,7 +2507,7 @@ allocate_global_data_got (dyn_i, data) if ((dyn_i->want_got || dyn_i->want_gotx) && ! dyn_i->want_fptr - && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)) + && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) { dyn_i->got_offset = x->ofs; x->ofs += 8; @@ -2427,7 +2519,7 @@ allocate_global_data_got (dyn_i, data) } if (dyn_i->want_dtpmod) { - if (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)) + if (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) { dyn_i->dtpmod_offset = x->ofs; x->ofs += 8; @@ -2464,7 +2556,7 @@ allocate_global_fptr_got (dyn_i, data) if (dyn_i->want_got && dyn_i->want_fptr - && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)) + && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, R_IA64_FPTR64LSB)) { dyn_i->got_offset = x->ofs; x->ofs += 8; @@ -2482,7 +2574,7 @@ allocate_local_got (dyn_i, data) struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; if ((dyn_i->want_got || dyn_i->want_gotx) - && !elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info)) + && !elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) { dyn_i->got_offset = x->ofs; x->ofs += 8; @@ -2576,7 +2668,7 @@ allocate_plt_entries (dyn_i, data) h = (struct elf_link_hash_entry *) h->root.u.i.link; /* ??? Versioned symbols seem to lose ELF_LINK_HASH_NEEDS_PLT. */ - if (elfNN_ia64_dynamic_symbol_p (h, x->info)) + if (elfNN_ia64_dynamic_symbol_p (h, x->info, 0)) { bfd_size_type offset = x->ofs; if (offset == 0) @@ -2654,7 +2746,10 @@ allocate_dynrel_entries (dyn_i, data) bfd_boolean dynamic_symbol, shared, resolved_zero; ia64_info = elfNN_ia64_hash_table (x->info); - dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info); + + /* Note that this can't be used in relation to FPTR relocs below. */ + dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0); + shared = x->info->shared; resolved_zero = (dyn_i->h && ELF_ST_VISIBILITY (dyn_i->h->other) @@ -2699,6 +2794,8 @@ allocate_dynrel_entries (dyn_i, data) default: abort (); } + if (rent->reltext) + ia64_info->reltext = 1; rent->srel->_raw_size += sizeof (ElfNN_External_Rela) * count; } @@ -2779,7 +2876,7 @@ elfNN_ia64_adjust_dynamic_symbol (info, h) static bfd_boolean elfNN_ia64_size_dynamic_sections (output_bfd, info) - bfd *output_bfd; + bfd *output_bfd ATTRIBUTE_UNUSED; struct bfd_link_info *info; { struct elfNN_ia64_allocate_data data; @@ -2909,6 +3006,15 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) if (strip) ia64_info->fptr_sec = NULL; } + else if (sec == ia64_info->rel_fptr_sec) + { + if (strip) + ia64_info->rel_fptr_sec = NULL; + else + /* We use the reloc_count field as a counter if we need to + copy relocs into the output file. */ + sec->reloc_count = 0; + } else if (sec == ia64_info->plt_sec) { if (strip) @@ -3342,7 +3448,7 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) || ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT || dyn_i->h->root.type != bfd_link_hash_undefweak) && dyn_r_type != R_IA64_DTPREL64LSB) - || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info) + || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info, dyn_r_type) || (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB)) && (!dyn_i->want_ltoff_fptr || !info->pie @@ -3526,12 +3632,10 @@ static bfd_vma elfNN_ia64_tprel_base (info) struct bfd_link_info *info; { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + asection *tls_sec = elf_hash_table (info)->tls_sec; - BFD_ASSERT (tls_segment != NULL); - return (tls_segment->start - - align_power ((bfd_vma) 16, tls_segment->align)); + BFD_ASSERT (tls_sec != NULL); + return tls_sec->vma - align_power ((bfd_vma) 16, tls_sec->alignment_power); } /* Return the base VMA address which should be subtracted from real addresses @@ -3542,8 +3646,8 @@ static bfd_vma elfNN_ia64_dtprel_base (info) struct bfd_link_info *info; { - BFD_ASSERT (elf_hash_table (info)->tls_segment != NULL); - return elf_hash_table (info)->tls_segment->start; + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); + return elf_hash_table (info)->tls_sec->vma; } /* Called through qsort to sort the .IA_64.unwind section during a @@ -3807,7 +3911,6 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, asection *sym_sec; bfd_byte *hit_addr; bfd_boolean dynamic_symbol_p; - bfd_boolean local_symbol_p; bfd_boolean undef_weak_ref; r_type = ELFNN_R_TYPE (rel->r_info); @@ -3831,9 +3934,11 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, if (r_symndx < symtab_hdr->sh_info) { /* Reloc against local symbol. */ + asection *msec; sym = local_syms + r_symndx; sym_sec = local_sections[r_symndx]; - value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel); + msec = sym_sec; + value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel); if ((sym_sec->flags & SEC_MERGE) && ELF_ST_TYPE (sym->st_info) == STT_SECTION && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE) @@ -3844,7 +3949,6 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, if (loc_h && ! loc_h->sec_merge_done) { struct elfNN_ia64_dyn_sym_info *dynent; - asection *msec; for (dynent = loc_h->info; dynent; dynent = dynent->next) { @@ -3868,62 +3972,24 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, } else { - long indx; + bfd_boolean unresolved_reloc; + bfd_boolean warned; - /* Reloc against global symbol. */ - indx = r_symndx - symtab_hdr->sh_info; - h = elf_sym_hashes (input_bfd)[indx]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - - value = 0; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - sym_sec = h->root.u.def.section; + RELOC_FOR_GLOBAL_SYMBOL (h, elf_sym_hashes (input_bfd), + r_symndx, + symtab_hdr, value, sym_sec, + unresolved_reloc, info, + warned); - /* Detect the cases that sym_sec->output_section is - expected to be NULL -- all cases in which the symbol - is defined in another shared module. This includes - PLT relocs for which we've created a PLT entry and - other relocs for which we're prepared to create - dynamic relocations. */ - /* ??? Just accept it NULL and continue. */ - - if (sym_sec->output_section != NULL) - { - value = (h->root.u.def.value - + sym_sec->output_section->vma - + sym_sec->output_offset); - } - } - else if (h->root.type == bfd_link_hash_undefweak) + if (h->root.type == bfd_link_hash_undefweak) undef_weak_ref = TRUE; - else if (! info->executable - && !info->no_undefined - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - ; - else - { - if (! ((*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, - input_section, rel->r_offset, - (!info->shared || info->no_undefined - || ELF_ST_VISIBILITY (h->other))))) - return FALSE; - continue; - } + else if (warned) + continue; } hit_addr = contents + rel->r_offset; value += rel->r_addend; - dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info); - /* Is this symbol locally defined? A protected symbol is locallly - defined. But its function descriptor may not. Use it with - caution. */ - local_symbol_p = (! dynamic_symbol_p - || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT); + dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info, r_type); switch (r_type) { @@ -3949,10 +4015,28 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, BFD_ASSERT (srel != NULL); + switch (r_type) + { + case R_IA64_IMM14: + case R_IA64_IMM22: + case R_IA64_IMM64: + /* ??? People shouldn't be doing non-pic code in + shared libraries nor dynamic executables. */ + (*_bfd_error_handler) + (_("%s: non-pic code with imm relocation against dynamic symbol `%s'"), + bfd_archive_filename (input_bfd), + h->root.root.string); + ret_val = FALSE; + continue; + + default: + break; + } + /* If we don't need dynamic symbol lookup, find a matching RELATIVE relocation. */ dyn_r_type = r_type; - if (! local_symbol_p) + if (dynamic_symbol_p) { dynindx = h->dynindx; addend = rel->r_addend; @@ -3976,17 +4060,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, break; default: - /* We can't represent this without a dynamic symbol. - Adjust the relocation to be against an output - section symbol, which are always present in the - dynamic symbol table. */ - /* ??? People shouldn't be doing non-pic code in - shared libraries. Hork. */ - (*_bfd_error_handler) - (_("%s: linking non-pic code in a shared library"), - bfd_archive_filename (input_bfd)); - ret_val = FALSE; - continue; + break; } dynindx = 0; addend = value; @@ -4300,7 +4374,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, /* If we don't need dynamic symbol lookup, install two RELATIVE relocations. */ - if (local_symbol_p) + if (!dynamic_symbol_p) { unsigned int dyn_r_type; @@ -4548,7 +4622,7 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym) loc = ia64_info->rel_pltoff_sec->contents; loc += ((ia64_info->rel_pltoff_sec->reloc_count + index) - * sizeof (Elf64_External_Rela)); + * sizeof (ElfNN_External_Rela)); bfd_elfNN_swap_reloca_out (output_bfd, &outrel, loc); } @@ -4798,6 +4872,13 @@ elfNN_ia64_reloc_type_class (rela) } } +static struct bfd_elf_special_section const elfNN_ia64_special_sections[]= +{ + { ".sbss", 5, -1, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, + { ".sdata", 6, -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, + { NULL, 0, 0, 0, 0 } +}; + static bfd_boolean elfNN_ia64_hpux_vec (const bfd_target *vec) { @@ -4829,6 +4910,23 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) } return FALSE; } + +static void +elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, + asymbol *asym) +{ + elf_symbol_type *elfsym = (elf_symbol_type *) asym;; + + switch (elfsym->internal_elf_sym.st_shndx) + { + case SHN_IA_64_ANSI_COMMON: + asym->section = bfd_com_section_ptr; + asym->value = elfsym->internal_elf_sym.st_size; + asym->flags &= ~BSF_GLOBAL; + break; + } +} + #define TARGET_LITTLE_SYM bfd_elfNN_ia64_little_vec #define TARGET_LITTLE_NAME "elfNN-ia64-little" @@ -4867,6 +4965,8 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) /* Stuff for the BFD linker: */ #define bfd_elfNN_bfd_link_hash_table_create \ elfNN_ia64_hash_table_create +#define bfd_elfNN_bfd_link_hash_table_free \ + elfNN_ia64_hash_table_free #define elf_backend_create_dynamic_sections \ elfNN_ia64_create_dynamic_sections #define elf_backend_check_relocs \ @@ -4895,7 +4995,6 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) #define elf_backend_want_plt_sym 0 #define elf_backend_plt_alignment 5 #define elf_backend_got_header_size 0 -#define elf_backend_plt_header_size PLT_HEADER_SIZE #define elf_backend_want_got_plt 1 #define elf_backend_may_use_rel_p 1 #define elf_backend_may_use_rela_p 1 @@ -4905,6 +5004,7 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) #define elf_backend_hide_symbol elfNN_ia64_hash_hide_symbol #define elf_backend_reloc_type_class elfNN_ia64_reloc_type_class #define elf_backend_rela_normal 1 +#define elf_backend_special_sections elfNN_ia64_special_sections #include "elfNN-target.h" @@ -4925,6 +5025,9 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) #undef elf_backend_section_from_bfd_section #define elf_backend_section_from_bfd_section elfNN_hpux_backend_section_from_bfd_section +#undef elf_backend_symbol_processing +#define elf_backend_symbol_processing elfNN_hpux_backend_symbol_processing + #undef elf_backend_want_p_paddr_set_to_zero #define elf_backend_want_p_paddr_set_to_zero 1