X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felfxx-ia64.c;h=81e683c81fe879c4f0a7f12ee5bf5feda4c40058;hb=75eb734c5cf4c99438b48359bef717055af77e8c;hp=15f7c0a126ad1157ec5d37c77e383604735efe1e;hpb=1fc0d1736505693dd0ab10986920cc6c8a5c4110;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index 15f7c0a126..81e683c81f 100644 --- a/bfd/elfxx-ia64.c +++ b/bfd/elfxx-ia64.c @@ -1,5 +1,6 @@ /* IA-64 support for 64-bit ELF - Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. Contributed by David Mosberger-Tang This file is part of BFD, the Binary File Descriptor library. @@ -16,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "bfd.h" #include "sysdep.h" @@ -24,6 +25,18 @@ #include "elf-bfd.h" #include "opcode/ia64.h" #include "elf/ia64.h" +#include "objalloc.h" +#include "hashtab.h" + +#define ARCH_SIZE NN + +#if ARCH_SIZE == 64 +#define LOG_SECTION_ALIGN 3 +#endif + +#if ARCH_SIZE == 32 +#define LOG_SECTION_ALIGN 2 +#endif /* THE RULES for all the stuff the linker creates -- @@ -51,7 +64,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 +92,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 +103,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 +131,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 +140,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,13 +164,15 @@ 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 { struct bfd_link_info *info; bfd_size_type ofs; + bfd_boolean only_got; }; #define elfNN_ia64_hash_table(p) \ @@ -178,52 +191,46 @@ static bfd_boolean elfNN_ia64_relax_section PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again)); static void elfNN_ia64_relax_ldxmov - PARAMS((bfd *abfd, bfd_byte *contents, bfd_vma off)); + PARAMS((bfd_byte *contents, bfd_vma off)); static bfd_boolean is_unwind_section_name PARAMS ((bfd *abfd, const char *)); -static bfd_boolean elfNN_ia64_section_from_shdr - PARAMS ((bfd *, Elf_Internal_Shdr *, const char *)); static bfd_boolean elfNN_ia64_section_flags - PARAMS ((flagword *, Elf_Internal_Shdr *)); + PARAMS ((flagword *, const Elf_Internal_Shdr *)); static bfd_boolean elfNN_ia64_fake_sections PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)); static void elfNN_ia64_final_write_processing PARAMS ((bfd *abfd, bfd_boolean linker)); static bfd_boolean elfNN_ia64_add_symbol_hook - PARAMS ((bfd *abfd, struct bfd_link_info *info, const Elf_Internal_Sym *sym, + PARAMS ((bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *sym, const char **namep, flagword *flagsp, asection **secp, bfd_vma *valp)); 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, int)); -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)); 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 ((const struct elf_backend_data *, struct elf_link_hash_entry *, + PARAMS ((struct bfd_link_info *, 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 +256,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)); @@ -278,7 +282,7 @@ static bfd_boolean allocate_dynrel_entries static bfd_boolean elfNN_ia64_size_dynamic_sections PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); static bfd_reloc_status_type elfNN_ia64_install_value - PARAMS ((bfd *abfd, bfd_byte *hit_addr, bfd_vma val, unsigned int r_type)); + PARAMS ((bfd_byte *hit_addr, bfd_vma val, unsigned int r_type)); static void elfNN_ia64_install_dyn_reloc PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec, asection *srel, bfd_vma offset, unsigned int type, @@ -450,8 +454,8 @@ static reloc_howto_type ia64_howto_table[] = 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", 4, FALSE, FALSE), - IA64_HOWTO (R_IA64_DTPMOD64LSB, "TPREL64LSB", 4, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPMOD64MSB, "DTPMOD64MSB", 4, FALSE, FALSE), + IA64_HOWTO (R_IA64_DTPMOD64LSB, "DTPMOD64LSB", 4, FALSE, FALSE), IA64_HOWTO (R_IA64_LTOFF_DTPMOD22, "LTOFF_DTPMOD22", 0, FALSE, FALSE), IA64_HOWTO (R_IA64_DTPREL14, "DTPREL14", 0, FALSE, FALSE), @@ -484,7 +488,8 @@ lookup_howto (rtype) elf_code_to_howto_index[ia64_howto_table[i].type] = i; } - BFD_ASSERT (rtype <= R_IA64_MAX_RELOC_CODE); + if (rtype > R_IA64_MAX_RELOC_CODE) + return 0; i = elf_code_to_howto_index[rtype]; if (i >= NELEMS (ia64_howto_table)) return 0; @@ -641,7 +646,7 @@ static const bfd_byte plt_min_entry[PLT_MIN_ENTRY_SIZE] = static const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] = { 0x0b, 0x78, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r15=0,r1;; */ - 0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0, /* ld8 r16=[r15],8 */ + 0x00, 0x41, 0x3c, 0x70, 0x29, 0xc0, /* ld8.acq r16=[r15],8*/ 0x01, 0x08, 0x00, 0x84, /* mov r14=r1;; */ 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, /* [MIB] ld8 r1=[r15] */ 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */ @@ -656,6 +661,197 @@ 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); +} + +#define BTYPE_SHIFT 6 +#define Y_SHIFT 26 +#define X6_SHIFT 27 +#define X4_SHIFT 27 +#define X3_SHIFT 33 +#define X2_SHIFT 31 +#define X_SHIFT 33 +#define OPCODE_SHIFT 37 + +#define OPCODE_BITS (0xfLL << OPCODE_SHIFT) +#define X6_BITS (0x3fLL << X6_SHIFT) +#define X4_BITS (0xfLL << X4_SHIFT) +#define X3_BITS (0x7LL << X3_SHIFT) +#define X2_BITS (0x3LL << X2_SHIFT) +#define X_BITS (0x1LL << X_SHIFT) +#define Y_BITS (0x1LL << Y_SHIFT) +#define BTYPE_BITS (0x7LL << BTYPE_SHIFT) +#define PREDICATE_BITS (0x3fLL) + +#define IS_NOP_B(i) \ + (((i) & (OPCODE_BITS | X6_BITS)) == (2LL << OPCODE_SHIFT)) +#define IS_NOP_F(i) \ + (((i) & (OPCODE_BITS | X_BITS | X6_BITS | Y_BITS)) \ + == (0x1LL << X6_SHIFT)) +#define IS_NOP_I(i) \ + (((i) & (OPCODE_BITS | X3_BITS | X6_BITS | Y_BITS)) \ + == (0x1LL << X6_SHIFT)) +#define IS_NOP_M(i) \ + (((i) & (OPCODE_BITS | X3_BITS | X2_BITS | X4_BITS | Y_BITS)) \ + == (0x1LL << X4_SHIFT)) +#define IS_BR_COND(i) \ + (((i) & (OPCODE_BITS | BTYPE_BITS)) == (0x4LL << OPCODE_SHIFT)) +#define IS_BR_CALL(i) \ + (((i) & OPCODE_BITS) == (0x5LL << OPCODE_SHIFT)) + +static bfd_boolean +elfNN_ia64_relax_br (bfd_byte *contents, bfd_vma off) +{ + unsigned int template, mlx; + bfd_vma t0, t1, s0, s1, s2, br_code; + long br_slot; + bfd_byte *hit_addr; + + hit_addr = (bfd_byte *) (contents + off); + br_slot = (long) hit_addr & 0x3; + hit_addr -= br_slot; + t0 = bfd_getl64 (hit_addr + 0); + t1 = bfd_getl64 (hit_addr + 8); + + /* Check if we can turn br into brl. A label is always at the start + of the bundle. Even if there are predicates on NOPs, we still + perform this optimization. */ + template = t0 & 0x1e; + s0 = (t0 >> 5) & 0x1ffffffffffLL; + s1 = ((t0 >> 46) | (t1 << 18)) & 0x1ffffffffffLL; + s2 = (t1 >> 23) & 0x1ffffffffffLL; + switch (br_slot) + { + case 0: + /* Check if slot 1 and slot 2 are NOPs. Possible template is + BBB. We only need to check nop.b. */ + if (!(IS_NOP_B (s1) && IS_NOP_B (s2))) + return FALSE; + br_code = s0; + break; + case 1: + /* Check if slot 2 is NOP. Possible templates are MBB and BBB. + For BBB, slot 0 also has to be nop.b. */ + if (!((template == 0x12 /* MBB */ + && IS_NOP_B (s2)) + || (template == 0x16 /* BBB */ + && IS_NOP_B (s0) + && IS_NOP_B (s2)))) + return FALSE; + br_code = s1; + break; + case 2: + /* Check if slot 1 is NOP. Possible templates are MIB, MBB, BBB, + MMB and MFB. For BBB, slot 0 also has to be nop.b. */ + if (!((template == 0x10 /* MIB */ + && IS_NOP_I (s1)) + || (template == 0x12 /* MBB */ + && IS_NOP_B (s1)) + || (template == 0x16 /* BBB */ + && IS_NOP_B (s0) + && IS_NOP_B (s1)) + || (template == 0x18 /* MMB */ + && IS_NOP_M (s1)) + || (template == 0x1c /* MFB */ + && IS_NOP_F (s1)))) + return FALSE; + br_code = s2; + break; + default: + /* It should never happen. */ + abort (); + } + + /* We can turn br.cond/br.call into brl.cond/brl.call. */ + if (!(IS_BR_COND (br_code) || IS_BR_CALL (br_code))) + return FALSE; + + /* Turn br into brl by setting bit 40. */ + br_code |= 0x1LL << 40; + + /* Turn the old bundle into a MLX bundle with the same stop-bit + variety. */ + if (t0 & 0x1) + mlx = 0x5; + else + mlx = 0x4; + + if (template == 0x16) + { + /* For BBB, we need to put nop.m in slot 0. We keep the original + predicate only if slot 0 isn't br. */ + if (br_slot == 0) + t0 = 0LL; + else + t0 &= PREDICATE_BITS << 5; + t0 |= 0x1LL << (X4_SHIFT + 5); + } + else + { + /* Keep the original instruction in slot 0. */ + t0 &= 0x1ffffffffffLL << 5; + } + + t0 |= mlx; + + /* Put brl in slot 1. */ + t1 = br_code << 23; + + bfd_putl64 (t0, hit_addr); + bfd_putl64 (t1, hit_addr + 8); + return TRUE; +} + +static void +elfNN_ia64_relax_brl (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_getl64 (hit_addr); + t1 = bfd_getl64 (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. */ + if (t0 & 0x1) + template = 0x13; + else + template = 0x12; + t0 = (i1 << 46) | (i0 << 5) | template; + t1 = (i2 << 23) | (i1 >> 18); + + bfd_putl64 (t0, hit_addr); + bfd_putl64 (t1, hit_addr + 8); +} /* These functions do relaxation for IA-64 ELF. */ @@ -691,22 +887,17 @@ 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; - /* If this is the first time we have been called for this section, - initialize the cooked size. */ - if (sec->_cooked_size == 0) - sec->_cooked_size = sec->_raw_size; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; /* Load the relocations for this section. */ @@ -724,12 +915,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) contents = elf_section_data (sec)->this_hdr.contents; else { - contents = (bfd_byte *) bfd_malloc (sec->_raw_size); - if (contents == NULL) - goto error_return; - - if (! bfd_get_section_contents (abfd, sec, contents, - (file_ptr) 0, sec->_raw_size)) + if (!bfd_malloc_and_get_section (abfd, sec, &contents)) goto error_return; } @@ -742,6 +928,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) bfd_size_type amt; bfd_boolean is_branch; struct elfNN_ia64_dyn_sym_info *dyn_i; + char symtype; switch (r_type) { @@ -749,14 +936,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 +992,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) @@ -800,6 +1004,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) toff = isym->st_value; dyn_i = get_dyn_sym_info (ia64_info, NULL, abfd, irel, FALSE); + symtype = ELF_ST_TYPE (isym->st_info); } else { @@ -836,7 +1041,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) 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; @@ -844,13 +1049,38 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) tsec = h->root.u.def.section; toff = h->root.u.def.value; } + + symtype = h->type; } if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE) - toff = _bfd_merged_section_offset (abfd, &tsec, - elf_section_data (tsec)->sec_info, - toff + irel->r_addend, - (bfd_vma) 0); + { + /* At this stage in linking, no SEC_MERGE symbol has been + adjusted, so all references to such symbols need to be + passed through _bfd_merged_section_offset. (Later, in + relocate_section, all SEC_MERGE symbols *except* for + section symbols have been adjusted.) + + gas may reduce relocations against symbols in SEC_MERGE + sections to a relocation against the section symbol when + the original addend was zero. When the reloc is against + a section symbol we should include the addend in the + offset passed to _bfd_merged_section_offset, since the + location of interest is the original symbol. On the + other hand, an access to "sym+addend" where "sym" is not + a section symbol should not include the addend; Such an + access is presumed to be an offset from "sym"; The + location of interest is just "sym". */ + if (symtype == STT_SECTION) + toff += irel->r_addend; + + toff = _bfd_merged_section_offset (abfd, &tsec, + elf_section_data (tsec)->sec_info, + toff); + + if (symtype != STT_SECTION) + toff += irel->r_addend; + } else toff += irel->r_addend; @@ -860,6 +1090,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,12 +1099,54 @@ 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 (contents, roff); + + irel->r_info + = ELFNN_R_INFO (ELFNN_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; + else if (elfNN_ia64_relax_br (contents, roff)) + { + irel->r_info + = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), + R_IA64_PCREL60B); + + /* Make the relocation offset point to slot 1. */ + irel->r_offset = (irel->r_offset & ~((bfd_vma) 0x3)) + 1; + continue; + } + + /* We can't put a trampoline in a .init/.fini section. Issue + an error. */ + if (strcmp (sec->output_section->name, ".init") == 0 + || strcmp (sec->output_section->name, ".fini") == 0) + { + (*_bfd_error_handler) + (_("%B: Can't relax br at 0x%lx in section `%A'. Please use brl or indirect branch."), + sec->owner, sec, (unsigned long) roff); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } /* If the branch and target are in the same section, you've - got one honking big section and we can't help you. You'll - get an error message later. */ - if (tsec == sec) + got one honking big section and we can't help you unless + you are branching backwards. You'll get an error message + later. */ + if (tsec == sec && toff > roff) continue; /* Look for an existing fixup to this address. */ @@ -891,17 +1165,22 @@ 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; + trampoff = (sec->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) goto error_return; - sec->_cooked_size = amt; + sec->size = amt; if (tsec == ia64_info->plt_sec) { @@ -914,10 +1193,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,15 +1222,19 @@ 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), - r_type) != bfd_reloc_ok) + /* Fix up the existing branch to hit the trampoline. */ + if (elfNN_ia64_install_value (contents + roff, offset, r_type) + != bfd_reloc_ok) goto error_return; changed_contents = TRUE; @@ -978,7 +1273,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) } else { - elfNN_ia64_relax_ldxmov (abfd, contents, roff); + elfNN_ia64_relax_ldxmov (contents, roff); irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE); changed_contents = TRUE; changed_relocs = TRUE; @@ -990,7 +1285,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) enough that the data segment moves, which will change the GP. Reset the GP so that we re-calculate next round. We need to do this at the _beginning_ of the next round; now will not do. */ - + /* Clean up and go home. */ while (fixups) { @@ -1041,13 +1336,23 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data); elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data); elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data); - ia64_info->got_sec->_raw_size = data.ofs; - ia64_info->got_sec->_cooked_size = data.ofs; + ia64_info->got_sec->size = data.ofs; - /* ??? Resize .rela.got too. */ + if (ia64_info->root.dynamic_sections_created + && ia64_info->rel_got_sec != NULL) + { + /* Resize .rela.got. */ + ia64_info->rel_got_sec->size = 0; + if (link_info->shared + && ia64_info->self_dtpmod_offset != (bfd_vma) -1) + ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); + data.only_got = TRUE; + elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries, + &data); + } } - if (link_info->relax_finalizing) + if (!link_info->need_relax_finalize) sec->need_finalize_relax = 0; *again = changed_contents || changed_relocs; @@ -1066,8 +1371,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) } static void -elfNN_ia64_relax_ldxmov (abfd, contents, off) - bfd *abfd; +elfNN_ia64_relax_ldxmov (contents, off) bfd_byte *contents; bfd_vma off; { @@ -1083,7 +1387,7 @@ elfNN_ia64_relax_ldxmov (abfd, contents, off) abort (); } - dword = bfd_get_64 (abfd, contents + off); + dword = bfd_getl64 (contents + off); insn = (dword >> shift) & 0x1ffffffffffLL; r1 = (insn >> 6) & 127; @@ -1095,7 +1399,7 @@ elfNN_ia64_relax_ldxmov (abfd, contents, off) dword &= ~(0x1ffffffffffLL << shift); dword |= (insn << shift); - bfd_put_64 (abfd, dword, contents + off); + bfd_putl64 (dword, contents + off); } /* Return TRUE if NAME is an unwind table section name. */ @@ -1120,13 +1424,14 @@ is_unwind_section_name (abfd, name) } /* Handle an IA-64 specific section when reading an object file. This - is called when elfcode.h finds a section with an unknown type. */ + is called when bfd_section_from_shdr finds a section with an unknown + type. */ static bfd_boolean -elfNN_ia64_section_from_shdr (abfd, hdr, name) - bfd *abfd; - Elf_Internal_Shdr *hdr; - const char *name; +elfNN_ia64_section_from_shdr (bfd *abfd, + Elf_Internal_Shdr *hdr, + const char *name, + int shindex) { asection *newsect; @@ -1150,7 +1455,7 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name) return FALSE; } - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; newsect = hdr->bfd_section; @@ -1165,7 +1470,7 @@ elfNN_ia64_section_from_shdr (abfd, hdr, name) static bfd_boolean elfNN_ia64_section_flags (flags, hdr) flagword *flags; - Elf_Internal_Shdr *hdr; + const Elf_Internal_Shdr *hdr; { if (hdr->sh_flags & SHF_IA_64_SHORT) *flags |= SEC_SMALL_DATA; @@ -1219,6 +1524,11 @@ elfNN_ia64_fake_sections (abfd, hdr, sec) if (sec->flags & SEC_SMALL_DATA) hdr->sh_flags |= SHF_IA_64_SHORT; + /* Some HP linkers look for the SHF_IA_64_HP_TLS flag instead of SHF_TLS. */ + + if (elfNN_ia64_hpux_vec (abfd->xvec) && (sec->flags & SHF_TLS)) + hdr->sh_flags |= SHF_IA_64_HP_TLS; + return TRUE; } @@ -1231,9 +1541,7 @@ elfNN_ia64_final_write_processing (abfd, linker) bfd_boolean linker ATTRIBUTE_UNUSED; { Elf_Internal_Shdr *hdr; - const char *sname; - asection *text_sect, *s; - size_t len; + asection *s; for (s = abfd->sections; s; s = s->next) { @@ -1241,64 +1549,11 @@ elfNN_ia64_final_write_processing (abfd, linker) switch (hdr->sh_type) { case SHT_IA_64_UNWIND: - /* See comments in gas/config/tc-ia64.c:dot_endp on why we - have to do this. */ - sname = bfd_get_section_name (abfd, s); - len = sizeof (ELF_STRING_ia64_unwind) - 1; - if (sname && strncmp (sname, ELF_STRING_ia64_unwind, len) == 0) - { - sname += len; - - if (sname[0] == '\0') - /* .IA_64.unwind -> .text */ - text_sect = bfd_get_section_by_name (abfd, ".text"); - else - /* .IA_64.unwindFOO -> FOO */ - text_sect = bfd_get_section_by_name (abfd, sname); - } - else if (sname - && (len = sizeof (ELF_STRING_ia64_unwind_once) - 1, - strncmp (sname, ELF_STRING_ia64_unwind_once, len)) == 0) - { - /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.t.FOO */ - size_t len2 = sizeof (".gnu.linkonce.t.") - 1; - char *once_name = bfd_malloc (len2 + strlen (sname + len) + 1); - - if (once_name != NULL) - { - memcpy (once_name, ".gnu.linkonce.t.", len2); - strcpy (once_name + len2, sname + len); - text_sect = bfd_get_section_by_name (abfd, once_name); - free (once_name); - } - else - /* Should only happen if we run out of memory, in - which case we're probably toast anyway. Try to - cope by finding the section the slow way. */ - for (text_sect = abfd->sections; - text_sect != NULL; - text_sect = text_sect->next) - { - if (strncmp (bfd_section_name (abfd, text_sect), - ".gnu.linkonce.t.", len2) == 0 - && strcmp (bfd_section_name (abfd, text_sect) + len2, - sname + len) == 0) - break; - } - } - else - /* last resort: fall back on .text */ - text_sect = bfd_get_section_by_name (abfd, ".text"); - - if (text_sect) - { - /* The IA-64 processor-specific ABI requires setting - sh_link to the unwind section, whereas HP-UX requires - sh_info to do so. For maximum compatibility, we'll - set both for now... */ - hdr->sh_link = elf_section_data (text_sect)->this_idx; - hdr->sh_info = elf_section_data (text_sect)->this_idx; - } + /* The IA-64 processor-specific ABI requires setting sh_link + to the unwind section, whereas HP-UX requires sh_info to + do so. For maximum compatibility, we'll set both for + now... */ + hdr->sh_info = hdr->sh_link; break; } } @@ -1324,7 +1579,7 @@ static bfd_boolean elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) bfd *abfd; struct bfd_link_info *info; - const Elf_Internal_Sym *sym; + Elf_Internal_Sym *sym; const char **namep ATTRIBUTE_UNUSED; flagword *flagsp ATTRIBUTE_UNUSED; asection **secp; @@ -1341,11 +1596,11 @@ elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) if (scomm == NULL) { - scomm = bfd_make_section (abfd, ".scommon"); - if (scomm == NULL - || !bfd_set_section_flags (abfd, scomm, (SEC_ALLOC - | SEC_IS_COMMON - | SEC_LINKER_CREATED))) + scomm = bfd_make_section_with_flags (abfd, ".scommon", + (SEC_ALLOC + | SEC_IS_COMMON + | SEC_LINKER_CREATED)); + if (scomm == NULL) return FALSE; } @@ -1379,8 +1634,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; @@ -1472,7 +1728,7 @@ elfNN_ia64_modify_segment_map (abfd) int i; for (i = m->count - 1; i >= 0; --i) { - struct bfd_link_order *order = m->sections[i]->link_order_head; + struct bfd_link_order *order = m->sections[i]->map_head.link_order; while (order) { if (order->type == bfd_indirect_link_order) @@ -1520,44 +1776,6 @@ elfNN_ia64_dynamic_symbol_p (h, info, r_type) 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; @@ -1575,21 +1793,18 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string) 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_link_hash_entry *) _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + ret->info = NULL; return (struct bfd_hash_entry *) ret; } static void -elfNN_ia64_hash_copy_indirect (bed, xdir, xind) - const struct elf_backend_data *bed ATTRIBUTE_UNUSED; +elfNN_ia64_hash_copy_indirect (info, xdir, xind) + struct bfd_link_info *info; struct elf_link_hash_entry *xdir, *xind; { struct elfNN_ia64_link_hash_entry *dir, *ind; @@ -1600,11 +1815,10 @@ elfNN_ia64_hash_copy_indirect (bed, xdir, xind) /* Copy down any references that we may have already seen to the symbol which just became indirect. */ - dir->root.elf_link_hash_flags |= - (ind->root.elf_link_hash_flags - & (ELF_LINK_HASH_REF_DYNAMIC - | ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK)); + dir->root.ref_dynamic |= ind->root.ref_dynamic; + dir->root.ref_regular |= ind->root.ref_regular; + dir->root.ref_regular_nonweak |= ind->root.ref_regular_nonweak; + dir->root.needs_plt |= ind->root.needs_plt; if (ind->root.root.type != bfd_link_hash_indirect) return; @@ -1612,29 +1826,34 @@ elfNN_ia64_hash_copy_indirect (bed, xdir, xind) /* Copy over the got and plt data. This would have been done by check_relocs. */ - if (dir->info == NULL) + if (ind->info != NULL) { struct elfNN_ia64_dyn_sym_info *dyn_i; + struct elfNN_ia64_dyn_sym_info **pdyn; - dir->info = dyn_i = ind->info; + pdyn = &dir->info; + while ((dyn_i = *pdyn) != NULL) + pdyn = &dyn_i->next; + *pdyn = dyn_i = ind->info; ind->info = NULL; /* Fix up the dyn_sym_info pointers to the global symbol. */ for (; dyn_i; dyn_i = dyn_i->next) dyn_i->h = &dir->root; } - BFD_ASSERT (ind->info == NULL); /* Copy over the dynindx. */ - if (dir->root.dynindx == -1) + if (ind->root.dynindx != -1) { + if (dir->root.dynindx != -1) + _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, + dir->root.dynstr_index); dir->root.dynindx = ind->root.dynindx; dir->root.dynstr_index = ind->root.dynstr_index; ind->root.dynindx = -1; ind->root.dynstr_index = 0; } - BFD_ASSERT (ind->root.dynindx == -1); } static void @@ -1657,6 +1876,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). */ @@ -1678,8 +1924,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; @@ -1688,16 +1936,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. */ @@ -1729,20 +1980,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 @@ -1758,8 +2009,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 @@ -1788,25 +2039,25 @@ elfNN_ia64_create_dynamic_sections (abfd, info) if (!get_pltoff (abfd, info, ia64_info)) return FALSE; - s = bfd_make_section(abfd, ".rela.IA_64.pltoff"); + s = bfd_make_section_with_flags (abfd, ".rela.IA_64.pltoff", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); if (s == NULL - || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)) - || !bfd_set_section_alignment (abfd, s, 3)) + || !bfd_set_section_alignment (abfd, s, LOG_SECTION_ALIGN)) return FALSE; ia64_info->rel_pltoff_sec = s; - s = bfd_make_section(abfd, ".rela.got"); + s = bfd_make_section_with_flags (abfd, ".rela.got", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); if (s == NULL - || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)) - || !bfd_set_section_alignment (abfd, s, 3)) + || !bfd_set_section_alignment (abfd, s, LOG_SECTION_ALIGN)) return FALSE; ia64_info->rel_got_sec = s; @@ -1821,22 +2072,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; } @@ -1921,7 +2183,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. */ @@ -1941,15 +2203,14 @@ get_fptr (abfd, info, ia64_info) if (!dynobj) ia64_info->root.dynobj = dynobj = abfd; - fptr = bfd_make_section (dynobj, ".opd"); + fptr = bfd_make_section_with_flags (dynobj, ".opd", + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | (info->pie ? 0 : SEC_READONLY) + | SEC_LINKER_CREATED)); if (!fptr - || !bfd_set_section_flags (dynobj, fptr, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | (info->pie ? 0 : SEC_READONLY) - | SEC_LINKER_CREATED)) || !bfd_set_section_alignment (abfd, fptr, 4)) { BFD_ASSERT (0); @@ -1961,15 +2222,15 @@ 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_with_flags (dynobj, ".rela.opd", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); if (fptr_rel == NULL - || !bfd_set_section_flags (abfd, 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_set_section_alignment (abfd, fptr_rel, + LOG_SECTION_ALIGN)) { BFD_ASSERT (0); return NULL; @@ -1998,15 +2259,15 @@ get_pltoff (abfd, info, ia64_info) if (!dynobj) ia64_info->root.dynobj = dynobj = abfd; - pltoff = bfd_make_section (dynobj, ELF_STRING_ia64_pltoff); + pltoff = bfd_make_section_with_flags (dynobj, + ELF_STRING_ia64_pltoff, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_SMALL_DATA + | SEC_LINKER_CREATED)); if (!pltoff - || !bfd_set_section_flags (dynobj, pltoff, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_SMALL_DATA - | SEC_LINKER_CREATED)) || !bfd_set_section_alignment (abfd, pltoff, 4)) { BFD_ASSERT (0); @@ -2050,31 +2311,24 @@ get_reloc_section (abfd, ia64_info, sec, create) srel = bfd_get_section_by_name (dynobj, srel_name); if (srel == NULL && create) { - srel = bfd_make_section (dynobj, srel_name); + srel = bfd_make_section_with_flags (dynobj, srel_name, + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); if (srel == NULL - || !bfd_set_section_flags (dynobj, srel, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)) - || !bfd_set_section_alignment (dynobj, srel, 3)) + || !bfd_set_section_alignment (dynobj, srel, + LOG_SECTION_ALIGN)) 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; @@ -2095,6 +2349,7 @@ count_dyn_reloc (abfd, dyn_i, srel, type) rent->count = 0; dyn_i->reloc_entries = rent; } + rent->reltext = reltext; rent->count++; return TRUE; @@ -2111,7 +2366,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) const Elf_Internal_Rela *relend; Elf_Internal_Shdr *symtab_hdr; const Elf_Internal_Rela *rel; - asection *got, *fptr, *srel; + asection *got, *fptr, *srel, *pltoff; if (info->relocatable) return TRUE; @@ -2119,7 +2374,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) symtab_hdr = &elf_tdata (abfd)->symtab_hdr; ia64_info = elfNN_ia64_hash_table (info); - got = fptr = srel = NULL; + got = fptr = srel = pltoff = NULL; relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; ++rel) @@ -2155,7 +2410,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + h->ref_regular = 1; } /* We can only get preliminary data on whether a symbol is @@ -2164,8 +2419,9 @@ 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->unresolved_syms_in_shared_libs == RM_IGNORE)) - || ! (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) + && (!info->symbolic + || info->unresolved_syms_in_shared_libs == RM_IGNORE)) + || !h->def_regular || h->root.type == bfd_link_hash_defweak)) maybe_dynamic = TRUE; @@ -2187,11 +2443,13 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) info->flags |= DF_STATIC_TLS; break; + case R_IA64_DTPREL32MSB: + case R_IA64_DTPREL32LSB: case R_IA64_DTPREL64MSB: case R_IA64_DTPREL64LSB: if (info->shared || maybe_dynamic) need_entry = NEED_DYNREL; - dynrel_type = R_IA64_DTPREL64LSB; + dynrel_type = R_IA64_DTPRELNNLSB; break; case R_IA64_LTOFF_DTPREL22: @@ -2227,7 +2485,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) need_entry = NEED_FPTR | NEED_DYNREL; else need_entry = NEED_FPTR; - dynrel_type = R_IA64_FPTR64LSB; + dynrel_type = R_IA64_FPTRNNLSB; break; case R_IA64_LTOFF22: @@ -2277,7 +2535,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) /* Shared objects will always need at least a REL relocation. */ if (info->shared || maybe_dynamic) need_entry = NEED_DYNREL; - dynrel_type = R_IA64_DIR64LSB; + dynrel_type = R_IA64_DIRNNLSB; break; case R_IA64_IPLTMSB: @@ -2296,7 +2554,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) case R_IA64_PCREL64LSB: if (maybe_dynamic) need_entry = NEED_DYNREL; - dynrel_type = R_IA64_PCREL64LSB; + dynrel_type = R_IA64_PCRELNNLSB; break; } @@ -2351,7 +2609,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) dynamic symbol table. */ if (!h && info->shared) { - if (! (_bfd_elfNN_link_record_local_dynamic_symbol + if (! (bfd_elf_link_record_local_dynamic_symbol (info, abfd, (long) r_symndx))) return FALSE; } @@ -2364,13 +2622,24 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) { if (!ia64_info->root.dynobj) ia64_info->root.dynobj = abfd; - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->needs_plt = 1; dyn_i->want_plt = 1; } if (need_entry & NEED_FULL_PLT) dyn_i->want_plt2 = 1; if (need_entry & NEED_PLTOFF) - dyn_i->want_pltoff = 1; + { + /* This is needed here, in case @pltoff is used in a non-shared + link. */ + if (!pltoff) + { + pltoff = get_pltoff (abfd, info, ia64_info); + if (!pltoff) + return FALSE; + } + + dyn_i->want_pltoff = 1; + } if ((need_entry & NEED_DYNREL) && (sec->flags & SEC_ALLOC)) { if (!srel) @@ -2379,7 +2648,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; } } @@ -2448,7 +2718,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, R_IA64_FPTR64LSB)) + && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, R_IA64_FPTRNNLSB)) { dyn_i->got_offset = x->ofs; x->ofs += 8; @@ -2515,14 +2785,15 @@ allocate_fptr (dyn_i, data) if (!x->info->executable && (!h || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT - || h->root.type != bfd_link_hash_undefweak)) + || (h->root.type != bfd_link_hash_undefweak + && h->root.type != bfd_link_hash_undefined))) { if (h && h->dynindx == -1) { BFD_ASSERT ((h->root.type == bfd_link_hash_defined) || (h->root.type == bfd_link_hash_defweak)); - if (!_bfd_elfNN_link_record_local_dynamic_symbol + if (!bfd_elf_link_record_local_dynamic_symbol (x->info, h->root.u.def.section->owner, global_sym_index (h))) return FALSE; @@ -2559,7 +2830,7 @@ allocate_plt_entries (dyn_i, data) || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - /* ??? Versioned symbols seem to lose ELF_LINK_HASH_NEEDS_PLT. */ + /* ??? Versioned symbols seem to lose NEEDS_PLT. */ if (elfNN_ia64_dynamic_symbol_p (h, x->info, 0)) { bfd_size_type offset = x->ofs; @@ -2647,6 +2918,52 @@ allocate_dynrel_entries (dyn_i, data) && ELF_ST_VISIBILITY (dyn_i->h->other) && dyn_i->h->root.type == bfd_link_hash_undefweak); + /* Take care of the GOT and PLT relocations. */ + + if ((!resolved_zero + && (dynamic_symbol || shared) + && (dyn_i->want_got || dyn_i->want_gotx)) + || (dyn_i->want_ltoff_fptr + && dyn_i->h + && dyn_i->h->dynindx != -1)) + { + 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->size += sizeof (ElfNN_External_Rela); + } + if ((dynamic_symbol || shared) && dyn_i->want_tprel) + ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); + if (dynamic_symbol && dyn_i->want_dtpmod) + ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); + if (dynamic_symbol && dyn_i->want_dtprel) + ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); + + if (x->only_got) + return TRUE; + + 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->size += sizeof (ElfNN_External_Rela); + } + + if (!resolved_zero && dyn_i->want_pltoff) + { + bfd_size_type t = 0; + + /* Dynamic symbols get one IPLT relocation. Local symbols in + shared libraries get two REL relocations. Local symbols in + main applications get nothing. */ + if (dynamic_symbol) + t = sizeof (ElfNN_External_Rela); + else if (shared) + t = 2 * sizeof (ElfNN_External_Rela); + + ia64_info->rel_pltoff_sec->size += t; + } + /* Take care of the normal data relocations. */ for (rent = dyn_i->reloc_entries; rent; rent = rent->next) @@ -2655,6 +2972,7 @@ allocate_dynrel_entries (dyn_i, data) switch (rent->type) { + case R_IA64_FPTR32LSB: case R_IA64_FPTR64LSB: /* Allocate one iff !want_fptr and not PIE, which by this point will be true only if we're actually allocating one statically @@ -2663,10 +2981,12 @@ allocate_dynrel_entries (dyn_i, data) if (dyn_i->want_fptr && !x->info->pie) continue; break; + case R_IA64_PCREL32LSB: case R_IA64_PCREL64LSB: if (!dynamic_symbol) continue; break; + case R_IA64_DIR32LSB: case R_IA64_DIR64LSB: if (!dynamic_symbol && !shared) continue; @@ -2679,6 +2999,7 @@ allocate_dynrel_entries (dyn_i, data) if (!dynamic_symbol) count *= 2; break; + case R_IA64_DTPREL32LSB: case R_IA64_TPREL64LSB: case R_IA64_DTPREL64LSB: case R_IA64_DTPMOD64LSB: @@ -2686,49 +3007,9 @@ allocate_dynrel_entries (dyn_i, data) default: abort (); } - rent->srel->_raw_size += sizeof (ElfNN_External_Rela) * count; - } - - /* Take care of the GOT and PLT relocations. */ - - if ((!resolved_zero - && (dynamic_symbol || shared) - && (dyn_i->want_got || dyn_i->want_gotx)) - || (dyn_i->want_ltoff_fptr - && dyn_i->h - && dyn_i->h->dynindx != -1)) - { - 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) - { - bfd_size_type t = 0; - - /* Dynamic symbols get one IPLT relocation. Local symbols in - shared libraries get two REL relocations. Local symbols in - main applications get nothing. */ - if (dynamic_symbol) - t = sizeof (ElfNN_External_Rela); - else if (shared) - t = 2 * sizeof (ElfNN_External_Rela); - - ia64_info->rel_pltoff_sec->_raw_size += t; + if (rent->reltext) + ia64_info->reltext = 1; + rent->srel->size += sizeof (ElfNN_External_Rela) * count; } return TRUE; @@ -2745,12 +3026,12 @@ elfNN_ia64_adjust_dynamic_symbol (info, h) /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the real definition first, and we can just use the same value. */ - if (h->weakdef != NULL) + if (h->u.weakdef != NULL) { - BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined - || h->weakdef->root.type == bfd_link_hash_defweak); - h->root.u.def.section = h->weakdef->root.u.def.section; - h->root.u.def.value = h->weakdef->root.u.def.value; + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; return TRUE; } @@ -2788,7 +3069,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) sec = bfd_get_section_by_name (dynobj, ".interp"); BFD_ASSERT (sec != NULL); sec->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; - sec->_raw_size = strlen (ELF_DYNAMIC_INTERPRETER) + 1; + sec->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1; } /* Allocate the GOT entries. */ @@ -2799,7 +3080,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data); elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data); elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data); - ia64_info->got_sec->_raw_size = data.ofs; + ia64_info->got_sec->size = data.ofs; } /* Allocate the FPTR entries. */ @@ -2808,7 +3089,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) { data.ofs = 0; elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_fptr, &data); - ia64_info->fptr_sec->_raw_size = data.ofs; + ia64_info->fptr_sec->size = data.ofs; } /* Now that we've seen all of the input files, we can decide which @@ -2830,16 +3111,20 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) data.ofs = (data.ofs + 31) & (bfd_vma) -32; elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_plt2_entries, &data); - if (data.ofs != 0) + if (data.ofs != 0 || ia64_info->root.dynamic_sections_created) { + /* FIXME: we always reserve the memory for dynamic linker even if + there are no PLT entries since dynamic linker may assume the + reserved memory always exists. */ + BFD_ASSERT (ia64_info->root.dynamic_sections_created); - ia64_info->plt_sec->_raw_size = data.ofs; + ia64_info->plt_sec->size = data.ofs; /* If we've got a .plt, we need some extra memory for the dynamic linker. We stuff these in .got.plt. */ sec = bfd_get_section_by_name (dynobj, ".got.plt"); - sec->_raw_size = 8 * PLT_RESERVED_WORDS; + sec->size = 8 * PLT_RESERVED_WORDS; } /* Allocate the PLTOFF entries. */ @@ -2848,7 +3133,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) { data.ofs = 0; elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_pltoff_entries, &data); - ia64_info->pltoff_sec->_raw_size = data.ofs; + ia64_info->pltoff_sec->size = data.ofs; } if (ia64_info->root.dynamic_sections_created) @@ -2857,7 +3142,8 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) required. */ if (info->shared && ia64_info->self_dtpmod_offset != (bfd_vma) -1) - ia64_info->rel_got_sec->_raw_size += sizeof (ElfNN_External_Rela); + ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); + data.only_got = FALSE; elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries, &data); } @@ -2878,7 +3164,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) function which decides whether anything needs to go into these sections. */ - strip = (sec->_raw_size == 0); + strip = (sec->size == 0); if (sec == ia64_info->got_sec) strip = FALSE; @@ -2896,6 +3182,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) @@ -2942,12 +3237,12 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) } if (strip) - _bfd_strip_section_from_output (info, sec); + sec->flags |= SEC_EXCLUDE; else { /* Allocate memory for the section contents. */ - sec->contents = (bfd_byte *) bfd_zalloc (dynobj, sec->_raw_size); - if (sec->contents == NULL && sec->_raw_size != 0) + sec->contents = (bfd_byte *) bfd_zalloc (dynobj, sec->size); + if (sec->contents == NULL && sec->size != 0) return FALSE; } } @@ -2963,7 +3258,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) /* The DT_DEBUG entry is filled in by the dynamic linker and used by the debugger. */ #define add_dynamic_entry(TAG, VAL) \ - bfd_elfNN_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) + _bfd_elf_add_dynamic_entry (info, TAG, VAL) if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; @@ -3001,15 +3296,15 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) } static bfd_reloc_status_type -elfNN_ia64_install_value (abfd, hit_addr, v, r_type) - bfd *abfd; +elfNN_ia64_install_value (hit_addr, v, r_type) bfd_byte *hit_addr; bfd_vma v; unsigned int r_type; { const struct ia64_operand *op; int bigendian = 0, shift = 0; - bfd_vma t0, t1, insn, dword; + bfd_vma t0, t1, dword; + ia64_insn insn; enum ia64_opnd opnd; const char *err; size_t size = 8; @@ -3134,8 +3429,8 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type) { case IA64_OPND_IMMU64: hit_addr -= (long) hit_addr & 0x3; - t0 = bfd_get_64 (abfd, hit_addr); - t1 = bfd_get_64 (abfd, hit_addr + 8); + t0 = bfd_getl64 (hit_addr); + t1 = bfd_getl64 (hit_addr + 8); /* tmpl/s: bits 0.. 5 in t0 slot 0: bits 5..45 in t0 @@ -3157,14 +3452,14 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type) | (((val >> 21) & 0x001) << 21) /* ic */ | (((val >> 63) & 0x001) << 36)) << 23; /* i */ - bfd_put_64 (abfd, t0, hit_addr); - bfd_put_64 (abfd, t1, hit_addr + 8); + bfd_putl64 (t0, hit_addr); + bfd_putl64 (t1, hit_addr + 8); break; case IA64_OPND_TGT64: hit_addr -= (long) hit_addr & 0x3; - t0 = bfd_get_64 (abfd, hit_addr); - t1 = bfd_get_64 (abfd, hit_addr + 8); + t0 = bfd_getl64 (hit_addr); + t1 = bfd_getl64 (hit_addr + 8); /* tmpl/s: bits 0.. 5 in t0 slot 0: bits 5..45 in t0 @@ -3182,8 +3477,8 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type) t1 |= ((((val >> 0) & 0xfffffLL) << 13) /* imm20b */ | (((val >> 59) & 0x1LL) << 36)) << 23; /* i */ - bfd_put_64 (abfd, t0, hit_addr); - bfd_put_64 (abfd, t1, hit_addr + 8); + bfd_putl64 (t0, hit_addr); + bfd_putl64 (t1, hit_addr + 8); break; default: @@ -3194,17 +3489,17 @@ elfNN_ia64_install_value (abfd, hit_addr, v, r_type) case 2: shift = 23; hit_addr += 6; break; case 3: return bfd_reloc_notsupported; /* shouldn't happen... */ } - dword = bfd_get_64 (abfd, hit_addr); + dword = bfd_getl64 (hit_addr); insn = (dword >> shift) & 0x1ffffffffffLL; op = elf64_ia64_operands + opnd; - err = (*op->insert) (op, val, (ia64_insn *)& insn); + err = (*op->insert) (op, val, &insn); if (err) return bfd_reloc_overflow; dword &= ~(0x1ffffffffffLL << shift); dword |= (insn << shift); - bfd_put_64 (abfd, dword, hit_addr); + bfd_putl64 (dword, hit_addr); break; case IA64_OPND_NIL: @@ -3258,8 +3553,7 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type, loc = srel->contents; loc += srel->reloc_count++ * sizeof (ElfNN_External_Rela); bfd_elfNN_swap_reloca_out (abfd, &outrel, loc); - BFD_ASSERT (sizeof (ElfNN_External_Rela) * srel->reloc_count - <= srel->_cooked_size); + BFD_ASSERT (sizeof (ElfNN_External_Rela) * srel->reloc_count <= srel->size); } /* Store an entry for target address TARGET_ADDR in the linkage table @@ -3304,6 +3598,7 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) } got_offset = dyn_i->dtpmod_offset; break; + case R_IA64_DTPREL32LSB: case R_IA64_DTPREL64LSB: done = dyn_i->dtprel_done; dyn_i->dtprel_done = TRUE; @@ -3328,9 +3623,12 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) && (!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_DTPREL32LSB && 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)) + || (dynindx != -1 + && (dyn_r_type == R_IA64_FPTR32LSB + || dyn_r_type == R_IA64_FPTR64LSB))) && (!dyn_i->want_ltoff_fptr || !info->pie || !dyn_i->h @@ -3339,9 +3637,10 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) if (dynindx == -1 && dyn_r_type != R_IA64_TPREL64LSB && dyn_r_type != R_IA64_DTPMOD64LSB + && dyn_r_type != R_IA64_DTPREL32LSB && dyn_r_type != R_IA64_DTPREL64LSB) { - dyn_r_type = R_IA64_REL64LSB; + dyn_r_type = R_IA64_RELNNLSB; dynindx = 0; addend = value; } @@ -3350,6 +3649,18 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) { switch (dyn_r_type) { + case R_IA64_REL32LSB: + dyn_r_type = R_IA64_REL32MSB; + break; + case R_IA64_DIR32LSB: + dyn_r_type = R_IA64_DIR32MSB; + break; + case R_IA64_FPTR32LSB: + dyn_r_type = R_IA64_FPTR32MSB; + break; + case R_IA64_DTPREL32LSB: + dyn_r_type = R_IA64_DTPREL32MSB; + break; case R_IA64_REL64LSB: dyn_r_type = R_IA64_REL64MSB; break; @@ -3479,9 +3790,9 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt) unsigned int dyn_r_type; if (bfd_big_endian (abfd)) - dyn_r_type = R_IA64_REL64MSB; + dyn_r_type = R_IA64_RELNNMSB; else - dyn_r_type = R_IA64_REL64LSB; + dyn_r_type = R_IA64_RELNNLSB; elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec, ia64_info->rel_pltoff_sec, @@ -3489,7 +3800,7 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt) dyn_r_type, 0, value); elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec, ia64_info->rel_pltoff_sec, - dyn_i->pltoff_offset + 8, + dyn_i->pltoff_offset + ARCH_SIZE / 8, dyn_r_type, 0, gp); } @@ -3507,18 +3818,17 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt) /* Return the base VMA address which should be subtracted from real addresses when resolving @tprel() relocation. Main program TLS (whose template starts at PT_TLS p_vaddr) - is assigned offset round(16, PT_TLS p_align). */ + is assigned offset round(2 * size of pointer, PT_TLS p_align). */ 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) ARCH_SIZE / 4, + tls_sec->alignment_power); } /* Return the base VMA address which should be subtracted from real addresses @@ -3529,8 +3839,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 @@ -3577,7 +3887,7 @@ elfNN_ia64_choose_gp (abfd, info) continue; lo = os->vma; - hi = os->vma + os->_raw_size; + hi = os->vma + os->size; if (hi < lo) hi = (bfd_vma) -1; @@ -3682,15 +3992,15 @@ elfNN_ia64_final_link (abfd, info) /* Make sure we've got ourselves a nice fat __gp value. */ if (!info->relocatable) { - bfd_vma gp_val = _bfd_get_gp_value (abfd); + bfd_vma gp_val; struct elf_link_hash_entry *gp; - if (gp_val == 0) - { - if (! elfNN_ia64_choose_gp (abfd, info)) - return FALSE; - gp_val = _bfd_get_gp_value (abfd); - } + /* We assume after gp is set, section size will only decrease. We + need to adjust gp for it. */ + _bfd_set_gp_value (abfd, 0); + if (! elfNN_ia64_choose_gp (abfd, info)) + return FALSE; + gp_val = _bfd_get_gp_value (abfd); gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, FALSE, FALSE); @@ -3713,27 +4023,27 @@ elfNN_ia64_final_link (abfd, info) { unwind_output_sec = s->output_section; unwind_output_sec->contents - = bfd_malloc (unwind_output_sec->_raw_size); + = bfd_malloc (unwind_output_sec->size); if (unwind_output_sec->contents == NULL) return FALSE; } } /* Invoke the regular ELF backend linker to do all the work. */ - if (!bfd_elfNN_bfd_final_link (abfd, info)) + if (!bfd_elf_final_link (abfd, info)) return FALSE; if (unwind_output_sec) { elfNN_ia64_unwind_entry_compare_bfd = abfd; qsort (unwind_output_sec->contents, - (size_t) (unwind_output_sec->_raw_size / 24), + (size_t) (unwind_output_sec->size / 24), 24, elfNN_ia64_unwind_entry_compare); if (! bfd_set_section_contents (abfd, unwind_output_sec, unwind_output_sec->contents, (bfd_vma) 0, - unwind_output_sec->_raw_size)) + unwind_output_sec->size)) return FALSE; } @@ -3800,8 +4110,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, if (r_type > R_IA64_MAX_RELOC_CODE) { (*_bfd_error_handler) - (_("%s: unknown relocation type %d"), - bfd_archive_filename (input_bfd), (int)r_type); + (_("%B: unknown relocation type %d"), + input_bfd, (int) r_type); bfd_set_error (bfd_error_bad_value); ret_val = FALSE; continue; @@ -3817,9 +4127,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) @@ -3830,7 +4142,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) { @@ -3840,8 +4151,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, elf_section_data (msec)-> sec_info, sym->st_value - + dynent->addend, - (bfd_vma) 0); + + dynent->addend); dynent->addend -= sym->st_value; dynent->addend += msec->output_section->vma + msec->output_offset @@ -3856,12 +4166,12 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, { bfd_boolean unresolved_reloc; bfd_boolean warned; + struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); - RELOC_FOR_GLOBAL_SYMBOL (h, elf_sym_hashes (input_bfd), - r_symndx, - symtab_hdr, value, sym_sec, - unresolved_reloc, info, - warned); + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sym_sec, value, + unresolved_reloc, warned); if (h->root.type == bfd_link_hash_undefweak) undef_weak_ref = TRUE; @@ -3897,6 +4207,26 @@ 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) + (_("%B: non-pic code with imm relocation against dynamic symbol `%s'"), + input_bfd, + h ? h->root.root.string + : bfd_elf_sym_name (input_bfd, symtab_hdr, sym, + sym_sec)); + ret_val = FALSE; + continue; + + default: + break; + } + /* If we don't need dynamic symbol lookup, find a matching RELATIVE relocation. */ dyn_r_type = r_type; @@ -3924,17 +4254,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; @@ -3950,7 +4270,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_LTV32LSB: case R_IA64_LTV64MSB: case R_IA64_LTV64LSB: - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_GPREL22: @@ -3962,13 +4282,16 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, if (dynamic_symbol_p) { (*_bfd_error_handler) - (_("%s: @gprel relocation against dynamic symbol %s"), - bfd_archive_filename (input_bfd), h->root.root.string); + (_("%B: @gprel relocation against dynamic symbol %s"), + input_bfd, + h ? h->root.root.string + : bfd_elf_sym_name (input_bfd, symtab_hdr, sym, + sym_sec)); ret_val = FALSE; continue; } value -= gp_val; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_LTOFF22: @@ -3976,9 +4299,9 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_LTOFF64I: dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); value = set_got_entry (input_bfd, info, dyn_i, (h ? h->dynindx : -1), - rel->r_addend, value, R_IA64_DIR64LSB); + rel->r_addend, value, R_IA64_DIRNNLSB); value -= gp_val; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_PLTOFF22: @@ -3988,7 +4311,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); value = set_pltoff_entry (output_bfd, info, dyn_i, value, FALSE); value -= gp_val; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_FPTR64I: @@ -4022,14 +4345,14 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, /* ??? 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)); + (_("%B: linking non-pic code in a position independent executable"), + input_bfd); ret_val = FALSE; continue; } dynindx = 0; addend = value; - dyn_r_type = r_type + R_IA64_REL64LSB - R_IA64_FPTR64LSB; + dyn_r_type = r_type + R_IA64_RELNNLSB - R_IA64_FPTRNNLSB; } else if (h) { @@ -4053,7 +4376,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, dynindx, addend); } - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_LTOFF_FPTR22: @@ -4068,7 +4391,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); if (dyn_i->want_fptr) { - BFD_ASSERT (h == NULL || h->dynindx == -1) + BFD_ASSERT (h == NULL || h->dynindx == -1); if (!undef_weak_ref) value = set_fptr_entry (output_bfd, info, dyn_i, value); dynindx = -1; @@ -4093,9 +4416,9 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, } value = set_got_entry (output_bfd, info, dyn_i, dynindx, - rel->r_addend, value, R_IA64_FPTR64LSB); + rel->r_addend, value, R_IA64_FPTRNNLSB); value -= gp_val; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); } break; @@ -4152,20 +4475,24 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_PCREL64I: /* The PCREL21BI reloc is specifically not intended for use with dynamic relocs. PCREL21F and PCREL21M are used for speculation - fixup code, and thus probably ought not be dynamic. The + fixup code, and thus probably ought not be dynamic. The PCREL22 and PCREL64I relocs aren't emitted as dynamic relocs. */ if (dynamic_symbol_p) { const char *msg; if (r_type == R_IA64_PCREL21BI) - msg = _("%s: @internal branch to dynamic symbol %s"); + msg = _("%B: @internal branch to dynamic symbol %s"); else if (r_type == R_IA64_PCREL21F || r_type == R_IA64_PCREL21M) - msg = _("%s: speculation fixup to dynamic symbol %s"); + msg = _("%B: speculation fixup to dynamic symbol %s"); else - msg = _("%s: @pcrel relocation against dynamic symbol %s"); - (*_bfd_error_handler) (msg, bfd_archive_filename (input_bfd), - h->root.root.string); + msg = _("%B: @pcrel relocation against dynamic symbol %s"); + (*_bfd_error_handler) (msg, input_bfd, + h ? h->root.root.string + : bfd_elf_sym_name (input_bfd, + symtab_hdr, + sym, + sym_sec)); ret_val = FALSE; continue; } @@ -4176,7 +4503,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, value -= (input_section->output_section->vma + input_section->output_offset + rel->r_offset) & ~ (bfd_vma) 0x3; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_SEGREL32MSB: @@ -4220,8 +4547,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, value -= p->p_vaddr; else value = 0; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, - r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); } break; } @@ -4230,12 +4556,11 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_SECREL32LSB: case R_IA64_SECREL64MSB: case R_IA64_SECREL64LSB: - /* Make output-section relative. */ - if (value > input_section->output_section->vma) - value -= input_section->output_section->vma; - else - value = 0; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + /* Make output-section relative to section where the symbol + is defined. PR 475 */ + if (sym_sec) + value -= sym_sec->output_section->vma; + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_IPLTMSB: @@ -4276,25 +4601,26 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, r_type = R_IA64_DIR64MSB; else r_type = R_IA64_DIR64LSB; - elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); - r = elfNN_ia64_install_value (output_bfd, hit_addr + 8, gp_val, - r_type); + elfNN_ia64_install_value (hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr + 8, gp_val, r_type); break; case R_IA64_TPREL14: case R_IA64_TPREL22: case R_IA64_TPREL64I: value -= elfNN_ia64_tprel_base (info); - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_DTPREL14: case R_IA64_DTPREL22: case R_IA64_DTPREL64I: + case R_IA64_DTPREL32LSB: + case R_IA64_DTPREL32MSB: case R_IA64_DTPREL64LSB: case R_IA64_DTPREL64MSB: value -= elfNN_ia64_dtprel_base (info); - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); break; case R_IA64_LTOFF_TPREL22: @@ -4329,15 +4655,14 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_LTOFF_DTPREL22: if (!dynamic_symbol_p) value -= elfNN_ia64_dtprel_base (info); - got_r_type = R_IA64_DTPREL64LSB; + got_r_type = R_IA64_DTPRELNNLSB; break; } dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); value = set_got_entry (input_bfd, info, dyn_i, dynindx, r_addend, value, got_r_type); value -= gp_val; - r = elfNN_ia64_install_value (output_bfd, hit_addr, value, - r_type); + r = elfNN_ia64_install_value (hit_addr, value, r_type); } break; @@ -4366,15 +4691,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, if (h) name = h->root.root.string; else - { - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL) - return FALSE; - if (*name == '\0') - name = bfd_section_name (input_bfd, input_section); - } + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, + sym_sec); if (!(*info->callbacks->warning) (info, _("unsupported reloc"), name, input_bfd, input_section, rel->r_offset)) @@ -4393,22 +4711,39 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, if (h) name = h->root.root.string; else + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, + sym_sec); + + switch (r_type) { - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL) + case R_IA64_PCREL21B: + case R_IA64_PCREL21BI: + case R_IA64_PCREL21M: + case R_IA64_PCREL21F: + if (is_elf_hash_table (info->hash)) + { + /* Relaxtion is always performed for ELF output. + Overflow failures for those relocations mean + that the section is too big to relax. */ + (*_bfd_error_handler) + (_("%B: Can't relax br (%s) to `%s' at 0x%lx in section `%A' with size 0x%lx (> 0x1000000)."), + input_bfd, input_section, howto->name, name, + rel->r_offset, input_section->size); + break; + } + default: + if (!(*info->callbacks->reloc_overflow) (info, + &h->root, + name, + howto->name, + (bfd_vma) 0, + input_bfd, + input_section, + rel->r_offset)) return FALSE; - if (*name == '\0') - name = bfd_section_name (input_bfd, input_section); + break; } - if (!(*info->callbacks->reloc_overflow) (info, name, - howto->name, - (bfd_vma) 0, - input_bfd, - input_section, - rel->r_offset)) - return FALSE; + ret_val = FALSE; } break; @@ -4448,9 +4783,8 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym) loc = plt_sec->contents + dyn_i->plt_offset; memcpy (loc, plt_min_entry, PLT_MIN_ENTRY_SIZE); - elfNN_ia64_install_value (output_bfd, loc, index, R_IA64_IMM22); - elfNN_ia64_install_value (output_bfd, loc+2, -dyn_i->plt_offset, - R_IA64_PCREL21B); + elfNN_ia64_install_value (loc, index, R_IA64_IMM22); + elfNN_ia64_install_value (loc+2, -dyn_i->plt_offset, R_IA64_PCREL21B); plt_addr = (plt_sec->output_section->vma + plt_sec->output_offset @@ -4463,14 +4797,13 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym) loc = plt_sec->contents + dyn_i->plt2_offset; memcpy (loc, plt_full_entry, PLT_FULL_ENTRY_SIZE); - elfNN_ia64_install_value (output_bfd, loc, pltoff_addr - gp_val, - R_IA64_IMM22); + elfNN_ia64_install_value (loc, pltoff_addr - gp_val, R_IA64_IMM22); /* Mark the symbol as undefined, rather than as defined in the plt section. Leave the value alone. */ /* ??? We didn't redefine it in adjust_dynamic_symbol in the - first place. But perhaps elflink.h did some for us. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + first place. But perhaps elflink.c did some for us. */ + if (!h->def_regular) sym->st_shndx = SHN_UNDEF; } @@ -4530,7 +4863,7 @@ elfNN_ia64_finish_dynamic_sections (abfd, info) sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); BFD_ASSERT (sdyn != NULL); dyncon = (ElfNN_External_Dyn *) sdyn->contents; - dynconend = (ElfNN_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + dynconend = (ElfNN_External_Dyn *) (sdyn->contents + sdyn->size); gp_val = _bfd_get_gp_value (abfd); @@ -4587,7 +4920,7 @@ elfNN_ia64_finish_dynamic_sections (abfd, info) + sgotplt->output_offset - gp_val); - elfNN_ia64_install_value (abfd, loc+1, pltres, R_IA64_GPREL22); + elfNN_ia64_install_value (loc+1, pltres, R_IA64_GPREL22); } } @@ -4654,8 +4987,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd) if ((in_flags & EF_IA_64_TRAPNIL) != (out_flags & EF_IA_64_TRAPNIL)) { (*_bfd_error_handler) - (_("%s: linking trap-on-NULL-dereference with non-trapping files"), - bfd_archive_filename (ibfd)); + (_("%B: linking trap-on-NULL-dereference with non-trapping files"), + ibfd); bfd_set_error (bfd_error_bad_value); ok = FALSE; @@ -4663,8 +4996,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd) if ((in_flags & EF_IA_64_BE) != (out_flags & EF_IA_64_BE)) { (*_bfd_error_handler) - (_("%s: linking big-endian files with little-endian files"), - bfd_archive_filename (ibfd)); + (_("%B: linking big-endian files with little-endian files"), + ibfd); bfd_set_error (bfd_error_bad_value); ok = FALSE; @@ -4672,8 +5005,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd) if ((in_flags & EF_IA_64_ABI64) != (out_flags & EF_IA_64_ABI64)) { (*_bfd_error_handler) - (_("%s: linking 64-bit files with 32-bit files"), - bfd_archive_filename (ibfd)); + (_("%B: linking 64-bit files with 32-bit files"), + ibfd); bfd_set_error (bfd_error_bad_value); ok = FALSE; @@ -4681,8 +5014,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd) if ((in_flags & EF_IA_64_CONS_GP) != (out_flags & EF_IA_64_CONS_GP)) { (*_bfd_error_handler) - (_("%s: linking constant-gp files with non-constant-gp files"), - bfd_archive_filename (ibfd)); + (_("%B: linking constant-gp files with non-constant-gp files"), + ibfd); bfd_set_error (bfd_error_bad_value); ok = FALSE; @@ -4691,8 +5024,8 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd) != (out_flags & EF_IA_64_NOFUNCDESC_CONS_GP)) { (*_bfd_error_handler) - (_("%s: linking auto-pic files with non-auto-pic files"), - bfd_archive_filename (ibfd)); + (_("%B: linking auto-pic files with non-auto-pic files"), + ibfd); bfd_set_error (bfd_error_bad_value); ok = FALSE; @@ -4746,13 +5079,106 @@ elfNN_ia64_reloc_type_class (rela) } } -static struct bfd_elf_special_section const elfNN_ia64_special_sections[]= +static const struct bfd_elf_special_section 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 } + { NULL, 0, 0, 0, 0 } }; +static bfd_boolean +elfNN_ia64_object_p (bfd *abfd) +{ + asection *sec; + asection *group, *unwi, *unw; + flagword flags; + const char *name; + char *unwi_name, *unw_name; + bfd_size_type amt; + + if (abfd->flags & DYNAMIC) + return TRUE; + + /* Flags for fake group section. */ + flags = (SEC_LINKER_CREATED | SEC_GROUP | SEC_LINK_ONCE + | SEC_EXCLUDE); + + /* We add a fake section group for each .gnu.linkonce.t.* section, + which isn't in a section group, and its unwind sections. */ + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if (elf_sec_group (sec) == NULL + && ((sec->flags & (SEC_LINK_ONCE | SEC_CODE | SEC_GROUP)) + == (SEC_LINK_ONCE | SEC_CODE)) + && strncmp (sec->name, ".gnu.linkonce.t.", 16) == 0) + { + name = sec->name + 16; + + amt = strlen (name) + sizeof (".gnu.linkonce.ia64unwi."); + unwi_name = bfd_alloc (abfd, amt); + if (!unwi_name) + return FALSE; + + strcpy (stpcpy (unwi_name, ".gnu.linkonce.ia64unwi."), name); + unwi = bfd_get_section_by_name (abfd, unwi_name); + + amt = strlen (name) + sizeof (".gnu.linkonce.ia64unw."); + unw_name = bfd_alloc (abfd, amt); + if (!unw_name) + return FALSE; + + strcpy (stpcpy (unw_name, ".gnu.linkonce.ia64unw."), name); + unw = bfd_get_section_by_name (abfd, unw_name); + + /* We need to create a fake group section for it and its + unwind sections. */ + group = bfd_make_section_anyway_with_flags (abfd, name, + flags); + if (group == NULL) + return FALSE; + + /* Move the fake group section to the beginning. */ + bfd_section_list_remove (abfd, group); + bfd_section_list_prepend (abfd, group); + + elf_next_in_group (group) = sec; + + elf_group_name (sec) = name; + elf_next_in_group (sec) = sec; + elf_sec_group (sec) = group; + + if (unwi) + { + elf_group_name (unwi) = name; + elf_next_in_group (unwi) = sec; + elf_next_in_group (sec) = unwi; + elf_sec_group (unwi) = group; + } + + if (unw) + { + elf_group_name (unw) = name; + if (unwi) + { + elf_next_in_group (unw) = elf_next_in_group (unwi); + elf_next_in_group (unwi) = unw; + } + else + { + elf_next_in_group (unw) = sec; + elf_next_in_group (sec) = unw; + } + elf_sec_group (unw) = group; + } + + /* Fake SHT_GROUP section header. */ + elf_section_data (group)->this_hdr.bfd_section = group; + elf_section_data (group)->this_hdr.sh_type = SHT_GROUP; + } + } + return TRUE; +} + static bfd_boolean elfNN_ia64_hpux_vec (const bfd_target *vec) { @@ -4789,7 +5215,7 @@ static void elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym) { - elf_symbol_type *elfsym = (elf_symbol_type *) asym;; + elf_symbol_type *elfsym = (elf_symbol_type *) asym; switch (elfsym->internal_elf_sym.st_shndx) { @@ -4836,9 +5262,14 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, #define bfd_elfNN_bfd_relax_section \ elfNN_ia64_relax_section +#define elf_backend_object_p \ + elfNN_ia64_object_p + /* 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 \ @@ -4867,7 +5298,6 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, #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 @@ -4879,6 +5309,13 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, #define elf_backend_rela_normal 1 #define elf_backend_special_sections elfNN_ia64_special_sections +/* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with + SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields. + We don't want to flood users with so many error messages. We turn + off the warning for now. It will be turned on later when the Intel + compiler is fixed. */ +#define elf_backend_link_order_error_handler NULL + #include "elfNN-target.h" /* HPUX-specific vectors. */