X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-alpha.c;h=2836fd50b5852aacf3adb3f72873ef3fbef95119;hb=aa4f99bbfde8d1650d61163622544d106c7eeab0;hp=06891d3e0e5a3f4f8293b047cafe18dca7188a36;hpb=16b65e4ea2e93d5893a07ad6e05ee7131c3ae8ce;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c index 06891d3e0e..2836fd50b5 100644 --- a/bfd/elf64-alpha.c +++ b/bfd/elf64-alpha.c @@ -74,6 +74,8 @@ static boolean elf64_alpha_object_p PARAMS((bfd *)); static boolean elf64_alpha_section_from_shdr PARAMS((bfd *, Elf64_Internal_Shdr *, char *)); +static boolean elf64_alpha_section_flags + PARAMS((flagword *, Elf64_Internal_Shdr *)); static boolean elf64_alpha_fake_sections PARAMS((bfd *, Elf64_Internal_Shdr *, asection *)); static boolean elf64_alpha_create_got_section @@ -133,6 +135,8 @@ static boolean elf64_alpha_merge_ind_symbols PARAMS((struct alpha_elf_link_hash_entry *, PTR)); static Elf_Internal_Rela * elf64_alpha_find_reloc_at_ofs PARAMS ((Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_vma, int)); +static enum elf_reloc_type_class elf64_alpha_reloc_type_class + PARAMS ((int)); struct alpha_elf_link_hash_entry { @@ -159,7 +163,7 @@ struct alpha_elf_link_hash_entry bfd *gotobj; /* the addend in effect for this entry. */ - bfd_vma addend; + bfd_signed_vma addend; /* the .got offset for this entry. */ int got_offset; @@ -182,7 +186,10 @@ struct alpha_elf_link_hash_entry asection *srel; /* what kind of relocation? */ - unsigned long rtype; + unsigned int rtype; + + /* is this against read-only section? */ + unsigned int reltext : 1; /* how many did we find? */ unsigned long count; @@ -394,6 +401,9 @@ elf64_alpha_object_p (abfd) from smaller values. Start with zero, widen, *then* decrement. */ #define MINUS_ONE (((bfd_vma)0) - 1) +#define SKIP_HOWTO(N) \ + HOWTO(N, 0, 0, 0, 0, 0, 0, elf64_alpha_reloc_bad, 0, 0, 0, 0, 0) + static reloc_howto_type elf64_alpha_howto_table[] = { HOWTO (R_ALPHA_NONE, /* type */ @@ -460,7 +470,7 @@ static reloc_howto_type elf64_alpha_howto_table[] = /* Used for an instruction that refers to memory off the GP register. */ HOWTO (R_ALPHA_LITERAL, /* type */ 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ @@ -481,7 +491,7 @@ static reloc_howto_type elf64_alpha_howto_table[] = This does not actually do any relocation. */ HOWTO (R_ALPHA_LITUSE, /* type */ 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ @@ -541,7 +551,7 @@ static reloc_howto_type elf64_alpha_howto_table[] = /* A hint for a jump to a register. */ HOWTO (R_ALPHA_HINT, /* type */ 2, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ 14, /* bitsize */ true, /* pc_relative */ 0, /* bitpos */ @@ -598,99 +608,22 @@ static reloc_howto_type elf64_alpha_howto_table[] = MINUS_ONE, /* dst_mask */ true), /* pcrel_offset */ - /* Push a value on the reloc evaluation stack. */ - /* Not implemented -- it's dumb. */ - HOWTO (R_ALPHA_OP_PUSH, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "OP_PUSH", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ - - /* Store the value from the stack at the given address. Store it in - a bitfield of size r_size starting at bit position r_offset. */ - /* Not implemented -- it's dumb. */ - HOWTO (R_ALPHA_OP_STORE, /* type */ - 0, /* rightshift */ - 4, /* size (0 = byte, 1 = short, 2 = long) */ - 64, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "OP_STORE", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - MINUS_ONE, /* dst_mask */ - false), /* pcrel_offset */ - - /* Subtract the reloc address from the value on the top of the - relocation stack. */ - /* Not implemented -- it's dumb. */ - HOWTO (R_ALPHA_OP_PSUB, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "OP_PSUB", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ - - /* Shift the value on the top of the relocation stack right by the - given value. */ - /* Not implemented -- it's dumb. */ - HOWTO (R_ALPHA_OP_PRSHIFT, /* type */ - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "OP_PRSHIFT", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ - - /* Change the value of GP used by +r_addend until the next GPVALUE or the - end of the input bfd. */ - /* Not implemented -- it's dumb. */ - HOWTO (R_ALPHA_GPVALUE, - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "GPVALUE", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ + /* Skip 12 - 16; deprecated ECOFF relocs. */ + SKIP_HOWTO (12), + SKIP_HOWTO (13), + SKIP_HOWTO (14), + SKIP_HOWTO (15), + SKIP_HOWTO (16), /* The high 16 bits of the displacement from GP to the target. */ HOWTO (R_ALPHA_GPRELHIGH, 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ + 0, /* special_function */ "GPRELHIGH", /* name */ false, /* partial_inplace */ 0xffff, /* src_mask */ @@ -700,12 +633,12 @@ static reloc_howto_type elf64_alpha_howto_table[] = /* The low 16 bits of the displacement from GP to the target. */ HOWTO (R_ALPHA_GPRELLOW, 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ + 0, /* special_function */ "GPRELLOW", /* name */ false, /* partial_inplace */ 0xffff, /* src_mask */ @@ -713,89 +646,25 @@ static reloc_howto_type elf64_alpha_howto_table[] = false), /* pcrel_offset */ /* A 16-bit displacement from the GP to the target. */ - /* XXX: Not implemented. */ - HOWTO (R_ALPHA_IMMED_GP_16, + HOWTO (R_ALPHA_GPREL16, 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ 0, /* special_function */ - "IMMED_GP_16", /* name */ + "GPREL16", /* name */ false, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ false), /* pcrel_offset */ - /* The high bits of a 32-bit displacement from the GP to the target; the - low bits are supplied in the subsequent R_ALPHA_IMMED_LO32 relocs. */ - /* XXX: Not implemented. */ - HOWTO (R_ALPHA_IMMED_GP_HI32, - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "IMMED_GP_HI32", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ - - /* The high bits of a 32-bit displacement to the starting address of the - current section (the relocation target is ignored); the low bits are - supplied in the subsequent R_ALPHA_IMMED_LO32 relocs. */ - /* XXX: Not implemented. */ - HOWTO (R_ALPHA_IMMED_SCN_HI32, - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "IMMED_SCN_HI32", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ - - /* The high bits of a 32-bit displacement from the previous br, bsr, jsr - or jmp insn (as tagged by a BRADDR or HINT reloc) to the target; the - low bits are supplied by subsequent R_ALPHA_IMMED_LO32 relocs. */ - /* XXX: Not implemented. */ - HOWTO (R_ALPHA_IMMED_BR_HI32, - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "IMMED_BR_HI32", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ - - /* The low 16 bits of a displacement calculated in a previous HI32 reloc. */ - /* XXX: Not implemented. */ - HOWTO (R_ALPHA_IMMED_LO32, - 0, /* rightshift */ - 0, /* size (0 = byte, 1 = short, 2 = long) */ - 0, /* bitsize */ - false, /* pc_relative */ - 0, /* bitpos */ - complain_overflow_dont, /* complain_on_overflow */ - elf64_alpha_reloc_bad, /* special_function */ - "IMMED_LO32", /* name */ - false, /* partial_inplace */ - 0, /* src_mask */ - 0, /* dst_mask */ - false), /* pcrel_offset */ + /* Skip 20 - 23; deprecated ECOFF relocs. */ + SKIP_HOWTO (20), + SKIP_HOWTO (21), + SKIP_HOWTO (22), + SKIP_HOWTO (23), /* Misc ELF relocations. */ @@ -998,30 +867,22 @@ struct elf_reloc_map static const struct elf_reloc_map elf64_alpha_reloc_map[] = { - {BFD_RELOC_NONE, R_ALPHA_NONE}, - {BFD_RELOC_32, R_ALPHA_REFLONG}, - {BFD_RELOC_64, R_ALPHA_REFQUAD}, - {BFD_RELOC_CTOR, R_ALPHA_REFQUAD}, - {BFD_RELOC_GPREL32, R_ALPHA_GPREL32}, - {BFD_RELOC_ALPHA_ELF_LITERAL, R_ALPHA_LITERAL}, - {BFD_RELOC_ALPHA_LITUSE, R_ALPHA_LITUSE}, - {BFD_RELOC_ALPHA_GPDISP, R_ALPHA_GPDISP}, - {BFD_RELOC_23_PCREL_S2, R_ALPHA_BRADDR}, - {BFD_RELOC_ALPHA_HINT, R_ALPHA_HINT}, - {BFD_RELOC_16_PCREL, R_ALPHA_SREL16}, - {BFD_RELOC_32_PCREL, R_ALPHA_SREL32}, - {BFD_RELOC_64_PCREL, R_ALPHA_SREL64}, - -/* The BFD_RELOC_ALPHA_USER_* relocations are used by the assembler to process - the explicit !!sequence relocations, and are mapped into the normal - relocations at the end of processing. */ - {BFD_RELOC_ALPHA_USER_LITERAL, R_ALPHA_LITERAL}, - {BFD_RELOC_ALPHA_USER_LITUSE_BASE, R_ALPHA_LITUSE}, - {BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF, R_ALPHA_LITUSE}, - {BFD_RELOC_ALPHA_USER_LITUSE_JSR, R_ALPHA_LITUSE}, - {BFD_RELOC_ALPHA_USER_GPDISP, R_ALPHA_GPDISP}, - {BFD_RELOC_ALPHA_USER_GPRELHIGH, R_ALPHA_GPRELHIGH}, - {BFD_RELOC_ALPHA_USER_GPRELLOW, R_ALPHA_GPRELLOW}, + {BFD_RELOC_NONE, R_ALPHA_NONE}, + {BFD_RELOC_32, R_ALPHA_REFLONG}, + {BFD_RELOC_64, R_ALPHA_REFQUAD}, + {BFD_RELOC_CTOR, R_ALPHA_REFQUAD}, + {BFD_RELOC_GPREL32, R_ALPHA_GPREL32}, + {BFD_RELOC_ALPHA_ELF_LITERAL, R_ALPHA_LITERAL}, + {BFD_RELOC_ALPHA_LITUSE, R_ALPHA_LITUSE}, + {BFD_RELOC_ALPHA_GPDISP, R_ALPHA_GPDISP}, + {BFD_RELOC_23_PCREL_S2, R_ALPHA_BRADDR}, + {BFD_RELOC_ALPHA_HINT, R_ALPHA_HINT}, + {BFD_RELOC_16_PCREL, R_ALPHA_SREL16}, + {BFD_RELOC_32_PCREL, R_ALPHA_SREL32}, + {BFD_RELOC_64_PCREL, R_ALPHA_SREL64}, + {BFD_RELOC_ALPHA_GPREL_HI16, R_ALPHA_GPRELHIGH}, + {BFD_RELOC_ALPHA_GPREL_LO16, R_ALPHA_GPRELLOW}, + {BFD_RELOC_GPREL16, R_ALPHA_GPREL16}, }; /* Given a BFD reloc type, return a HOWTO structure. */ @@ -1119,7 +980,8 @@ elf64_alpha_find_reloc_at_ofs (rel, relend, offset, type) { while (rel < relend) { - if (rel->r_offset == offset && ELF64_R_TYPE (rel->r_info) == type) + if (rel->r_offset == offset + && ELF64_R_TYPE (rel->r_info) == (unsigned int) type) return rel; ++rel; } @@ -1199,7 +1061,7 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend) register from the literal insn. Leave the offset alone. */ insn = (insn & 0xffe0ffff) | (lit_insn & 0x001f0000); urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), - R_ALPHA_GPRELLOW); + R_ALPHA_GPREL16); urel->r_addend = irel->r_addend; info->changed_relocs = true; @@ -1289,14 +1151,36 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend) else all_optimized = false; - /* ??? If target gp == current gp we can eliminate the gp reload. - This does depend on every place a gp could be reloaded will - be, which currently happens for all code produced by gcc, but - not necessarily by hand-coded assembly, or if sibling calls - are enabled in gcc. - - Perhaps conditionalize this on a flag being set in the target - object file's header, and have gcc set it? */ + /* Even if the target is not in range for a direct branch, + if we share a GP, we can eliminate the gp reload. */ + if (optdest) + { + Elf_Internal_Rela *gpdisp + = (elf64_alpha_find_reloc_at_ofs + (irel, irelend, urel->r_offset + 4, R_ALPHA_GPDISP)); + if (gpdisp) + { + bfd_byte *p_ldah = info->contents + gpdisp->r_offset; + bfd_byte *p_lda = p_ldah + gpdisp->r_addend; + unsigned int ldah = bfd_get_32 (info->abfd, p_ldah); + unsigned int lda = bfd_get_32 (info->abfd, p_lda); + + /* Verify that the instruction is "ldah $29,0($26)". + Consider a function that ends in a noreturn call, + and that the next function begins with an ldgp, + and that by accident there is no padding between. + In that case the insn would use $27 as the base. */ + if (ldah == 0x27ba0000 && lda == 0x23bd0000) + { + bfd_put_32 (info->abfd, INSN_UNOP, p_ldah); + bfd_put_32 (info->abfd, INSN_UNOP, p_lda); + + gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE); + info->changed_contents = true; + info->changed_relocs = true; + } + } + } } break; } @@ -1436,7 +1320,7 @@ elf64_alpha_relax_without_lituse (info, symval, irel) bfd_put_32 (info->abfd, insn, info->contents + irel->r_offset); info->changed_contents = true; - irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), R_ALPHA_GPRELLOW); + irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), R_ALPHA_GPREL16); info->changed_relocs = true; /* Reduce the use count on this got entry by one, possibly @@ -1615,7 +1499,6 @@ elf64_alpha_relax_section (abfd, sec, link_info, again) continue; info.h = h; - info.gotent = gotent; info.tsec = h->root.root.u.def.section; info.other = h->root.other; gotent = h->got_entries; @@ -1741,13 +1624,6 @@ elf64_alpha_section_from_shdr (abfd, hdr, name) if (strcmp (name, ".mdebug") != 0) return false; break; -#ifdef ERIC_neverdef - case SHT_ALPHA_REGINFO: - if (strcmp (name, ".reginfo") != 0 - || hdr->sh_size != sizeof (Elf64_External_RegInfo)) - return false; - break; -#endif default: return false; } @@ -1764,22 +1640,18 @@ elf64_alpha_section_from_shdr (abfd, hdr, name) return false; } -#ifdef ERIC_neverdef - /* For a .reginfo section, set the gp value in the tdata information - from the contents of this section. We need the gp value while - processing relocs, so we just get it now. */ - if (hdr->sh_type == SHT_ALPHA_REGINFO) - { - Elf64_External_RegInfo ext; - Elf64_RegInfo s; + return true; +} - if (! bfd_get_section_contents (abfd, newsect, (PTR) &ext, - (file_ptr) 0, sizeof ext)) - return false; - bfd_alpha_elf64_swap_reginfo_in (abfd, &ext, &s); - elf_gp (abfd) = s.ri_gp_value; - } -#endif +/* Convert Alpha specific section flags to bfd internal section flags. */ + +static boolean +elf64_alpha_section_flags (flags, hdr) + flagword *flags; + Elf64_Internal_Shdr *hdr; +{ + if (hdr->sh_flags & SHF_ALPHA_GPREL) + *flags |= SEC_SMALL_DATA; return true; } @@ -1807,31 +1679,8 @@ elf64_alpha_fake_sections (abfd, hdr, sec) else hdr->sh_entsize = 1; } -#ifdef ERIC_neverdef - else if (strcmp (name, ".reginfo") == 0) - { - hdr->sh_type = SHT_ALPHA_REGINFO; - /* In a shared object on Irix 5.3, the .reginfo section has an - entsize of 0x18. FIXME: Does this matter? */ - if ((abfd->flags & DYNAMIC) != 0) - hdr->sh_entsize = sizeof (Elf64_External_RegInfo); - else - hdr->sh_entsize = 1; - - /* Force the section size to the correct value, even if the - linker thinks it is larger. The link routine below will only - write out this much data for .reginfo. */ - hdr->sh_size = sec->_raw_size = sizeof (Elf64_External_RegInfo); - } - else if (strcmp (name, ".hash") == 0 - || strcmp (name, ".dynamic") == 0 - || strcmp (name, ".dynstr") == 0) - { - hdr->sh_entsize = 0; - hdr->sh_info = SIZEOF_ALPHA_DYNSYM_SECNAMES; - } -#endif - else if (strcmp (name, ".sdata") == 0 + else if ((sec->flags & SEC_SMALL_DATA) + || strcmp (name, ".sdata") == 0 || strcmp (name, ".sbss") == 0 || strcmp (name, ".lit4") == 0 || strcmp (name, ".lit8") == 0) @@ -1855,7 +1704,7 @@ elf64_alpha_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) { if (sym->st_shndx == SHN_COMMON && !info->relocateable - && sym->st_size <= bfd_get_gp_size (abfd)) + && sym->st_size <= elf_gp_size (abfd)) { /* Common symbols less than or equal to -G nn bytes are automatically put into .sbss. */ @@ -2335,9 +2184,6 @@ elf64_alpha_output_extsym (h, data) else h->esym.asym.value = 0; } -#if 0 /* FIXME? */ - h->esym.ifd = 0; -#endif } if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap, @@ -2534,6 +2380,7 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) /* FALLTHRU */ case R_ALPHA_GPDISP: + case R_ALPHA_GPREL16: case R_ALPHA_GPREL32: case R_ALPHA_GPRELHIGH: case R_ALPHA_GPRELLOW: @@ -2589,8 +2436,10 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) sreloc = bfd_make_section (dynobj, rel_sec_name); if (sreloc == NULL || !bfd_set_section_flags (dynobj, sreloc, - ((sec->flags & (SEC_ALLOC - | SEC_LOAD)) + (((sec->flags + & SEC_ALLOC) + ? (SEC_ALLOC + | SEC_LOAD) : 0) | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED @@ -2625,6 +2474,7 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) rent->srel = sreloc; rent->rtype = r_type; rent->count = 1; + rent->reltext = (sec->flags & SEC_READONLY) != 0; rent->next = h->reloc_entries; h->reloc_entries = rent; @@ -2637,6 +2487,8 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) /* If this is a shared library, and the section is to be loaded into memory, we need a RELATIVE reloc. */ sreloc->_raw_size += sizeof (Elf64_External_Rela); + if (sec->flags & SEC_READONLY) + info->flags |= DF_TEXTREL; } break; } @@ -2831,7 +2683,7 @@ elf64_alpha_can_merge_gots (a, b) Elf_Internal_Shdr *symtab_hdr = &elf_tdata (bsub)->symtab_hdr; int i, n; - n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info; + n = NUM_SHDR_ENTRIES (symtab_hdr) - symtab_hdr->sh_info; for (i = 0; i < n; ++i) { struct alpha_elf_got_entry *ae, *be; @@ -2903,7 +2755,7 @@ elf64_alpha_merge_gots (a, b) hashes = alpha_elf_sym_hashes (bsub); symtab_hdr = &elf_tdata (bsub)->symtab_hdr; - n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info; + n = NUM_SHDR_ENTRIES (symtab_hdr) - symtab_hdr->sh_info; for (i = 0; i < n; ++i) { struct alpha_elf_got_entry *ae, *be, **pbe, **start; @@ -2961,7 +2813,7 @@ elf64_alpha_merge_gots (a, b) static boolean elf64_alpha_calc_got_offsets_for_symbol (h, arg) struct alpha_elf_link_hash_entry *h; - PTR arg; + PTR arg ATTRIBUTE_UNUSED; { struct alpha_elf_got_entry *gotent; @@ -3027,10 +2879,10 @@ elf64_alpha_calc_got_offsets (info) static boolean elf64_alpha_size_got_sections (output_bfd, info) - bfd *output_bfd; + bfd *output_bfd ATTRIBUTE_UNUSED; struct bfd_link_info *info; { - bfd *i, *got_list, *cur_got_obj; + bfd *i, *got_list, *cur_got_obj = NULL; int something_changed = 0; got_list = alpha_elf_hash_table (info)->got_list; @@ -3179,6 +3031,8 @@ elf64_alpha_calc_dynrel_sizes (h, info) { relent->srel->_raw_size += sizeof (Elf64_External_Rela) * relent->count; + if (relent->reltext) + info->flags |= DT_TEXTREL; } dynobj = elf_hash_table(info)->dynobj; @@ -3207,12 +3061,11 @@ elf64_alpha_calc_dynrel_sizes (h, info) static boolean elf64_alpha_size_dynamic_sections (output_bfd, info) - bfd *output_bfd; + bfd *output_bfd ATTRIBUTE_UNUSED; struct bfd_link_info *info; { bfd *dynobj; asection *s; - boolean reltext; boolean relplt; dynobj = elf_hash_table(info)->dynobj; @@ -3261,7 +3114,6 @@ elf64_alpha_size_dynamic_sections (output_bfd, info) /* The check_relocs and adjust_dynamic_symbol entry points have determined the sizes of the various dynamic sections. Allocate memory for them. */ - reltext = false; relplt = false; for (s = dynobj->sections; s != NULL; s = s->next) { @@ -3291,19 +3143,6 @@ elf64_alpha_size_dynamic_sections (output_bfd, info) if (!strip) { - const char *outname; - asection *target; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL entry. */ - outname = bfd_get_section_name (output_bfd, - s->output_section); - target = bfd_get_section_by_name (output_bfd, outname + 5); - if (target != NULL - && (target->flags & SEC_READONLY) != 0 - && (target->flags & SEC_ALLOC) != 0) - reltext = true; - if (strcmp(name, ".rela.plt") == 0) relplt = true; @@ -3359,11 +3198,10 @@ elf64_alpha_size_dynamic_sections (output_bfd, info) sizeof (Elf64_External_Rela))) return false; - if (reltext) + if (info->flags & DF_TEXTREL) { if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0)) return false; - info->flags |= DF_TEXTREL; } } @@ -3390,6 +3228,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, asection *sec, *sgot, *srel, *srelgot; bfd *dynobj, *gotobj; bfd_vma gp; + boolean ret_val = true; srelgot = srel = NULL; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; @@ -3426,7 +3265,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, struct alpha_elf_link_hash_entry *h; Elf_Internal_Sym *sym; bfd_vma relocation; - bfd_vma addend; + bfd_signed_vma addend; bfd_reloc_status_type r; r_type = ELF64_R_TYPE(rel->r_info); @@ -3491,33 +3330,8 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, { sec = h->root.root.u.def.section; -#if rth_notdef - if ((r_type == R_ALPHA_LITERAL - && elf_hash_table(info)->dynamic_sections_created - && (!info->shared - || !info->symbolic - || !(h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR))) - || (info->shared - && (!info->symbolic - || !(h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR)) - && (input_section->flags & SEC_ALLOC) - && (r_type == R_ALPHA_REFLONG - || r_type == R_ALPHA_REFQUAD - || r_type == R_ALPHA_LITERAL))) - { - /* In these cases, we don't need the relocation value. - We check specially because in some obscure cases - sec->output_section will be NULL. */ - relocation = 0; - } -#else - /* FIXME: Are not these obscure cases simply bugs? Let's - get something working and come back to this. */ if (sec->output_section == NULL) relocation = 0; -#endif /* rth_notdef */ else { relocation = (h->root.root.u.def.value @@ -3538,7 +3352,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, input_section, rel->r_offset, (!info->shared || info->no_undefined || ELF_ST_VISIBILITY (h->root.other))))) - return false; + ret_val = false; relocation = 0; } } @@ -3564,13 +3378,6 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, } break; - case R_ALPHA_OP_PUSH: - case R_ALPHA_OP_STORE: - case R_ALPHA_OP_PSUB: - case R_ALPHA_OP_PRSHIFT: - /* We hate these silly beasts. */ - abort (); - case R_ALPHA_LITERAL: { struct alpha_elf_got_entry *gotent; @@ -3617,7 +3424,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, + sgot->output_offset + gotent->got_offset); outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); - outrel.r_addend = 0; + outrel.r_addend = relocation+addend; bfd_elf64_swap_reloca_out (output_bfd, &outrel, ((Elf64_External_Rela *) @@ -3641,13 +3448,28 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, /* overflow handled by _bfd_final_link_relocate */ goto default_reloc; + case R_ALPHA_GPREL16: case R_ALPHA_GPREL32: case R_ALPHA_GPRELLOW: + if (h && alpha_elf_dynamic_symbol_p (&h->root, info)) + { + (*_bfd_error_handler) + (_("%s: gp-relative relocation against dynamic symbol %s"), + bfd_get_filename (input_bfd), h->root.root.root.string); + ret_val = false; + } BFD_ASSERT(gp != 0); relocation -= gp; goto default_reloc; case R_ALPHA_GPRELHIGH: + if (h && alpha_elf_dynamic_symbol_p (&h->root, info)) + { + (*_bfd_error_handler) + (_("%s: gp-relative relocation against dynamic symbol %s"), + bfd_get_filename (input_bfd), h->root.root.root.string); + ret_val = false; + } BFD_ASSERT(gp != 0); relocation -= gp; relocation += addend; @@ -3656,8 +3478,17 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, + ((relocation >> 15) & 1)); goto default_reloc; - case R_ALPHA_BRADDR: case R_ALPHA_HINT: + /* A call to a dynamic symbol is definitely out of range of + the 16-bit displacement. Don't bother writing anything. */ + if (h && alpha_elf_dynamic_symbol_p (&h->root, info)) + { + r = bfd_reloc_ok; + break; + } + /* FALLTHRU */ + + case R_ALPHA_BRADDR: /* The regular PC-relative stuff measures from the start of the instruction rather than the end. */ addend -= 4; @@ -3682,7 +3513,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, else if (info->shared && (input_section->flags & SEC_ALLOC)) { outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); - outrel.r_addend = 0; + outrel.r_addend = relocation + addend; } else goto default_reloc; @@ -3764,7 +3595,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, 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; @@ -3774,7 +3605,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, } } - return true; + return ret_val; } /* Finish up dynamic symbol handling. We set the contents of various @@ -3875,7 +3706,7 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym) + sgot->output_offset + gotent->got_offset); outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); - outrel.r_addend = 0; + outrel.r_addend = plt_addr; bfd_elf64_swap_reloca_out (output_bfd, &outrel, ((Elf64_External_Rela *) @@ -4020,9 +3851,9 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info) return true; } -/* We need to use a special link routine to handle the .reginfo and - the .mdebug sections. We need to merge all instances of these - sections together, not write them all out sequentially. */ +/* We need to use a special link routine to handle the .mdebug section. + We need to merge all instances of these sections together, not write + them all out sequentially. */ static boolean elf64_alpha_final_link (abfd, info) @@ -4031,96 +3862,17 @@ elf64_alpha_final_link (abfd, info) { asection *o; struct bfd_link_order *p; - asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec; + asection *mdebug_sec; struct ecoff_debug_info debug; const struct ecoff_debug_swap *swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; HDRR *symhdr = &debug.symbolic_header; PTR mdebug_handle = NULL; -#if 0 - if (++ngots == 2) - { - (*info->callbacks->warning) - (info, _("using multiple gp values"), (char *) NULL, - output_bfd, (asection *) NULL, (bfd_vma) 0); - } -#endif - - /* Go through the sections and collect the .reginfo and .mdebug - information. */ - reginfo_sec = NULL; + /* Go through the sections and collect the mdebug information. */ mdebug_sec = NULL; - gptab_data_sec = NULL; - gptab_bss_sec = NULL; for (o = abfd->sections; o != (asection *) NULL; o = o->next) { -#ifdef ERIC_neverdef - if (strcmp (o->name, ".reginfo") == 0) - { - memset (®info, 0, sizeof reginfo); - - /* We have found the .reginfo section in the output file. - Look through all the link_orders comprising it and merge - the information together. */ - for (p = o->link_order_head; - p != (struct bfd_link_order *) NULL; - p = p->next) - { - asection *input_section; - bfd *input_bfd; - Elf64_External_RegInfo ext; - Elf64_RegInfo sub; - - if (p->type != bfd_indirect_link_order) - { - if (p->type == bfd_fill_link_order) - continue; - abort (); - } - - input_section = p->u.indirect.section; - input_bfd = input_section->owner; - - /* The linker emulation code has probably clobbered the - size to be zero bytes. */ - if (input_section->_raw_size == 0) - input_section->_raw_size = sizeof (Elf64_External_RegInfo); - - if (! bfd_get_section_contents (input_bfd, input_section, - (PTR) &ext, - (file_ptr) 0, - sizeof ext)) - return false; - - bfd_alpha_elf64_swap_reginfo_in (input_bfd, &ext, &sub); - - reginfo.ri_gprmask |= sub.ri_gprmask; - reginfo.ri_cprmask[0] |= sub.ri_cprmask[0]; - reginfo.ri_cprmask[1] |= sub.ri_cprmask[1]; - reginfo.ri_cprmask[2] |= sub.ri_cprmask[2]; - reginfo.ri_cprmask[3] |= sub.ri_cprmask[3]; - - /* ri_gp_value is set by the function - alpha_elf_section_processing when the section is - finally written out. */ - - /* Hack: reset the SEC_HAS_CONTENTS flag so that - elf_link_input_bfd ignores this section. */ - input_section->flags &=~ SEC_HAS_CONTENTS; - } - - /* Force the section size to the value we want. */ - o->_raw_size = sizeof (Elf64_External_RegInfo); - - /* Skip this section later on (I don't think this currently - matters, but someday it might). */ - o->link_order_head = (struct bfd_link_order *) NULL; - - reginfo_sec = o; - } -#endif - if (strcmp (o->name, ".mdebug") == 0) { struct extsym_info einfo; @@ -4166,7 +3918,7 @@ elf64_alpha_final_link (abfd, info) { asection *s; EXTR esym; - bfd_vma last; + bfd_vma last = 0; unsigned int i; static const char * const name[] = { @@ -4307,31 +4059,6 @@ elf64_alpha_final_link (abfd, info) input_section->flags &=~ SEC_HAS_CONTENTS; } -#ifdef ERIC_neverdef - if (info->shared) - { - /* Create .rtproc section. */ - rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc"); - if (rtproc_sec == NULL) - { - flagword flags = (SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY); - - rtproc_sec = bfd_make_section (abfd, ".rtproc"); - if (rtproc_sec == NULL - || ! bfd_set_section_flags (abfd, rtproc_sec, flags) - || ! bfd_set_section_alignment (abfd, rtproc_sec, 12)) - return false; - } - - if (! alpha_elf_create_procedure_table (mdebug_handle, abfd, - info, rtproc_sec, &debug)) - return false; - } -#endif - /* Build the external symbol information. */ einfo.abfd = abfd; einfo.info = info; @@ -4353,229 +4080,6 @@ elf64_alpha_final_link (abfd, info) mdebug_sec = o; } - -#ifdef ERIC_neverdef - if (strncmp (o->name, ".gptab.", sizeof ".gptab." - 1) == 0) - { - const char *subname; - unsigned int c; - Elf64_gptab *tab; - Elf64_External_gptab *ext_tab; - unsigned int i; - - /* The .gptab.sdata and .gptab.sbss sections hold - information describing how the small data area would - change depending upon the -G switch. These sections - not used in executables files. */ - if (! info->relocateable) - { - asection **secpp; - - for (p = o->link_order_head; - p != (struct bfd_link_order *) NULL; - p = p->next) - { - asection *input_section; - - if (p->type != bfd_indirect_link_order) - { - if (p->type == bfd_fill_link_order) - continue; - abort (); - } - - input_section = p->u.indirect.section; - - /* Hack: reset the SEC_HAS_CONTENTS flag so that - elf_link_input_bfd ignores this section. */ - input_section->flags &=~ SEC_HAS_CONTENTS; - } - - /* Skip this section later on (I don't think this - currently matters, but someday it might). */ - o->link_order_head = (struct bfd_link_order *) NULL; - - /* Really remove the section. */ - for (secpp = &abfd->sections; - *secpp != o; - secpp = &(*secpp)->next) - ; - *secpp = (*secpp)->next; - --abfd->section_count; - - continue; - } - - /* There is one gptab for initialized data, and one for - uninitialized data. */ - if (strcmp (o->name, ".gptab.sdata") == 0) - gptab_data_sec = o; - else if (strcmp (o->name, ".gptab.sbss") == 0) - gptab_bss_sec = o; - else - { - (*_bfd_error_handler) - (_("%s: illegal section name `%s'"), - bfd_get_filename (abfd), o->name); - bfd_set_error (bfd_error_nonrepresentable_section); - return false; - } - - /* The linker script always combines .gptab.data and - .gptab.sdata into .gptab.sdata, and likewise for - .gptab.bss and .gptab.sbss. It is possible that there is - no .sdata or .sbss section in the output file, in which - case we must change the name of the output section. */ - subname = o->name + sizeof ".gptab" - 1; - if (bfd_get_section_by_name (abfd, subname) == NULL) - { - if (o == gptab_data_sec) - o->name = ".gptab.data"; - else - o->name = ".gptab.bss"; - subname = o->name + sizeof ".gptab" - 1; - BFD_ASSERT (bfd_get_section_by_name (abfd, subname) != NULL); - } - - /* Set up the first entry. */ - c = 1; - tab = (Elf64_gptab *) bfd_malloc (c * sizeof (Elf64_gptab)); - if (tab == NULL) - return false; - tab[0].gt_header.gt_current_g_value = elf_gp_size (abfd); - tab[0].gt_header.gt_unused = 0; - - /* Combine the input sections. */ - for (p = o->link_order_head; - p != (struct bfd_link_order *) NULL; - p = p->next) - { - asection *input_section; - bfd *input_bfd; - bfd_size_type size; - unsigned long last; - bfd_size_type gpentry; - - if (p->type != bfd_indirect_link_order) - { - if (p->type == bfd_fill_link_order) - continue; - abort (); - } - - input_section = p->u.indirect.section; - input_bfd = input_section->owner; - - /* Combine the gptab entries for this input section one - by one. We know that the input gptab entries are - sorted by ascending -G value. */ - size = bfd_section_size (input_bfd, input_section); - last = 0; - for (gpentry = sizeof (Elf64_External_gptab); - gpentry < size; - gpentry += sizeof (Elf64_External_gptab)) - { - Elf64_External_gptab ext_gptab; - Elf64_gptab int_gptab; - unsigned long val; - unsigned long add; - boolean exact; - unsigned int look; - - if (! (bfd_get_section_contents - (input_bfd, input_section, (PTR) &ext_gptab, - gpentry, sizeof (Elf64_External_gptab)))) - { - free (tab); - return false; - } - - bfd_alpha_elf64_swap_gptab_in (input_bfd, &ext_gptab, - &int_gptab); - val = int_gptab.gt_entry.gt_g_value; - add = int_gptab.gt_entry.gt_bytes - last; - - exact = false; - for (look = 1; look < c; look++) - { - if (tab[look].gt_entry.gt_g_value >= val) - tab[look].gt_entry.gt_bytes += add; - - if (tab[look].gt_entry.gt_g_value == val) - exact = true; - } - - if (! exact) - { - Elf64_gptab *new_tab; - unsigned int max; - - /* We need a new table entry. */ - new_tab = ((Elf64_gptab *) - bfd_realloc ((PTR) tab, - (c + 1) * sizeof (Elf64_gptab))); - if (new_tab == NULL) - { - free (tab); - return false; - } - tab = new_tab; - tab[c].gt_entry.gt_g_value = val; - tab[c].gt_entry.gt_bytes = add; - - /* Merge in the size for the next smallest -G - value, since that will be implied by this new - value. */ - max = 0; - for (look = 1; look < c; look++) - { - if (tab[look].gt_entry.gt_g_value < val - && (max == 0 - || (tab[look].gt_entry.gt_g_value - > tab[max].gt_entry.gt_g_value))) - max = look; - } - if (max != 0) - tab[c].gt_entry.gt_bytes += - tab[max].gt_entry.gt_bytes; - - ++c; - } - - last = int_gptab.gt_entry.gt_bytes; - } - - /* Hack: reset the SEC_HAS_CONTENTS flag so that - elf_link_input_bfd ignores this section. */ - input_section->flags &=~ SEC_HAS_CONTENTS; - } - - /* The table must be sorted by -G value. */ - if (c > 2) - qsort (tab + 1, c - 1, sizeof (tab[0]), gptab_compare); - - /* Swap out the table. */ - ext_tab = ((Elf64_External_gptab *) - bfd_alloc (abfd, c * sizeof (Elf64_External_gptab))); - if (ext_tab == NULL) - { - free (tab); - return false; - } - - for (i = 0; i < c; i++) - bfd_alpha_elf64_swap_gptab_out (abfd, tab + i, ext_tab + i); - free (tab); - - o->_raw_size = c * sizeof (Elf64_External_gptab); - o->contents = (bfd_byte *) ext_tab; - - /* Skip this section later on (I don't think this currently - matters, but someday it might). */ - o->link_order_head = (struct bfd_link_order *) NULL; - } -#endif - } /* Invoke the regular ELF backend linker to do all the work. */ @@ -4605,18 +4109,6 @@ elf64_alpha_final_link (abfd, info) } } -#ifdef ERIC_neverdef - if (reginfo_sec != (asection *) NULL) - { - Elf64_External_RegInfo ext; - - bfd_alpha_elf64_swap_reginfo_out (abfd, ®info, &ext); - if (! bfd_set_section_contents (abfd, reginfo_sec, (PTR) &ext, - (file_ptr) 0, sizeof ext)) - return false; - } -#endif - if (mdebug_sec != (asection *) NULL) { BFD_ASSERT (abfd->output_has_begun); @@ -4628,25 +4120,24 @@ elf64_alpha_final_link (abfd, info) bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info); } - if (gptab_data_sec != (asection *) NULL) - { - if (! bfd_set_section_contents (abfd, gptab_data_sec, - gptab_data_sec->contents, - (file_ptr) 0, - gptab_data_sec->_raw_size)) - return false; - } + return true; +} - if (gptab_bss_sec != (asection *) NULL) +static enum elf_reloc_type_class +elf64_alpha_reloc_type_class (type) + int type; +{ + switch (type) { - if (! bfd_set_section_contents (abfd, gptab_bss_sec, - gptab_bss_sec->contents, - (file_ptr) 0, - gptab_bss_sec->_raw_size)) - return false; + case R_ALPHA_RELATIVE: + return reloc_class_relative; + case R_ALPHA_JMP_SLOT: + return reloc_class_plt; + case R_ALPHA_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; } - - return true; } /* ECOFF swapping routines. These are used when dealing with the @@ -4745,6 +4236,8 @@ const struct elf_size_info alpha_elf_size_info = #define elf_backend_section_from_shdr \ elf64_alpha_section_from_shdr +#define elf_backend_section_flags \ + elf64_alpha_section_flags #define elf_backend_fake_sections \ elf64_alpha_fake_sections @@ -4775,6 +4268,8 @@ const struct elf_size_info alpha_elf_size_info = elf64_alpha_finish_dynamic_sections #define bfd_elf64_bfd_final_link \ elf64_alpha_final_link +#define elf_backend_reloc_type_class \ + elf64_alpha_reloc_type_class #define elf_backend_ecoff_debug_swap \ &elf64_alpha_ecoff_debug_swap