X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-ia64.c;h=878511bb828c3f14baadb4e89ea52faa09014a39;hb=de9811afe23bbdd0cb72c7c05d7136aebf9e75c9;hp=5e8dadf889ec729b91145155659e44127a446d0b;hpb=9f1c3a0af772804f5e93ac3f2a72c30e286552bf;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index 5e8dadf889..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; @@ -143,6 +143,7 @@ struct elfNN_ia64_link_hash_table asection *got_sec; /* the linkage table section (or NULL) */ asection *rel_got_sec; /* dynamic relocation section for same */ asection *fptr_sec; /* function descriptor table (or NULL) */ + asection *rel_fptr_sec; /* dynamic relocation section for same */ asection *plt_sec; /* the primary plt section (or NULL) */ asection *pltoff_sec; /* private descriptors for plt (or NULL) */ asection *rel_pltoff_sec; /* dynamic relocation section for same */ @@ -152,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 @@ -192,45 +194,33 @@ static bfd_boolean elfNN_ia64_add_symbol_hook PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym, const char **namep, flagword *flagsp, asection **secp, bfd_vma *valp)); -static bfd_boolean elfNN_ia64_aix_vec - PARAMS ((const bfd_target *vec)); -static bfd_boolean elfNN_ia64_aix_add_symbol_hook - PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym, - const char **namep, flagword *flagsp, asection **secp, - bfd_vma *valp)); -static bfd_boolean elfNN_ia64_aix_link_add_symbols - PARAMS ((bfd *abfd, struct bfd_link_info *info)); 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), @@ -256,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)); @@ -367,7 +354,7 @@ elfNN_ia64_reloc (abfd, reloc, sym, data, input_section, #define IA64_HOWTO(TYPE, NAME, SIZE, PCREL, IN) \ HOWTO (TYPE, 0, SIZE, 0, PCREL, 0, complain_overflow_signed, \ - elfNN_ia64_reloc, NAME, FALSE, 0, 0, IN) + elfNN_ia64_reloc, NAME, FALSE, 0, -1, IN) /* This table has to be sorted according to increasing number of the TYPE field. */ @@ -453,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,9 +643,6 @@ static const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] = }; #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" -#define AIX_DYNAMIC_INTERPRETER "/usr/lib/ia64l64/libc.so.1" -#define DYNAMIC_INTERPRETER(abfd) \ - (elfNN_ia64_aix_vec (abfd->xvec) ? AIX_DYNAMIC_INTERPRETER : ELF_DYNAMIC_INTERPRETER) static const bfd_byte oor_brl[16] = { @@ -666,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. */ @@ -701,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; @@ -759,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; @@ -798,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) @@ -841,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; @@ -870,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; @@ -877,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 @@ -901,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) @@ -924,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. */ @@ -941,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; @@ -1057,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; @@ -1341,7 +1436,7 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) bfd_vma *valp; { if (sym->st_shndx == SHN_COMMON - && !info->relocateable + && !info->relocatable && sym->st_size <= elf_gp_size (abfd)) { /* Common symbols less than or equal to -G nn bytes are @@ -1366,114 +1461,6 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) return TRUE; } -static bfd_boolean -elfNN_ia64_aix_vec (const bfd_target *vec) -{ - extern const bfd_target bfd_elfNN_ia64_aix_little_vec; - extern const bfd_target bfd_elfNN_ia64_aix_big_vec; - - return (/**/vec == & bfd_elfNN_ia64_aix_little_vec - || vec == & bfd_elfNN_ia64_aix_big_vec); -} - -/* Hook called by the linker routine which adds symbols from an object - file. We use it to handle OS-specific symbols. */ - -static bfd_boolean -elfNN_ia64_aix_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) - bfd *abfd; - struct bfd_link_info *info; - const Elf_Internal_Sym *sym; - const char **namep; - flagword *flagsp; - asection **secp; - bfd_vma *valp; -{ - if (strcmp (*namep, "__GLOB_DATA_PTR") == 0) - { - /* Define __GLOB_DATA_PTR when it is encountered. This is expected to - be a linker-defined symbol by the Aix C runtime startup code. IBM sez - no one else should use it b/c it is undocumented. */ - struct elf_link_hash_entry *h; - - h = elf_link_hash_lookup (elf_hash_table (info), *namep, - FALSE, FALSE, FALSE); - if (h == NULL) - { - struct elf_backend_data *bed; - struct elfNN_ia64_link_hash_table *ia64_info; - struct bfd_link_hash_entry *bh = NULL; - - bed = get_elf_backend_data (abfd); - ia64_info = elfNN_ia64_hash_table (info); - - if (!(_bfd_generic_link_add_one_symbol - (info, abfd, *namep, BSF_GLOBAL, - bfd_get_section_by_name (abfd, ".bss"), - bed->got_symbol_offset, (const char *) NULL, FALSE, - bed->collect, &bh))) - return FALSE; - - h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; - h->type = STT_OBJECT; - - if (! _bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - - return TRUE; - } - else if (sym->st_shndx == SHN_LOOS) - { - unsigned int i; - - /* SHN_AIX_SYSCALL: Treat this as any other symbol. The special symbol - is only relevant when compiling code for extended system calls. - Replace the "special" section with .text, if possible. - Note that these symbols are always assumed to be in .text. */ - for (i = 1; i < elf_numsections (abfd); i++) - { - asection * sec = bfd_section_from_elf_index (abfd, i); - - if (sec && strcmp (sec->name, ".text") == 0) - { - *secp = sec; - break; - } - } - - if (*secp == NULL) - *secp = bfd_abs_section_ptr; - - *valp = sym->st_size; - - return TRUE; - } - else - { - return elfNN_ia64_add_symbol_hook (abfd, info, sym, - namep, flagsp, secp, valp); - } -} - -bfd_boolean -elfNN_ia64_aix_link_add_symbols (abfd, info) - bfd *abfd; - struct bfd_link_info *info; -{ - /* Make sure dynamic sections are always created. */ - if (! elf_hash_table (info)->dynamic_sections_created - && abfd->xvec == info->hash->creator) - { - if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) - return FALSE; - } - - /* Now do the standard call. */ - return bfd_elfNN_bfd_link_add_symbols (abfd, info); -} - /* Return the number of additional phdrs we will need. */ static int @@ -1497,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; @@ -1626,79 +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; + bfd_boolean ignore_protected + = ((r_type & 0xf8) == 0x40 /* FPTR relocs */ + || (r_type & 0xf8) == 0x50); /* LTOFF_FPTR relocs */ - if (h->dynindx == -1) - return FALSE; - switch (ELF_ST_VISIBILITY (h->other)) - { - case STV_INTERNAL: - case STV_HIDDEN: - return FALSE; - default: - break; - } - - if (h->root.type == bfd_link_hash_undefweak - || h->root.type == bfd_link_hash_defweak) - return TRUE; - - 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))) - return TRUE; - - return FALSE; + 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; @@ -1730,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; @@ -1745,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; @@ -1798,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). */ @@ -1819,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; @@ -1829,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. */ @@ -1870,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 @@ -1899,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 @@ -1922,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)) @@ -1960,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; } @@ -2048,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); } @@ -2056,14 +2033,14 @@ 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. */ static asection * get_fptr (abfd, info, ia64_info) bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; + struct bfd_link_info *info; struct elfNN_ia64_link_hash_table *ia64_info; { asection *fptr; @@ -2083,7 +2060,7 @@ get_fptr (abfd, info, ia64_info) | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_READONLY + | (info->pie ? 0 : SEC_READONLY) | SEC_LINKER_CREATED)) || !bfd_set_section_alignment (abfd, fptr, 4)) { @@ -2092,6 +2069,26 @@ get_fptr (abfd, info, ia64_info) } ia64_info->fptr_sec = fptr; + + if (info->pie) + { + asection *fptr_rel; + fptr_rel = bfd_make_section(dynobj, ".rela.opd"); + if (fptr_rel == NULL + || !bfd_set_section_flags (dynobj, fptr_rel, + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)) + || !bfd_set_section_alignment (abfd, fptr_rel, 3)) + { + BFD_ASSERT (0); + return NULL; + } + + ia64_info->rel_fptr_sec = fptr_rel; + } } return fptr; @@ -2178,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; @@ -2210,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; @@ -2228,7 +2220,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) const Elf_Internal_Rela *rel; asection *got, *fptr, *srel; - if (info->relocateable) + if (info->relocatable) return TRUE; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -2278,11 +2270,10 @@ elfNN_ia64_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 || info->allow_shlib_undefined)) + if (h && ((!info->executable + && (!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 - || elfNN_ia64_aix_vec (abfd->xvec))) + || h->root.type == bfd_link_hash_defweak)) maybe_dynamic = TRUE; need_entry = 0; @@ -2339,7 +2330,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) case R_IA64_FPTR32LSB: case R_IA64_FPTR64MSB: case R_IA64_FPTR64LSB: - if (info->shared || h || elfNN_ia64_aix_vec (abfd->xvec)) + if (info->shared || h) need_entry = NEED_FPTR | NEED_DYNREL; else need_entry = NEED_FPTR; @@ -2391,10 +2382,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) case R_IA64_DIR64MSB: case R_IA64_DIR64LSB: /* Shared objects will always need at least a REL relocation. */ - if (info->shared || maybe_dynamic - || (elfNN_ia64_aix_vec (abfd->xvec) - && (!h || strcmp (h->root.root.string, - "__GLOB_DATA_PTR") != 0))) + if (info->shared || maybe_dynamic) need_entry = NEED_DYNREL; dynrel_type = R_IA64_DIR64LSB; break; @@ -2468,9 +2456,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) /* FPTRs for shared libraries are allocated by the dynamic linker. Make sure this local symbol will appear in the dynamic symbol table. */ - if (!h && (info->shared - /* AIX also needs one */ - || elfNN_ia64_aix_vec (abfd->xvec))) + if (!h && info->shared) { if (! (_bfd_elfNN_link_record_local_dynamic_symbol (info, abfd, (long) r_symndx))) @@ -2500,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; } } @@ -2520,10 +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_aix_vec (x->info->hash->creator) - && (!dyn_i->h || strcmp (dyn_i->h->root.root.string, - "__GLOB_DATA_PTR") != 0)))) + && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) { dyn_i->got_offset = x->ofs; x->ofs += 8; @@ -2535,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; @@ -2572,8 +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_aix_vec (x->info->hash->creator))) + && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, R_IA64_FPTR64LSB)) { dyn_i->got_offset = x->ofs; x->ofs += 8; @@ -2591,8 +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_aix_vec (x->info->hash->creator))) + && !elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) { dyn_i->got_offset = x->ofs; x->ofs += 8; @@ -2638,15 +2620,10 @@ allocate_fptr (dyn_i, data) || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - if ((x->info->shared - && (!h - || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) - /* AIX needs an FPTR in this case. */ - || (elfNN_ia64_aix_vec (x->info->hash->creator) - && (!h - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak))) + if (!x->info->executable + && (!h + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) { if (h && h->dynindx == -1) { @@ -2691,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) @@ -2769,11 +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) - || (elfNN_ia64_aix_vec (x->info->hash->creator) - /* Don't allocate an entry for __GLOB_DATA_PTR */ - && (!dyn_i->h || strcmp (dyn_i->h->root.root.string, - "__GLOB_DATA_PTR") != 0)); + + /* 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) @@ -2788,10 +2764,11 @@ allocate_dynrel_entries (dyn_i, data) switch (rent->type) { case R_IA64_FPTR64LSB: - /* Allocate one iff !want_fptr, which by this point will - be true only if we're actually allocating one statically - in the main executable. */ - if (dyn_i->want_fptr) + /* Allocate one iff !want_fptr and not PIE, which by this point + will be true only if we're actually allocating one statically + in the main executable. Position independent executables + need a relative reloc. */ + if (dyn_i->want_fptr && !x->info->pie) continue; break; case R_IA64_PCREL64LSB: @@ -2817,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; } @@ -2828,13 +2807,24 @@ allocate_dynrel_entries (dyn_i, data) || (dyn_i->want_ltoff_fptr && dyn_i->h && dyn_i->h->dynindx != -1)) - ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela); + { + if (!dyn_i->want_ltoff_fptr + || !x->info->pie + || dyn_i->h == NULL + || dyn_i->h->root.type != bfd_link_hash_undefweak) + ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela); + } if ((dynamic_symbol || shared) && dyn_i->want_tprel) ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela); if (dynamic_symbol && dyn_i->want_dtpmod) ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela); if (dynamic_symbol && dyn_i->want_dtprel) ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela); + if (ia64_info->rel_fptr_sec && dyn_i->want_fptr) + { + if (dyn_i->h == NULL || dyn_i->h->root.type != bfd_link_hash_undefweak) + ia64_info->rel_fptr_sec->_raw_size += sizeof (ElfNN_External_Rela); + } if (!resolved_zero && dyn_i->want_pltoff) { @@ -2886,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; @@ -2907,8 +2897,8 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) { sec = bfd_get_section_by_name (dynobj, ".interp"); BFD_ASSERT (sec != NULL); - sec->contents = (bfd_byte *) DYNAMIC_INTERPRETER (output_bfd); - sec->_raw_size = strlen (DYNAMIC_INTERPRETER (output_bfd)) + 1; + sec->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; + sec->_raw_size = strlen (ELF_DYNAMIC_INTERPRETER) + 1; } /* Allocate the GOT entries. */ @@ -3016,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) @@ -3444,14 +3443,17 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) bfd_put_64 (abfd, value, got_sec->contents + got_offset); /* Install a dynamic relocation if needed. */ - if ((info->shared - && (!dyn_i->h - || 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_aix_vec (abfd->xvec) - || (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB)) + if (((info->shared + && (!dyn_i->h + || 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, dyn_r_type) + || (dynindx != -1 && dyn_r_type == R_IA64_FPTR64LSB)) + && (!dyn_i->want_ltoff_fptr + || !info->pie + || !dyn_i->h + || dyn_i->h->root.type != bfd_link_hash_undefweak)) { if (dynindx == -1 && dyn_r_type != R_IA64_TPREL64LSB @@ -3530,6 +3532,24 @@ set_fptr_entry (abfd, info, dyn_i, value) bfd_put_64 (abfd, value, fptr_sec->contents + dyn_i->fptr_offset); bfd_put_64 (abfd, _bfd_get_gp_value (abfd), fptr_sec->contents + dyn_i->fptr_offset + 8); + if (ia64_info->rel_fptr_sec) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + + if (bfd_little_endian (abfd)) + outrel.r_info = ELFNN_R_INFO (0, R_IA64_IPLTLSB); + else + outrel.r_info = ELFNN_R_INFO (0, R_IA64_IPLTMSB); + outrel.r_addend = value; + outrel.r_offset = (fptr_sec->output_section->vma + + fptr_sec->output_offset + + dyn_i->fptr_offset); + loc = ia64_info->rel_fptr_sec->contents; + loc += ia64_info->rel_fptr_sec->reloc_count++ + * sizeof (ElfNN_External_Rela); + bfd_elfNN_swap_reloca_out (abfd, &outrel, loc); + } } /* Return the descriptor's address. */ @@ -3612,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 @@ -3628,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 @@ -3779,7 +3797,7 @@ elfNN_ia64_final_link (abfd, info) ia64_info = elfNN_ia64_hash_table (info); /* Make sure we've got ourselves a nice fat __gp value. */ - if (!info->relocateable) + if (!info->relocatable) { bfd_vma gp_val = _bfd_get_gp_value (abfd); struct elf_link_hash_entry *gp; @@ -3805,7 +3823,7 @@ elfNN_ia64_final_link (abfd, info) of the .IA_64.unwind section. Force this section to be relocated into memory rather than written immediately to the output file. */ unwind_output_sec = NULL; - if (!info->relocateable) + if (!info->relocatable) { asection *s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind); if (s) @@ -3863,7 +3881,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, ia64_info = elfNN_ia64_hash_table (info); /* Infect various flags from the input section to the output section. */ - if (info->relocateable) + if (info->relocatable) { bfd_vma flags; @@ -3893,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); @@ -3917,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) @@ -3930,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) { @@ -3954,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; + RELOC_FOR_GLOBAL_SYMBOL (h, elf_sym_hashes (input_bfd), + r_symndx, + symtab_hdr, value, sym_sec, + unresolved_reloc, info, + warned); - value = 0; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - sym_sec = h->root.u.def.section; - - /* 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->shared - && !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) { @@ -4025,11 +4005,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_DIR64MSB: case R_IA64_DIR64LSB: /* Install a dynamic relocation for this reloc. */ - if ((dynamic_symbol_p || info->shared - || (elfNN_ia64_aix_vec (info->hash->creator) - /* Don't emit relocs for __GLOB_DATA_PTR on AIX. */ - && (!h || strcmp (h->root.root.string, - "__GLOB_DATA_PTR") != 0))) + if ((dynamic_symbol_p || info->shared) && r_symndx != 0 && (input_section->flags & SEC_ALLOC) != 0) { @@ -4039,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; @@ -4066,24 +4060,12 @@ 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; } - if (elfNN_ia64_aix_vec (info->hash->creator)) - rel->r_addend = value; elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section, srel, rel->r_offset, dyn_r_type, dynindx, addend); @@ -4146,14 +4128,36 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, if (!undef_weak_ref) value = set_fptr_entry (output_bfd, info, dyn_i, value); } - else + if (!dyn_i->want_fptr || info->pie) { long dynindx; + unsigned int dyn_r_type = r_type; + bfd_vma addend = rel->r_addend; /* Otherwise, we expect the dynamic linker to create the entry. */ - if (h) + if (dyn_i->want_fptr) + { + if (r_type == R_IA64_FPTR64I) + { + /* 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 position independent executable"), + bfd_archive_filename (input_bfd)); + ret_val = FALSE; + continue; + } + dynindx = 0; + addend = value; + dyn_r_type = r_type + R_IA64_REL64LSB - R_IA64_FPTR64LSB; + } + else if (h) { if (h->dynindx != -1) dynindx = h->dynindx; @@ -4161,17 +4165,18 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, dynindx = (_bfd_elf_link_lookup_local_dynindx (info, h->root.u.def.section->owner, global_sym_index (h))); + value = 0; } else { dynindx = (_bfd_elf_link_lookup_local_dynindx (info, input_bfd, (long) r_symndx)); + value = 0; } elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section, - srel, rel->r_offset, r_type, - dynindx, rel->r_addend); - value = 0; + srel, rel->r_offset, dyn_r_type, + dynindx, addend); } r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); @@ -4225,9 +4230,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_PCREL64MSB: case R_IA64_PCREL64LSB: /* Install a dynamic relocation for this reloc. */ - if ((dynamic_symbol_p - || elfNN_ia64_aix_vec (info->hash->creator)) - && r_symndx != 0) + if (dynamic_symbol_p && r_symndx != 0) { BFD_ASSERT (srel != NULL); @@ -4371,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; @@ -4619,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); } @@ -4869,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) { @@ -4900,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" @@ -4938,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 \ @@ -4966,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 @@ -4976,27 +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 - -#include "elfNN-target.h" - -/* AIX-specific vectors. */ - -#undef TARGET_LITTLE_SYM -#define TARGET_LITTLE_SYM bfd_elfNN_ia64_aix_little_vec -#undef TARGET_LITTLE_NAME -#define TARGET_LITTLE_NAME "elfNN-ia64-aix-little" -#undef TARGET_BIG_SYM -#define TARGET_BIG_SYM bfd_elfNN_ia64_aix_big_vec -#undef TARGET_BIG_NAME -#define TARGET_BIG_NAME "elfNN-ia64-aix-big" - -#undef elf_backend_add_symbol_hook -#define elf_backend_add_symbol_hook elfNN_ia64_aix_add_symbol_hook - -#undef bfd_elfNN_bfd_link_add_symbols -#define bfd_elfNN_bfd_link_add_symbols elfNN_ia64_aix_link_add_symbols - -#define elfNN_bed elfNN_ia64_aix_bed +#define elf_backend_special_sections elfNN_ia64_special_sections #include "elfNN-target.h" @@ -5009,14 +5017,6 @@ elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) #undef TARGET_BIG_NAME #define TARGET_BIG_NAME "elfNN-ia64-hpux-big" -/* We need to undo the AIX specific functions. */ - -#undef elf_backend_add_symbol_hook -#define elf_backend_add_symbol_hook elfNN_ia64_add_symbol_hook - -#undef bfd_elfNN_bfd_link_add_symbols -#define bfd_elfNN_bfd_link_add_symbols _bfd_generic_link_add_symbols - /* These are HP-UX specific functions. */ #undef elf_backend_post_process_headers @@ -5025,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