From 3765b1be13d34da8aae366959c3601a09afa193b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 30 May 2002 22:01:38 +0000 Subject: [PATCH] include/elf/ * alpha.h (R_ALPHA_TLSGD, R_ALPHA_TLSLDM, R_ALPHA_DTPMOD64, R_ALPHA_GOTDTPREL, R_ALPHA_DTPREL64, R_ALPHA_DTPRELHI, R_ALPHA_DTPRELLO, R_ALPHA_DTPREL16, R_ALPHA_GOTTPREL, R_ALPHA_TPREL64, R_ALPHA_TPRELHI, R_ALPHA_TPRELLO, R_ALPHA_TPREL16): New. bfd/ * elf64-alpha.c (ALPHA_ELF_LINK_HASH_LU_TLSGD, ALPHA_ELF_LINK_HASH_LU_TLSLDM, ALPHA_ELF_LINK_HASH_LU_FUNC): New. (ALPHA_ELF_GOT_ENTRY_RELOCS_DONE): Remove. (ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED): Remove. (struct alpha_elf_got_entry): Add reloc_type, reloc_done, reloc_xlated. (struct alpha_elf_obj_tdata): Rename total_got_entries and n_local_got_entries to total_got_size and local_got_size. (elf64_alpha_howto, elf64_alpha_reloc_map): Update for TLS relocs. (alpha_got_entry_size): New. (elf64_alpha_relax_with_lituse): Use it. (elf64_alpha_relax_without_lituse): Likewise. (MAX_GOT_SIZE): Rename from MAX_GOT_ENTRIES. (get_got_entry): New. (elf64_alpha_check_relocs): Handle TLS relocs. Reorganize. (elf64_alpha_adjust_dynamic_symbol): Test LU_FUNC as a mask. (elf64_alpha_merge_ind_symbols): Check gotent->reloc_type. (elf64_alpha_can_merge_gots, elf64_alpha_merge_gots): Likewise. (elf64_alpha_calc_got_offsets_for_symbol): Use alpha_got_entry_size. (elf64_alpha_calc_got_offsets): Likewise. (alpha_dynamic_entries_for_reloc): New. (elf64_alpha_calc_dynrel_sizes): Use it. (elf64_alpha_size_dynamic_sections): Likewise. (elf64_alpha_relocate_section): Handle TLS relocations. * reloc.c: Add Alpha TLS relocations. * bfd-in2.h, libbfd.h: Rebuild. gas/ * expr.h (operatorT): Add O_md17..O_md32. * config/tc-alpha.c (O_lituse_tlsgd, O_lituse_tlsldm, O_tlsgd, O_tlsldm, O_gotdtprel, O_dtprelhi, O_dtprello, O_dtprel, O_gottprel, O_tprelhi, O_tprello, O_tprel): New. (USER_RELOC_P, alpha_reloc_op_tag, debug_exp): Include them. (DUMMY_RELOC_LITUSE_TLSGD, DUMMY_RELOC_LITUSE_TLSLDM): New. (LITUSE_TLSGD, LITUSE_TLSLDM): New. (struct alpha_reloc_tag): Add master, saw_tlsgd, saw_tlsld, saw_lu_tlsgd, saw_lu_tlsldm. Make multi_section_p a bit field. (md_apply_fix3): Handle TLS relocations. (alpha_force_relocation, alpha_fix_adjustable): Likewise. (alpha_adjust_symtab_relocs): Sort LITERAL relocs after the associated TLS reloc. Check lituse_tls relocs match up. (emit_insn): Handle TLS relocations. (ldX_op): Remove. gas/testsuite/ * gas/alpha/elf-tls-1.s, gas/alpha/elf-tls-1.d: New. * gas/alpha/elf-tls-2.s, gas/alpha/elf-tls-1.l: New. * gas/alpha/elf-tls-3.s, gas/alpha/elf-tls-1.l: New. * gas/alpha/alpha.exp: Run them. --- bfd/ChangeLog | 28 + bfd/bfd-in2.h | 15 + bfd/elf64-alpha.c | 1324 +++++++++++++++++++-------- bfd/libbfd.h | 13 + bfd/reloc.c | 29 + gas/ChangeLog | 18 + gas/config/tc-alpha.c | 223 ++++- gas/expr.h | 2 + gas/testsuite/ChangeLog | 7 + gas/testsuite/gas/alpha/alpha.exp | 3 + gas/testsuite/gas/alpha/elf-tls-1.d | 29 + gas/testsuite/gas/alpha/elf-tls-1.s | 24 + gas/testsuite/gas/alpha/elf-tls-2.l | 9 + gas/testsuite/gas/alpha/elf-tls-2.s | 32 + gas/testsuite/gas/alpha/elf-tls-3.l | 7 + gas/testsuite/gas/alpha/elf-tls-3.s | 22 + include/elf/ChangeLog | 7 + include/elf/alpha.h | 15 + 18 files changed, 1391 insertions(+), 416 deletions(-) create mode 100644 gas/testsuite/gas/alpha/elf-tls-1.d create mode 100644 gas/testsuite/gas/alpha/elf-tls-1.s create mode 100644 gas/testsuite/gas/alpha/elf-tls-2.l create mode 100644 gas/testsuite/gas/alpha/elf-tls-2.s create mode 100644 gas/testsuite/gas/alpha/elf-tls-3.l create mode 100644 gas/testsuite/gas/alpha/elf-tls-3.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c1e6aad39d..9cc751838b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,31 @@ +2002-05-30 Richard Henderson + + * elf64-alpha.c (ALPHA_ELF_LINK_HASH_LU_TLSGD, + ALPHA_ELF_LINK_HASH_LU_TLSLDM, ALPHA_ELF_LINK_HASH_LU_FUNC): New. + (ALPHA_ELF_GOT_ENTRY_RELOCS_DONE): Remove. + (ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED): Remove. + (struct alpha_elf_got_entry): Add reloc_type, reloc_done, reloc_xlated. + (struct alpha_elf_obj_tdata): Rename total_got_entries and + n_local_got_entries to total_got_size and local_got_size. + (elf64_alpha_howto, elf64_alpha_reloc_map): Update for TLS relocs. + (alpha_got_entry_size): New. + (elf64_alpha_relax_with_lituse): Use it. + (elf64_alpha_relax_without_lituse): Likewise. + (MAX_GOT_SIZE): Rename from MAX_GOT_ENTRIES. + (get_got_entry): New. + (elf64_alpha_check_relocs): Handle TLS relocs. Reorganize. + (elf64_alpha_adjust_dynamic_symbol): Test LU_FUNC as a mask. + (elf64_alpha_merge_ind_symbols): Check gotent->reloc_type. + (elf64_alpha_can_merge_gots, elf64_alpha_merge_gots): Likewise. + (elf64_alpha_calc_got_offsets_for_symbol): Use alpha_got_entry_size. + (elf64_alpha_calc_got_offsets): Likewise. + (alpha_dynamic_entries_for_reloc): New. + (elf64_alpha_calc_dynrel_sizes): Use it. + (elf64_alpha_size_dynamic_sections): Likewise. + (elf64_alpha_relocate_section): Handle TLS relocations. + * reloc.c: Add Alpha TLS relocations. + * bfd-in2.h, libbfd.h: Rebuild. + 2002-05-29 Ralf Habacker * peXXigen.c (pe_print_idata): Remove double printed diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 6d827370d7..000fee6fba 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2147,6 +2147,21 @@ share a common GP, and the target address is adjusted for STO_ALPHA_STD_GPLOAD. */ BFD_RELOC_ALPHA_BRSGP, +/* Alpha thread-local storage relocations. */ + BFD_RELOC_ALPHA_TLSGD, + BFD_RELOC_ALPHA_TLSLDM, + BFD_RELOC_ALPHA_DTPMOD64, + BFD_RELOC_ALPHA_GOTDTPREL16, + BFD_RELOC_ALPHA_DTPREL64, + BFD_RELOC_ALPHA_DTPREL_HI16, + BFD_RELOC_ALPHA_DTPREL_LO16, + BFD_RELOC_ALPHA_DTPREL16, + BFD_RELOC_ALPHA_GOTTPREL16, + BFD_RELOC_ALPHA_TPREL64, + BFD_RELOC_ALPHA_TPREL_HI16, + BFD_RELOC_ALPHA_TPREL_LO16, + BFD_RELOC_ALPHA_TPREL16, + /* Bits 27..2 of the relocation address shifted right 2 bits; simple reloc otherwise. */ BFD_RELOC_MIPS_JMP, diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c index 94b4ebe056..7099ba5d41 100644 --- a/bfd/elf64-alpha.c +++ b/bfd/elf64-alpha.c @@ -109,11 +109,16 @@ static boolean elf64_alpha_size_got_sections PARAMS ((bfd *, struct bfd_link_info *)); static boolean elf64_alpha_always_size_sections PARAMS ((bfd *, struct bfd_link_info *)); +static int alpha_dynamic_entries_for_reloc + PARAMS ((int, int, int)); static boolean elf64_alpha_calc_dynrel_sizes PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *)); static boolean elf64_alpha_add_symbol_hook PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, const char **, flagword *, asection **, bfd_vma *)); +static struct alpha_elf_got_entry *get_got_entry + PARAMS ((bfd *, struct alpha_elf_link_hash_entry *, unsigned long, + unsigned long, bfd_vma)); static boolean elf64_alpha_check_relocs PARAMS((bfd *, struct bfd_link_info *, asection *sec, const Elf_Internal_Rela *)); @@ -149,10 +154,13 @@ struct alpha_elf_link_hash_entry int flags; /* Contexts (LITUSE) in which a literal was referenced. */ -#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01 -#define ALPHA_ELF_LINK_HASH_LU_MEM 0x02 -#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04 -#define ALPHA_ELF_LINK_HASH_LU_FUNC 0x08 +#define ALPHA_ELF_LINK_HASH_LU_ADDR 0x01 +#define ALPHA_ELF_LINK_HASH_LU_MEM 0x02 +#define ALPHA_ELF_LINK_HASH_LU_BYTE 0x04 +#define ALPHA_ELF_LINK_HASH_LU_JSR 0x08 +#define ALPHA_ELF_LINK_HASH_LU_TLSGD 0x10 +#define ALPHA_ELF_LINK_HASH_LU_TLSLDM 0x20 +#define ALPHA_ELF_LINK_HASH_LU_FUNC 0x38 /* Used to implement multiple .got subsections. */ struct alpha_elf_got_entry @@ -168,13 +176,20 @@ struct alpha_elf_link_hash_entry /* the .got offset for this entry. */ int got_offset; - int flags; + /* How many references to this entry? */ + int use_count; - /* Additional flags. */ -#define ALPHA_ELF_GOT_ENTRY_RELOCS_DONE 0x10 -#define ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED 0x20 + /* The relocation type of this entry. */ + unsigned char reloc_type; - int use_count; + /* How a LITERAL is used. */ + unsigned char flags; + + /* Have we initialized the dynamic relocation for this entry? */ + unsigned char reloc_done; + + /* Have we adjusted this entry for SEC_MERGE? */ + unsigned char reloc_xlated; } *got_entries; /* used to count non-got, non-plt relocations for delayed sizing @@ -361,12 +376,12 @@ struct alpha_elf_obj_tdata /* For every got, this is the section. */ asection *got; - /* For every got, this is it's total number of *entries*. */ - int total_got_entries; + /* For every got, this is it's total number of words. */ + int total_got_size; - /* For every got, this is the sum of the number of *entries* required + /* For every got, this is the sum of the number of words required to hold all of the member object's local got. */ - int n_local_got_entries; + int local_got_size; }; #define alpha_elf_tdata(abfd) \ @@ -748,6 +763,203 @@ static reloc_howto_type elf64_alpha_howto_table[] = 0x1fffff, /* src_mask */ 0x1fffff, /* dst_mask */ true), /* pcrel_offset */ + + /* Creates a tls_index for the symbol in the got. */ + HOWTO (R_ALPHA_TLSGD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "TLSGD", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Creates a tls_index for the (current) module in the got. */ + HOWTO (R_ALPHA_TLSLDM, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "TLSLDM", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A dynamic relocation for a DTP module entry. */ + HOWTO (R_ALPHA_DTPMOD64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "DTPMOD64", /* name */ + false, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* Creates a 64-bit offset in the got for the displacement + from DTP to the target. */ + HOWTO (R_ALPHA_GOTDTPREL, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "GOTDTPREL", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A dynamic relocation for a displacement from DTP to the target. */ + HOWTO (R_ALPHA_DTPREL64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "DTPREL64", /* name */ + false, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* The high 16 bits of the displacement from DTP to the target. */ + HOWTO (R_ALPHA_DTPRELHI, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "DTPRELHI", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The low 16 bits of the displacement from DTP to the target. */ + HOWTO (R_ALPHA_DTPRELLO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "DTPRELLO", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 16-bit displacement from DTP to the target. */ + HOWTO (R_ALPHA_DTPREL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "DTPREL16", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* Creates a 64-bit offset in the got for the displacement + from TP to the target. */ + HOWTO (R_ALPHA_GOTTPREL, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "GOTTPREL", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A dynamic relocation for a displacement from TP to the target. */ + HOWTO (R_ALPHA_TPREL64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + 0, /* special_function */ + "TPREL64", /* name */ + false, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + false), /* pcrel_offset */ + + /* The high 16 bits of the displacement from TP to the target. */ + HOWTO (R_ALPHA_TPRELHI, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "TPRELHI", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* The low 16 bits of the displacement from TP to the target. */ + HOWTO (R_ALPHA_TPRELLO, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + 0, /* special_function */ + "TPRELLO", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 16-bit displacement from TP to the target. */ + HOWTO (R_ALPHA_TPREL16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + 0, /* special_function */ + "TPREL16", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ }; /* A relocation function which doesn't do anything. */ @@ -902,6 +1114,19 @@ static const struct elf_reloc_map elf64_alpha_reloc_map[] = {BFD_RELOC_ALPHA_GPREL_LO16, R_ALPHA_GPRELLOW}, {BFD_RELOC_GPREL16, R_ALPHA_GPREL16}, {BFD_RELOC_ALPHA_BRSGP, R_ALPHA_BRSGP}, + {BFD_RELOC_ALPHA_TLSGD, R_ALPHA_TLSGD}, + {BFD_RELOC_ALPHA_TLSLDM, R_ALPHA_TLSLDM}, + {BFD_RELOC_ALPHA_DTPMOD64, R_ALPHA_DTPMOD64}, + {BFD_RELOC_ALPHA_GOTDTPREL16, R_ALPHA_GOTDTPREL}, + {BFD_RELOC_ALPHA_DTPREL64, R_ALPHA_DTPREL64}, + {BFD_RELOC_ALPHA_DTPREL_HI16, R_ALPHA_DTPRELHI}, + {BFD_RELOC_ALPHA_DTPREL_LO16, R_ALPHA_DTPRELLO}, + {BFD_RELOC_ALPHA_DTPREL16, R_ALPHA_DTPREL16}, + {BFD_RELOC_ALPHA_GOTTPREL16, R_ALPHA_GOTTPREL}, + {BFD_RELOC_ALPHA_TPREL64, R_ALPHA_TPREL64}, + {BFD_RELOC_ALPHA_TPREL_HI16, R_ALPHA_TPRELHI}, + {BFD_RELOC_ALPHA_TPREL_LO16, R_ALPHA_TPRELLO}, + {BFD_RELOC_ALPHA_TPREL16, R_ALPHA_TPREL16}, }; /* Given a BFD reloc type, return a HOWTO structure. */ @@ -936,6 +1161,10 @@ elf64_alpha_info_to_howto (abfd, cache_ptr, dst) BFD_ASSERT (r_type < (unsigned int) R_ALPHA_max); cache_ptr->howto = &elf64_alpha_howto_table[r_type]; } + +/* These two relocations create a two-word entry in the got. */ +#define alpha_got_entry_size(r_type) \ + (r_type == R_ALPHA_TLSGD || r_type == R_ALPHA_TLSLDM ? 16 : 8) /* These functions do relaxation for Alpha ELF. @@ -1213,14 +1442,17 @@ elf64_alpha_relax_with_lituse (info, symval, irel, irelend) got entry by one, possibly eliminating it. */ if (all_optimized) { - info->gotent->use_count -= 1; - alpha_elf_tdata (info->gotent->gotobj)->total_got_entries -= 1; - if (!info->h) - alpha_elf_tdata (info->gotent->gotobj)->n_local_got_entries -= 1; + if (--info->gotent->use_count == 0) + { + int sz = alpha_got_entry_size (info->gotent->reloc_type); + alpha_elf_tdata (info->gotent->gotobj)->total_got_size -= sz; + if (!info->h) + alpha_elf_tdata (info->gotent->gotobj)->local_got_size -= sz; + } /* If the literal instruction is no longer needed (it may have been - reused. We can eliminate it. - ??? For now, I don't want to deal with compacting the section, + reused. We can eliminate it. */ + /* ??? For now, I don't want to deal with compacting the section, so just nop it out. */ if (!lit_reused) { @@ -1349,10 +1581,13 @@ elf64_alpha_relax_without_lituse (info, symval, irel) /* Reduce the use count on this got entry by one, possibly eliminating it. */ - info->gotent->use_count -= 1; - alpha_elf_tdata (info->gotent->gotobj)->total_got_entries -= 1; - if (!info->h) - alpha_elf_tdata (info->gotent->gotobj)->n_local_got_entries -= 1; + if (--info->gotent->use_count == 0) + { + int sz = alpha_got_entry_size (info->gotent->reloc_type); + alpha_elf_tdata (info->gotent->gotobj)->total_got_size -= sz; + if (!info->h) + alpha_elf_tdata (info->gotent->gotobj)->local_got_size -= sz; + } /* ??? Search forward through this basic block looking for insns that use the target register. Stop after an insn modifying the @@ -1643,7 +1878,7 @@ elf64_alpha_relax_section (abfd, sec, link_info, again) #define PLT_ENTRY_WORD2 0 #define PLT_ENTRY_WORD3 0 -#define MAX_GOT_ENTRIES (64*1024 / 8) +#define MAX_GOT_SIZE (64*1024) #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so" @@ -2256,6 +2491,86 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug) struct ecoff_debug_info *debug; */ +/* Search for and possibly create a got entry. */ + +static struct alpha_elf_got_entry * +get_got_entry (abfd, h, r_type, r_symndx, r_addend) + bfd *abfd; + struct alpha_elf_link_hash_entry *h; + unsigned long r_type, r_symndx; + bfd_vma r_addend; +{ + struct alpha_elf_got_entry *gotent; + struct alpha_elf_got_entry **slot; + + if (h) + slot = &h->got_entries; + else + { + /* This is a local .got entry -- record for merge. */ + + struct alpha_elf_got_entry **local_got_entries; + + local_got_entries = alpha_elf_tdata(abfd)->local_got_entries; + if (!local_got_entries) + { + bfd_size_type size; + Elf_Internal_Shdr *symtab_hdr; + + symtab_hdr = &elf_tdata(abfd)->symtab_hdr; + size = symtab_hdr->sh_info; + size *= sizeof (struct alpha_elf_got_entry *); + + local_got_entries + = (struct alpha_elf_got_entry **) bfd_alloc (abfd, size); + if (!local_got_entries) + return NULL; + + memset (local_got_entries, 0, (size_t) size); + alpha_elf_tdata (abfd)->local_got_entries = local_got_entries; + } + + slot = &local_got_entries[r_symndx]; + } + + for (gotent = *slot; gotent ; gotent = gotent->next) + if (gotent->gotobj == abfd + && gotent->reloc_type == r_type + && gotent->addend == r_addend) + break; + + if (!gotent) + { + int entry_size; + bfd_size_type amt; + + amt = sizeof (struct alpha_elf_got_entry); + gotent = (struct alpha_elf_got_entry *) bfd_alloc (abfd, amt); + if (!gotent) + return NULL; + + gotent->gotobj = abfd; + gotent->addend = r_addend; + gotent->got_offset = -1; + gotent->use_count = 1; + gotent->reloc_type = r_type; + gotent->reloc_done = 0; + gotent->reloc_xlated = 0; + + gotent->next = *slot; + *slot = gotent; + + entry_size = alpha_got_entry_size (r_type); + alpha_elf_tdata (abfd)->total_got_size += entry_size; + if (!h) + alpha_elf_tdata(abfd)->local_got_size += entry_size; + } + else + gotent->use_count += 1; + + return gotent; +} + /* Handle dynamic relocations when doing an Alpha ELF link. */ static boolean @@ -2270,9 +2585,8 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) const char *rel_sec_name; Elf_Internal_Shdr *symtab_hdr; struct alpha_elf_link_hash_entry **sym_hashes; - struct alpha_elf_got_entry **local_got_entries; const Elf_Internal_Rela *rel, *relend; - int got_created; + boolean got_created; bfd_size_type amt; if (info->relocateable) @@ -2286,14 +2600,23 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) rel_sec_name = NULL; symtab_hdr = &elf_tdata(abfd)->symtab_hdr; sym_hashes = alpha_elf_sym_hashes(abfd); - local_got_entries = alpha_elf_tdata(abfd)->local_got_entries; - got_created = 0; + got_created = false; relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; ++rel) { + enum { + NEED_GOT = 1, + NEED_GOT_ENTRY = 2, + NEED_DYNREL = 4 + }; + unsigned long r_symndx, r_type; struct alpha_elf_link_hash_entry *h; + unsigned int gotent_flags; + boolean maybe_dynamic; + unsigned int need; + bfd_vma addend; r_symndx = ELF64_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -2308,125 +2631,40 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) h->root.elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; } + + /* We can only get preliminary data on whether a symbol is + locally or externally defined, as not all of the input files + have yet been processed. Do something with what we know, as + this may help reduce memory usage and processing time later. */ + maybe_dynamic = false; + if (h && ((info->shared + && (!info->symbolic || info->allow_shlib_undefined)) + || ! (h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) + || h->root.type == bfd_link_hash_defweak)) + maybe_dynamic = true; + + need = 0; + gotent_flags = 0; r_type = ELF64_R_TYPE (rel->r_info); + addend = rel->r_addend; switch (r_type) { case R_ALPHA_LITERAL: - { - struct alpha_elf_got_entry *gotent; - int flags = 0; - - if (h) - { - /* Search for and possibly create a got entry. */ - for (gotent = h->got_entries; gotent ; gotent = gotent->next) - if (gotent->gotobj == abfd && - gotent->addend == rel->r_addend) - break; - - if (!gotent) - { - amt = sizeof (struct alpha_elf_got_entry); - gotent = ((struct alpha_elf_got_entry *) - bfd_alloc (abfd, amt)); - if (!gotent) - return false; - - gotent->gotobj = abfd; - gotent->addend = rel->r_addend; - gotent->got_offset = -1; - gotent->flags = 0; - gotent->use_count = 1; - - gotent->next = h->got_entries; - h->got_entries = gotent; - - alpha_elf_tdata (abfd)->total_got_entries++; - } - else - gotent->use_count += 1; - } - else - { - /* This is a local .got entry -- record for merge. */ - if (!local_got_entries) - { - bfd_size_type size; - size = symtab_hdr->sh_info; - size *= sizeof (struct alpha_elf_got_entry *); - - local_got_entries = ((struct alpha_elf_got_entry **) - bfd_alloc (abfd, size)); - if (!local_got_entries) - return false; - - memset (local_got_entries, 0, (size_t) size); - alpha_elf_tdata (abfd)->local_got_entries = - local_got_entries; - } - - for (gotent = local_got_entries[ELF64_R_SYM(rel->r_info)]; - gotent != NULL && gotent->addend != rel->r_addend; - gotent = gotent->next) - continue; - if (!gotent) - { - amt = sizeof (struct alpha_elf_got_entry); - gotent = ((struct alpha_elf_got_entry *) - bfd_alloc (abfd, amt)); - if (!gotent) - return false; - - gotent->gotobj = abfd; - gotent->addend = rel->r_addend; - gotent->got_offset = -1; - gotent->flags = 0; - gotent->use_count = 1; - - gotent->next = local_got_entries[ELF64_R_SYM(rel->r_info)]; - local_got_entries[ELF64_R_SYM(rel->r_info)] = gotent; - - alpha_elf_tdata(abfd)->total_got_entries++; - alpha_elf_tdata(abfd)->n_local_got_entries++; - } - else - gotent->use_count += 1; - } - - /* Remember how this literal is used from its LITUSEs. - This will be important when it comes to decide if we can - create a .plt entry for a function symbol. */ - if (rel+1 < relend - && ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE) - { - do - { - ++rel; - if (rel->r_addend >= 1 && rel->r_addend <= 3) - flags |= 1 << rel->r_addend; - } - while (rel+1 < relend && - ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE); - } - else - { - /* No LITUSEs -- presumably the address is not being - loaded for nothing. */ - flags = ALPHA_ELF_LINK_HASH_LU_ADDR; - } - - gotent->flags |= flags; - if (h) - { - /* Make a guess as to whether a .plt entry will be needed. */ - if ((h->flags |= flags) == ALPHA_ELF_LINK_HASH_LU_FUNC) - h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; - else - h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; - } - } - /* FALLTHRU */ + need = NEED_GOT | NEED_GOT_ENTRY; + + /* Remember how this literal is used from its LITUSEs. + This will be important when it comes to decide if we can + create a .plt entry for a function symbol. */ + while (++rel < relend && ELF64_R_TYPE (rel->r_info) == R_ALPHA_LITUSE) + if (rel->r_addend >= 1 && rel->r_addend <= 5) + gotent_flags |= 1 << rel->r_addend; + --rel; + + /* No LITUSEs -- presumably the address is used somehow. */ + if (gotent_flags == 0) + gotent_flags = ALPHA_ELF_LINK_HASH_LU_ADDR; + break; case R_ALPHA_GPDISP: case R_ALPHA_GPREL16: @@ -2434,9 +2672,37 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) case R_ALPHA_GPRELHIGH: case R_ALPHA_GPRELLOW: case R_ALPHA_BRSGP: - /* We don't actually use the .got here, but the sections must - be created before the linker maps input sections to output - sections. */ + need = NEED_GOT; + break; + + case R_ALPHA_REFLONG: + case R_ALPHA_REFQUAD: + if (info->shared || maybe_dynamic) + need = NEED_DYNREL; + break; + + case R_ALPHA_TLSGD: + case R_ALPHA_TLSLDM: + case R_ALPHA_GOTDTPREL: + need = NEED_GOT | NEED_GOT_ENTRY; + break; + + case R_ALPHA_GOTTPREL: + need = NEED_GOT | NEED_GOT_ENTRY; + if (info->shared) + info->flags |= DF_STATIC_TLS; + break; + + case R_ALPHA_TPREL64: + if (info->shared || maybe_dynamic) + need = NEED_DYNREL; + if (info->shared) + info->flags |= DF_STATIC_TLS; + break; + } + + if (need & NEED_GOT) + { if (!got_created) { if (!elf64_alpha_create_got_section (abfd, info)) @@ -2450,17 +2716,36 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) got_created = 1; } - break; + } - case R_ALPHA_SREL16: - case R_ALPHA_SREL32: - case R_ALPHA_SREL64: - if (h == NULL) - break; - /* FALLTHRU */ + if (need & NEED_GOT_ENTRY) + { + struct alpha_elf_got_entry *gotent; - case R_ALPHA_REFLONG: - case R_ALPHA_REFQUAD: + gotent = get_got_entry (abfd, h, r_type, r_symndx, addend); + if (!gotent) + return false; + + if (gotent_flags) + { + gotent->flags |= gotent_flags; + if (h) + { + gotent_flags |= h->flags; + h->flags = gotent_flags; + + /* Make a guess as to whether a .plt entry is needed. */ + if ((gotent_flags & ALPHA_ELF_LINK_HASH_LU_FUNC) + && !(gotent_flags & ~ALPHA_ELF_LINK_HASH_LU_FUNC)) + h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + else + h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + } + } + + if (need & NEED_DYNREL) + { if (rel_sec_name == NULL) { rel_sec_name = (bfd_elf_string_from_elf_section @@ -2538,7 +2823,6 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs) if (sec->flags & SEC_READONLY) info->flags |= DF_TEXTREL; } - break; } } @@ -2570,7 +2854,8 @@ elf64_alpha_adjust_dynamic_symbol (info, h) && ((h->type == STT_FUNC && !(ah->flags & ALPHA_ELF_LINK_HASH_LU_ADDR)) || (h->type == STT_NOTYPE - && ah->flags == ALPHA_ELF_LINK_HASH_LU_FUNC)) + && (ah->flags & ALPHA_ELF_LINK_HASH_LU_FUNC) + && !(ah->flags & ~ALPHA_ELF_LINK_HASH_LU_FUNC))) /* Don't prevent otherwise valid programs from linking by attempting to create a new .got entry somewhere. A Correct Solution would be to add a new .got section to a new object file and let it be merged @@ -2667,8 +2952,13 @@ elf64_alpha_merge_ind_symbols (hi, dummy) { gin = gi->next; for (gs = gsh; gs ; gs = gs->next) - if (gi->gotobj == gs->gotobj && gi->addend == gs->addend) - goto got_found; + if (gi->gotobj == gs->gotobj + && gi->reloc_type == gs->reloc_type + && gi->addend == gs->addend) + { + gi->use_count += gs->use_count; + goto got_found; + } gi->next = hs->got_entries; hs->got_entries = gi; got_found:; @@ -2710,15 +3000,15 @@ static boolean elf64_alpha_can_merge_gots (a, b) bfd *a, *b; { - int total = alpha_elf_tdata (a)->total_got_entries; + int total = alpha_elf_tdata (a)->total_got_size; bfd *bsub; /* Trivial quick fallout test. */ - if (total + alpha_elf_tdata (b)->total_got_entries <= MAX_GOT_ENTRIES) + if (total + alpha_elf_tdata (b)->total_got_size <= MAX_GOT_SIZE) return true; /* By their nature, local .got entries cannot be merged. */ - if ((total += alpha_elf_tdata (b)->n_local_got_entries) > MAX_GOT_ENTRIES) + if ((total += alpha_elf_tdata (b)->local_got_size) > MAX_GOT_SIZE) return false; /* Failing the common trivial comparison, we must effectively @@ -2749,10 +3039,13 @@ elf64_alpha_can_merge_gots (a, b) continue; for (ae = h->got_entries; ae ; ae = ae->next) - if (ae->gotobj == a && ae->addend == be->addend) + if (ae->gotobj == a + && ae->reloc_type == be->reloc_type + && ae->addend == be->addend) goto global_found; - if (++total > MAX_GOT_ENTRIES) + total += alpha_got_entry_size (be->reloc_type); + if (total > MAX_GOT_SIZE) return false; global_found:; } @@ -2768,14 +3061,14 @@ static void elf64_alpha_merge_gots (a, b) bfd *a, *b; { - int total = alpha_elf_tdata (a)->total_got_entries; + int total = alpha_elf_tdata (a)->total_got_size; bfd *bsub; /* Remember local expansion. */ { - int e = alpha_elf_tdata (b)->n_local_got_entries; + int e = alpha_elf_tdata (b)->local_got_size; total += e; - alpha_elf_tdata (a)->n_local_got_entries += e; + alpha_elf_tdata (a)->local_got_size += e; } for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next) @@ -2825,7 +3118,9 @@ elf64_alpha_merge_gots (a, b) continue; for (ae = *start; ae ; ae = ae->next) - if (ae->gotobj == a && ae->addend == be->addend) + if (ae->gotobj == a + && ae->reloc_type == be->reloc_type + && ae->addend == be->addend) { ae->flags |= be->flags; ae->use_count += be->use_count; @@ -2833,7 +3128,7 @@ elf64_alpha_merge_gots (a, b) goto global_found; } be->gotobj = a; - total += 1; + total += alpha_got_entry_size (be->reloc_type); global_found:; } @@ -2841,7 +3136,7 @@ elf64_alpha_merge_gots (a, b) alpha_elf_tdata (bsub)->gotobj = a; } - alpha_elf_tdata (a)->total_got_entries = total; + alpha_elf_tdata (a)->total_got_size = total; /* Merge the two in_got chains. */ { @@ -2874,7 +3169,7 @@ elf64_alpha_calc_got_offsets_for_symbol (h, arg) = &alpha_elf_tdata (gotent->gotobj)->got->_raw_size; gotent->got_offset = *plge; - *plge += 8; + *plge += alpha_got_entry_size (gotent->reloc_type); } return true; @@ -2916,7 +3211,7 @@ elf64_alpha_calc_got_offsets (info) if (gotent->use_count > 0) { gotent->got_offset = got_offset; - got_offset += 8; + got_offset += alpha_got_entry_size (gotent->reloc_type); } } @@ -2950,13 +3245,13 @@ elf64_alpha_size_got_sections (output_bfd, info) /* We are assuming no merging has yet ocurred. */ BFD_ASSERT (this_got == i); - if (alpha_elf_tdata (this_got)->total_got_entries > MAX_GOT_ENTRIES) + if (alpha_elf_tdata (this_got)->total_got_size > MAX_GOT_SIZE) { /* Yikes! A single object file has too many entries. */ (*_bfd_error_handler) (_("%s: .got subsegment exceeds 64K (size %d)"), bfd_archive_filename (i), - alpha_elf_tdata (this_got)->total_got_entries * 8); + alpha_elf_tdata (this_got)->total_got_size); return false; } @@ -3037,6 +3332,40 @@ elf64_alpha_always_size_sections (output_bfd, info) return true; } +/* The number of dynamic relocations required by a static relocation. */ + +static int +alpha_dynamic_entries_for_reloc (r_type, dynamic, shared) + int r_type, dynamic, shared; +{ + switch (r_type) + { + /* May appear in GOT entries. */ + case R_ALPHA_TLSGD: + return (dynamic ? 2 : shared ? 1 : 0); + case R_ALPHA_TLSLDM: + return shared; + case R_ALPHA_LITERAL: + return dynamic || shared; + case R_ALPHA_GOTDTPREL: + case R_ALPHA_GOTTPREL: + return dynamic; + + /* May appear in data sections. */ + case R_ALPHA_REFLONG: + case R_ALPHA_REFQUAD: + return dynamic || shared; + case R_ALPHA_SREL64: + case R_ALPHA_TPREL64: + return dynamic; + + /* Everything else is illegal. We'll issue an error during + relocate_section. */ + default: + return 0; + } +} + /* Work out the sizes of the dynamic relocation entries. */ static boolean @@ -3044,6 +3373,11 @@ elf64_alpha_calc_dynrel_sizes (h, info) struct alpha_elf_link_hash_entry *h; struct bfd_link_info *info; { + boolean dynamic; + struct alpha_elf_reloc_entry *relent; + struct alpha_elf_got_entry *gotent; + int entries; + if (h->root.root.type == bfd_link_hash_warning) h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link; @@ -3070,41 +3404,37 @@ elf64_alpha_calc_dynrel_sizes (h, info) natural form. If this is a shared object, and it has been forced local, we'll need the same number of RELATIVE relocations. */ - if (alpha_elf_dynamic_symbol_p (&h->root, info) || info->shared) - { - struct alpha_elf_reloc_entry *relent; - bfd *dynobj; - struct alpha_elf_got_entry *gotent; - bfd_size_type count; - asection *srel; - - for (relent = h->reloc_entries; relent; relent = relent->next) - if (relent->rtype == R_ALPHA_REFLONG - || relent->rtype == R_ALPHA_REFQUAD) - { - relent->srel->_raw_size += - sizeof (Elf64_External_Rela) * relent->count; - if (relent->reltext) - info->flags |= DT_TEXTREL; - } + dynamic = alpha_elf_dynamic_symbol_p (&h->root, info); - dynobj = elf_hash_table(info)->dynobj; - count = 0; + for (relent = h->reloc_entries; relent; relent = relent->next) + { + entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic, + info->shared); + if (entries) + { + relent->srel->_raw_size += + entries * sizeof (Elf64_External_Rela) * relent->count; + if (relent->reltext) + info->flags |= DT_TEXTREL; + } + } - for (gotent = h->got_entries; gotent ; gotent = gotent->next) - count++; + entries = 0; + for (gotent = h->got_entries; gotent ; gotent = gotent->next) + entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type, + dynamic, info->shared); - /* If we are using a .plt entry, subtract one, as the first - reference uses a .rela.plt entry instead. */ - if (h->root.plt.offset != MINUS_ONE) - count--; + /* If we are using a .plt entry, subtract one, as the first + reference uses a .rela.plt entry instead. */ + if (h->root.plt.offset != MINUS_ONE) + entries--; - if (count > 0) - { - srel = bfd_get_section_by_name (dynobj, ".rela.got"); - BFD_ASSERT (srel != NULL); - srel->_raw_size += sizeof (Elf64_External_Rela) * count; - } + if (entries > 0) + { + bfd *dynobj = elf_hash_table(info)->dynobj; + asection *srel = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (srel != NULL); + srel->_raw_size += sizeof (Elf64_External_Rela) * entries; } return true; @@ -3126,6 +3456,9 @@ elf64_alpha_size_dynamic_sections (output_bfd, info) if (elf_hash_table (info)->dynamic_sections_created) { + int entries; + bfd *i; + /* Set the contents of the .interp section to the interpreter. */ if (!info->shared) { @@ -3143,23 +3476,38 @@ elf64_alpha_size_dynamic_sections (output_bfd, info) elf64_alpha_calc_dynrel_sizes, info); - /* When building shared libraries, each local .got entry needs a - RELATIVE reloc. */ - if (info->shared) + /* Shared libraries often require RELATIVE relocs, and some relocs + require attention for the main application as well. */ + + entries = 0; + for (i = alpha_elf_hash_table(info)->got_list; + i ; i = alpha_elf_tdata(i)->got_link_next) { - bfd *i; - asection *srel; - bfd_size_type count; - - srel = bfd_get_section_by_name (dynobj, ".rela.got"); - BFD_ASSERT (srel != NULL); + bfd *j; - for (i = alpha_elf_hash_table(info)->got_list, count = 0; - i != NULL; - i = alpha_elf_tdata(i)->got_link_next) - count += alpha_elf_tdata(i)->n_local_got_entries; + for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next) + { + struct alpha_elf_got_entry **local_got_entries, *gotent; + int k, n; + + local_got_entries = alpha_elf_tdata(j)->local_got_entries; + if (!local_got_entries) + continue; + + for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k) + for (gotent = local_got_entries[k]; + gotent ; gotent = gotent->next) + if (gotent->use_count > 0) + entries += (alpha_dynamic_entries_for_reloc + (gotent->reloc_type, 0, info->shared)); + } + } - srel->_raw_size += count * sizeof (Elf64_External_Rela); + if (entries > 0) + { + s = bfd_get_section_by_name (dynobj, ".rela.got"); + BFD_ASSERT (s != NULL); + s->_raw_size += sizeof (Elf64_External_Rela) * entries; } } /* else we're not dynamic and by definition we don't need such things. */ @@ -3278,60 +3626,85 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, Elf_Internal_Sym *local_syms; asection **local_sections; { - Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; - asection *sec, *sgot, *srel, *srelgot; - bfd *dynobj, *gotobj; - bfd_vma gp; + struct elf_link_tls_segment *tls_segment = NULL; + asection *sgot = NULL, *srel = NULL, *srelgot = NULL; + bfd *dynobj = NULL, *gotobj = NULL; + bfd_vma gp = 0, tp_base = 0, dtp_base = 0; boolean ret_val = true; - srelgot = srel = NULL; - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; - dynobj = elf_hash_table (info)->dynobj; - if (dynobj) + if (!info->relocateable) { - srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); - } + const char *name; - /* Find the gp value for this input bfd. */ - sgot = NULL; - gp = 0; - gotobj = alpha_elf_tdata (input_bfd)->gotobj; - if (gotobj) - { - sgot = alpha_elf_tdata (gotobj)->got; - gp = _bfd_get_gp_value (gotobj); - if (gp == 0) + dynobj = elf_hash_table (info)->dynobj; + if (dynobj) + srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); + + name = (bfd_elf_string_from_elf_section + (input_bfd, elf_elfheader(input_bfd)->e_shstrndx, + elf_section_data(input_section)->rel_hdr.sh_name)); + BFD_ASSERT(name != NULL); + srel = bfd_get_section_by_name (dynobj, name); + + /* Find the gp value for this input bfd. */ + gotobj = alpha_elf_tdata (input_bfd)->gotobj; + if (gotobj) { - gp = (sgot->output_section->vma - + sgot->output_offset - + 0x8000); - _bfd_set_gp_value (gotobj, gp); - } + sgot = alpha_elf_tdata (gotobj)->got; + gp = _bfd_get_gp_value (gotobj); + if (gp == 0) + { + gp = (sgot->output_section->vma + + sgot->output_offset + + 0x8000); + _bfd_set_gp_value (gotobj, gp); + } + } + + tls_segment = elf_hash_table (info)->tls_segment; + if (tls_segment) + { + /* This is PT_TLS segment p_vaddr. */ + dtp_base = tls_segment->start; + + /* Main program TLS (whose template starts at PT_TLS p_vaddr) + is assigned offset round(16, PT_TLS p_align). */ + tp_base = dtp_base - align_power (16, tls_segment->align); + } } rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) { - int r_type; + struct alpha_elf_link_hash_entry *h; + struct alpha_elf_got_entry *gotent; + bfd_reloc_status_type r; reloc_howto_type *howto; unsigned long r_symndx; - struct alpha_elf_link_hash_entry *h; Elf_Internal_Sym *sym; - bfd_vma relocation; + asection *sec; + bfd_vma value; bfd_vma addend; - bfd_reloc_status_type r; + boolean dynamic_symbol_p; + boolean undef_weak_ref; + unsigned long r_type; r_type = ELF64_R_TYPE(rel->r_info); - if (r_type < 0 || r_type >= (int) R_ALPHA_max) + if (r_type >= R_ALPHA_max) { + (*_bfd_error_handler) + (_("%s: unknown relocation type %d"), + bfd_archive_filename (input_bfd), (int)r_type); bfd_set_error (bfd_error_bad_value); - return false; + ret_val = false; + continue; } - howto = elf64_alpha_howto_table + r_type; + howto = elf64_alpha_howto_table + r_type; r_symndx = ELF64_R_SYM(rel->r_info); if (info->relocateable) @@ -3364,12 +3737,48 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, h = NULL; sym = NULL; sec = NULL; + undef_weak_ref = false; if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; sec = local_sections[r_symndx]; - relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); + value = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel); + + gotent = alpha_elf_tdata(input_bfd)->local_got_entries[r_symndx]; + + /* Need to adjust local GOT entries' addends for SEC_MERGE + unless it has been done already. */ + if ((sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION + && (elf_section_data (sec)->sec_info_type + == ELF_INFO_TYPE_MERGE) + && !gotent->reloc_xlated) + { + struct alpha_elf_got_entry *ent; + asection *msec; + + for (ent = gotent; ent; ent = ent->next) + { + ent->reloc_xlated = 1; + if (ent->use_count == 0) + continue; + msec = sec; + ent->addend = + _bfd_merged_section_offset (output_bfd, &msec, + elf_section_data (sec)-> + sec_info, + sym->st_value + ent->addend, + (bfd_vma) 0); + ent->addend -= sym->st_value; + ent->addend += msec->output_section->vma + + msec->output_offset + - sec->output_section->vma + - sec->output_offset; + } + } + + dynamic_symbol_p = false; } else { @@ -3379,27 +3788,32 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, || h->root.root.type == bfd_link_hash_warning) h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link; + value = 0; if (h->root.root.type == bfd_link_hash_defined || h->root.root.type == bfd_link_hash_defweak) { sec = h->root.root.u.def.section; - if (sec->output_section == NULL) - relocation = 0; - else - { - relocation = (h->root.root.u.def.value - + sec->output_section->vma - + sec->output_offset); - } + /* Detect the cases that sym_sec->output_section is + expected to be NULL -- all cases in which the symbol + is defined in another shared module. This includes + PLT relocs for which we've created a PLT entry and + other relocs for which we're prepared to create + dynamic relocations. */ + /* ??? Just accept it NULL and continue. */ + + if (sec->output_section != NULL) + value = (h->root.root.u.def.value + + sec->output_section->vma + + sec->output_offset); } else if (h->root.root.type == bfd_link_hash_undefweak) - relocation = 0; + undef_weak_ref = true; else if (info->shared && (!info->symbolic || info->allow_shlib_undefined) && !info->no_undefined && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) - relocation = 0; + ; else { if (!((*info->callbacks->undefined_symbol) @@ -3407,11 +3821,24 @@ 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))))) - ret_val = false; - relocation = 0; + return false; + ret_val = false; + continue; } + + dynamic_symbol_p = alpha_elf_dynamic_symbol_p (&h->root, info); + gotent = h->got_entries; } + addend = rel->r_addend; + value += addend; + + /* Search for the proper got entry. */ + for (; gotent ; gotent = gotent->next) + if (gotent->gotobj == gotobj + && gotent->reloc_type == r_type + && gotent->addend == addend) + break; switch (r_type) { @@ -3421,124 +3848,66 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, BFD_ASSERT(gp != 0); - relocation = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); + value = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); - p_ldah = contents + rel->r_offset - input_section->vma; + p_ldah = contents + rel->r_offset; p_lda = p_ldah + rel->r_addend; - r = elf64_alpha_do_reloc_gpdisp (input_bfd, gp - relocation, + r = elf64_alpha_do_reloc_gpdisp (input_bfd, gp - value, p_ldah, p_lda); } break; case R_ALPHA_LITERAL: - { - struct alpha_elf_got_entry *gotent; - boolean dynamic_symbol; - - BFD_ASSERT(sgot != NULL); - BFD_ASSERT(gp != 0); - - if (h != NULL) - { - gotent = h->got_entries; - dynamic_symbol = alpha_elf_dynamic_symbol_p (&h->root, info); - } - else - { - gotent = (alpha_elf_tdata(input_bfd)-> - local_got_entries[r_symndx]); - dynamic_symbol = false; - - /* Need to adjust local GOT entries' addends for SEC_MERGE - unless it has been done already. */ - if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION - && (elf_section_data (sec)->sec_info_type - == ELF_INFO_TYPE_MERGE) - && (gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED) == 0) - { - struct alpha_elf_got_entry *ent; - asection *msec; - - for (ent = gotent; ent; ent = ent->next) - { - ent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_XLATED; - if (ent->use_count == 0) - continue; - msec = sec; - ent->addend = - _bfd_merged_section_offset (output_bfd, &msec, - elf_section_data (sec)-> - sec_info, - sym->st_value - + ent->addend, - (bfd_vma) 0); - ent->addend -= sym->st_value; - ent->addend += msec->output_section->vma - + msec->output_offset - - sec->output_section->vma - - sec->output_offset; - } - } - } + BFD_ASSERT(sgot != NULL); + BFD_ASSERT(gp != 0); + BFD_ASSERT(gotent != NULL); + BFD_ASSERT(gotent->use_count >= 1); - BFD_ASSERT(gotent != NULL); + if (!gotent->reloc_done) + { + gotent->reloc_done = 1; - while (gotent->gotobj != gotobj || gotent->addend != addend) - gotent = gotent->next; + bfd_put_64 (output_bfd, value, + sgot->contents + gotent->got_offset); - BFD_ASSERT(gotent->use_count >= 1); + /* If the symbol has been forced local, output a + RELATIVE reloc, otherwise it will be handled in + finish_dynamic_symbol. */ + if (info->shared && !dynamic_symbol_p) + { + Elf_Internal_Rela outrel; - /* Initialize the .got entry's value. */ - if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE)) - { - bfd_put_64 (output_bfd, relocation + addend, - sgot->contents + gotent->got_offset); + BFD_ASSERT(srelgot != NULL); - /* If the symbol has been forced local, output a - RELATIVE reloc, otherwise it will be handled in - finish_dynamic_symbol. */ - if (info->shared && !dynamic_symbol) - { - Elf_Internal_Rela outrel; - - BFD_ASSERT(srelgot != NULL); - - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset - + gotent->got_offset); - outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); - outrel.r_addend = relocation + addend; - - bfd_elf64_swap_reloca_out (output_bfd, &outrel, - ((Elf64_External_Rela *) - srelgot->contents) - + srelgot->reloc_count++); - BFD_ASSERT (sizeof (Elf64_External_Rela) - * srelgot->reloc_count - <= srelgot->_cooked_size); - } + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + gotent->got_offset); + outrel.r_info = ELF64_R_INFO (0, R_ALPHA_RELATIVE); + outrel.r_addend = value; - gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE; - } + bfd_elf64_swap_reloca_out (output_bfd, &outrel, + ((Elf64_External_Rela *) + srelgot->contents) + + srelgot->reloc_count++); + BFD_ASSERT (sizeof (Elf64_External_Rela) + * srelgot->reloc_count + <= srelgot->_cooked_size); + } + } - /* Figure the gprel relocation. */ - addend = 0; - relocation = (sgot->output_section->vma - + sgot->output_offset - + gotent->got_offset); - relocation -= gp; - } - /* overflow handled by _bfd_final_link_relocate */ + value = (sgot->output_section->vma + + sgot->output_offset + + gotent->got_offset); + value -= gp; 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)) + if (dynamic_symbol_p) { (*_bfd_error_handler) (_("%s: gp-relative relocation against dynamic symbol %s"), @@ -3546,11 +3915,11 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, ret_val = false; } BFD_ASSERT(gp != 0); - relocation -= gp; + value -= gp; goto default_reloc; case R_ALPHA_GPRELHIGH: - if (h && alpha_elf_dynamic_symbol_p (&h->root, info)) + if (dynamic_symbol_p) { (*_bfd_error_handler) (_("%s: gp-relative relocation against dynamic symbol %s"), @@ -3558,27 +3927,34 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, ret_val = false; } BFD_ASSERT(gp != 0); - relocation -= gp; - relocation += addend; - addend = 0; - relocation = (((bfd_signed_vma) relocation >> 16) - + ((relocation >> 15) & 1)); + value -= gp; + value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1); goto default_reloc; 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)) + if (dynamic_symbol_p) { r = bfd_reloc_ok; break; } - /* FALLTHRU */ + /* The regular PC-relative stuff measures from the start of + the instruction rather than the end. */ + value -= 4; + goto default_reloc; case R_ALPHA_BRADDR: + if (dynamic_symbol_p) + { + (*_bfd_error_handler) + (_("%s: pc-relative relocation against dynamic symbol %s"), + bfd_archive_filename (input_bfd), h->root.root.root.string); + ret_val = false; + } /* The regular PC-relative stuff measures from the start of the instruction rather than the end. */ - addend -= 4; + value -= 4; goto default_reloc; case R_ALPHA_BRSGP: @@ -3588,7 +3964,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, /* The regular PC-relative stuff measures from the start of the instruction rather than the end. */ - addend -= 4; + value -= 4; /* The source and destination gp must be the same. Note that the source will always have an assigned gp, since we forced @@ -3641,41 +4017,52 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, case R_ALPHA_REFLONG: case R_ALPHA_REFQUAD: + case R_ALPHA_DTPREL64: + case R_ALPHA_TPREL64: { Elf_Internal_Rela outrel; /* Careful here to remember RELATIVE relocations for global variables for symbolic shared objects. */ - if (h && alpha_elf_dynamic_symbol_p (&h->root, info)) + if (dynamic_symbol_p) { BFD_ASSERT(h->root.dynindx != -1); - outrel.r_info = ELF64_R_INFO(h->root.dynindx, r_type); + outrel.r_info = ELF64_R_INFO (h->root.dynindx, r_type); outrel.r_addend = addend; - addend = 0, relocation = 0; + addend = 0, value = 0; + } + else if (r_type == R_ALPHA_DTPREL64) + { + BFD_ASSERT(tls_segment != NULL); + value -= dtp_base; + goto default_reloc; + } + else if (r_type == R_ALPHA_TPREL64) + { + BFD_ASSERT(tls_segment != NULL); + value -= dtp_base; + goto default_reloc; } else if (info->shared && r_symndx != 0 && (input_section->flags & SEC_ALLOC)) { - outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE); - outrel.r_addend = relocation + addend; + if (r_type == R_ALPHA_REFLONG) + { + (*_bfd_error_handler) + (_("%s: unhandled dynamic relocation against %s"), + bfd_archive_filename (input_bfd), + h->root.root.root.string); + ret_val = false; + } + outrel.r_info = ELF64_R_INFO (0, R_ALPHA_RELATIVE); + outrel.r_addend = value; } else goto default_reloc; - if (!srel) - { - const char *name; - - name = (bfd_elf_string_from_elf_section - (input_bfd, elf_elfheader(input_bfd)->e_shstrndx, - elf_section_data(input_section)->rel_hdr.sh_name)); - BFD_ASSERT(name != NULL); - - srel = bfd_get_section_by_name (dynobj, name); - BFD_ASSERT(srel != NULL); - } + BFD_ASSERT(srel != NULL); outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, input_section, @@ -3695,8 +4082,17 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, } goto default_reloc; + case R_ALPHA_SREL16: case R_ALPHA_SREL32: case R_ALPHA_SREL64: + if (dynamic_symbol_p) + { + (*_bfd_error_handler) + (_("%s: pc-relative relocation against dynamic symbol %s"), + bfd_archive_filename (input_bfd), h->root.root.root.string); + ret_val = false; + } + /* ??? .eh_frame references to discarded sections will be smashed to relocations against SHN_UNDEF. The .eh_frame format allows NULL to be encoded as 0 in any format, so this works here. */ @@ -3705,11 +4101,123 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG)); goto default_reloc; + case R_ALPHA_TLSLDM: + /* Ignore the symbol for the relocation. The result is always + the current module. */ + dynamic_symbol_p = 0; + /* FALLTHRU */ + + case R_ALPHA_TLSGD: + if (!gotent->reloc_done) + { + gotent->reloc_done = 1; + + /* Note that the module index for the main program is 1. */ + bfd_put_64 (output_bfd, !info->shared && !dynamic_symbol_p, + sgot->contents + gotent->got_offset); + + /* If the symbol has been forced local, output a + DTPMOD64 reloc, otherwise it will be handled in + finish_dynamic_symbol. */ + if (info->shared && !dynamic_symbol_p) + { + Elf_Internal_Rela outrel; + + BFD_ASSERT(srelgot != NULL); + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + gotent->got_offset); + /* ??? Proper dynindx here. */ + outrel.r_info = ELF64_R_INFO (0, R_ALPHA_DTPMOD64); + outrel.r_addend = 0; + + bfd_elf64_swap_reloca_out (output_bfd, &outrel, + ((Elf64_External_Rela *) + srelgot->contents) + + srelgot->reloc_count++); + BFD_ASSERT (sizeof (Elf64_External_Rela) + * srelgot->reloc_count + <= srelgot->_cooked_size); + } + + if (dynamic_symbol_p || r_type == R_ALPHA_TLSLDM) + value = 0; + else + { + BFD_ASSERT(tls_segment != NULL); + value -= dtp_base; + } + bfd_put_64 (output_bfd, value, + sgot->contents + gotent->got_offset + 8); + } + + value = (sgot->output_section->vma + + sgot->output_offset + + gotent->got_offset); + value -= gp; + goto default_reloc; + + case R_ALPHA_DTPRELHI: + case R_ALPHA_DTPRELLO: + case R_ALPHA_DTPREL16: + if (dynamic_symbol_p) + { + (*_bfd_error_handler) + (_("%s: dtp-relative relocation against dynamic symbol %s"), + bfd_archive_filename (input_bfd), h->root.root.root.string); + ret_val = false; + } + BFD_ASSERT(tls_segment != NULL); + value -= dtp_base; + goto default_reloc; + + case R_ALPHA_TPRELHI: + case R_ALPHA_TPRELLO: + case R_ALPHA_TPREL16: + if (dynamic_symbol_p) + { + (*_bfd_error_handler) + (_("%s: tp-relative relocation against dynamic symbol %s"), + bfd_archive_filename (input_bfd), h->root.root.root.string); + ret_val = false; + } + BFD_ASSERT(tls_segment != NULL); + value -= tp_base; + goto default_reloc; + + case R_ALPHA_GOTDTPREL: + case R_ALPHA_GOTTPREL: + BFD_ASSERT(sgot != NULL); + BFD_ASSERT(gp != 0); + BFD_ASSERT(gotent != NULL); + BFD_ASSERT(gotent->use_count >= 1); + + if (!gotent->reloc_done) + { + gotent->reloc_done = 1; + + if (dynamic_symbol_p) + value = 0; + else + { + BFD_ASSERT(tls_segment != NULL); + value -= (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base); + } + bfd_put_64 (output_bfd, value, + sgot->contents + gotent->got_offset); + } + + value = (sgot->output_section->vma + + sgot->output_offset + + gotent->got_offset); + value -= gp; + goto default_reloc; + default: default_reloc: r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, relocation, - addend); + contents, rel->r_offset, value, 0); break; } @@ -3881,20 +4389,54 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym) srel = bfd_get_section_by_name (dynobj, ".rela.got"); BFD_ASSERT (srel != NULL); - outrel.r_info = ELF64_R_INFO (h->dynindx, R_ALPHA_GLOB_DAT); for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries; gotent != NULL; gotent = gotent->next) { asection *sgot = alpha_elf_tdata (gotent->gotobj)->got; + int r_type; + outrel.r_offset = (sgot->output_section->vma + sgot->output_offset + gotent->got_offset); + + r_type = gotent->reloc_type; + switch (r_type) + { + case R_ALPHA_LITERAL: + r_type = R_ALPHA_GLOB_DAT; + break; + case R_ALPHA_TLSGD: + r_type = R_ALPHA_DTPMOD64; + break; + case R_ALPHA_GOTDTPREL: + r_type = R_ALPHA_DTPREL64; + break; + case R_ALPHA_GOTTPREL: + r_type = R_ALPHA_TPREL64; + break; + case R_ALPHA_TLSLDM: + default: + abort (); + } + + outrel.r_info = ELF64_R_INFO (h->dynindx, r_type); outrel.r_addend = gotent->addend; bfd_elf64_swap_reloca_out (output_bfd, &outrel, ((Elf64_External_Rela *)srel->contents + srel->reloc_count++)); + + if (gotent->reloc_type == R_ALPHA_TLSGD) + { + outrel.r_offset += 8; + outrel.r_info = ELF64_R_INFO (h->dynindx, R_ALPHA_DTPREL64); + + bfd_elf64_swap_reloca_out (output_bfd, &outrel, + ((Elf64_External_Rela *)srel->contents + + srel->reloc_count++)); + } + BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count <= srel->_cooked_size); } diff --git a/bfd/libbfd.h b/bfd/libbfd.h index cbb6390af1..6cba82970e 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -732,6 +732,19 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_ALPHA_GPREL_HI16", "BFD_RELOC_ALPHA_GPREL_LO16", "BFD_RELOC_ALPHA_BRSGP", + "BFD_RELOC_ALPHA_TLSGD", + "BFD_RELOC_ALPHA_TLSLDM", + "BFD_RELOC_ALPHA_DTPMOD64", + "BFD_RELOC_ALPHA_GOTDTPREL16", + "BFD_RELOC_ALPHA_DTPREL64", + "BFD_RELOC_ALPHA_DTPREL_HI16", + "BFD_RELOC_ALPHA_DTPREL_LO16", + "BFD_RELOC_ALPHA_DTPREL16", + "BFD_RELOC_ALPHA_GOTTPREL16", + "BFD_RELOC_ALPHA_TPREL64", + "BFD_RELOC_ALPHA_TPREL_HI16", + "BFD_RELOC_ALPHA_TPREL_LO16", + "BFD_RELOC_ALPHA_TPREL16", "BFD_RELOC_MIPS_JMP", "BFD_RELOC_MIPS16_JMP", "BFD_RELOC_MIPS16_GPREL", diff --git a/bfd/reloc.c b/bfd/reloc.c index 60d40aa7d2..8af90fc796 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -1962,6 +1962,35 @@ ENUMDOC share a common GP, and the target address is adjusted for STO_ALPHA_STD_GPLOAD. +ENUM + BFD_RELOC_ALPHA_TLSGD +ENUMX + BFD_RELOC_ALPHA_TLSLDM +ENUMX + BFD_RELOC_ALPHA_DTPMOD64 +ENUMX + BFD_RELOC_ALPHA_GOTDTPREL16 +ENUMX + BFD_RELOC_ALPHA_DTPREL64 +ENUMX + BFD_RELOC_ALPHA_DTPREL_HI16 +ENUMX + BFD_RELOC_ALPHA_DTPREL_LO16 +ENUMX + BFD_RELOC_ALPHA_DTPREL16 +ENUMX + BFD_RELOC_ALPHA_GOTTPREL16 +ENUMX + BFD_RELOC_ALPHA_TPREL64 +ENUMX + BFD_RELOC_ALPHA_TPREL_HI16 +ENUMX + BFD_RELOC_ALPHA_TPREL_LO16 +ENUMX + BFD_RELOC_ALPHA_TPREL16 +ENUMDOC + Alpha thread-local storage relocations. + ENUM BFD_RELOC_MIPS_JMP ENUMDOC diff --git a/gas/ChangeLog b/gas/ChangeLog index 979573b85e..84fac4576e 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,21 @@ +2002-05-30 Richard Henderson + + * expr.h (operatorT): Add O_md17..O_md32. + * config/tc-alpha.c (O_lituse_tlsgd, O_lituse_tlsldm, O_tlsgd, + O_tlsldm, O_gotdtprel, O_dtprelhi, O_dtprello, O_dtprel, O_gottprel, + O_tprelhi, O_tprello, O_tprel): New. + (USER_RELOC_P, alpha_reloc_op_tag, debug_exp): Include them. + (DUMMY_RELOC_LITUSE_TLSGD, DUMMY_RELOC_LITUSE_TLSLDM): New. + (LITUSE_TLSGD, LITUSE_TLSLDM): New. + (struct alpha_reloc_tag): Add master, saw_tlsgd, saw_tlsld, + saw_lu_tlsgd, saw_lu_tlsldm. Make multi_section_p a bit field. + (md_apply_fix3): Handle TLS relocations. + (alpha_force_relocation, alpha_fix_adjustable): Likewise. + (alpha_adjust_symtab_relocs): Sort LITERAL relocs after the + associated TLS reloc. Check lituse_tls relocs match up. + (emit_insn): Handle TLS relocations. + (ldX_op): Remove. + 2002-05-30 Thiemo Seufer * config/tc-mips.c (mips_gprel_offset): New variable. diff --git a/gas/config/tc-alpha.c b/gas/config/tc-alpha.c index 7746f99d26..1ba7aca6b0 100644 --- a/gas/config/tc-alpha.c +++ b/gas/config/tc-alpha.c @@ -106,30 +106,45 @@ struct alpha_macro { #define O_pregister O_md1 /* O_register, in parentheses */ #define O_cpregister O_md2 /* + a leading comma */ -/* Note, the alpha_reloc_op table below depends on the ordering - of O_literal .. O_gpre16. */ +/* The alpha_reloc_op table below depends on the ordering of these. */ #define O_literal O_md3 /* !literal relocation */ #define O_lituse_addr O_md4 /* !lituse_addr relocation */ #define O_lituse_base O_md5 /* !lituse_base relocation */ #define O_lituse_bytoff O_md6 /* !lituse_bytoff relocation */ #define O_lituse_jsr O_md7 /* !lituse_jsr relocation */ -#define O_gpdisp O_md8 /* !gpdisp relocation */ -#define O_gprelhigh O_md9 /* !gprelhigh relocation */ -#define O_gprellow O_md10 /* !gprellow relocation */ -#define O_gprel O_md11 /* !gprel relocation */ -#define O_samegp O_md12 /* !samegp relocation */ +#define O_lituse_tlsgd O_md8 /* !lituse_tlsgd relocation */ +#define O_lituse_tlsldm O_md9 /* !lituse_tlsldm relocation */ +#define O_gpdisp O_md10 /* !gpdisp relocation */ +#define O_gprelhigh O_md11 /* !gprelhigh relocation */ +#define O_gprellow O_md12 /* !gprellow relocation */ +#define O_gprel O_md13 /* !gprel relocation */ +#define O_samegp O_md14 /* !samegp relocation */ +#define O_tlsgd O_md15 /* !tlsgd relocation */ +#define O_tlsldm O_md16 /* !tlsldm relocation */ +#define O_gotdtprel O_md17 /* !gotdtprel relocation */ +#define O_dtprelhi O_md18 /* !dtprelhi relocation */ +#define O_dtprello O_md19 /* !dtprello relocation */ +#define O_dtprel O_md20 /* !dtprel relocation */ +#define O_gottprel O_md21 /* !gottprel relocation */ +#define O_tprelhi O_md22 /* !tprelhi relocation */ +#define O_tprello O_md23 /* !tprello relocation */ +#define O_tprel O_md24 /* !tprel relocation */ #define DUMMY_RELOC_LITUSE_ADDR (BFD_RELOC_UNUSED + 1) #define DUMMY_RELOC_LITUSE_BASE (BFD_RELOC_UNUSED + 2) #define DUMMY_RELOC_LITUSE_BYTOFF (BFD_RELOC_UNUSED + 3) #define DUMMY_RELOC_LITUSE_JSR (BFD_RELOC_UNUSED + 4) +#define DUMMY_RELOC_LITUSE_TLSGD (BFD_RELOC_UNUSED + 5) +#define DUMMY_RELOC_LITUSE_TLSLDM (BFD_RELOC_UNUSED + 6) #define LITUSE_ADDR 0 #define LITUSE_BASE 1 #define LITUSE_BYTOFF 2 #define LITUSE_JSR 3 +#define LITUSE_TLSGD 4 +#define LITUSE_TLSLDM 5 -#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_samegp) +#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_tprel) /* Macros for extracting the type and number of encoded register tokens */ @@ -496,11 +511,23 @@ static const struct alpha_reloc_op_tag { DEF(lituse_base, DUMMY_RELOC_LITUSE_BASE, 1, 1), DEF(lituse_bytoff, DUMMY_RELOC_LITUSE_BYTOFF, 1, 1), DEF(lituse_jsr, DUMMY_RELOC_LITUSE_JSR, 1, 1), + DEF(lituse_tlsgd, DUMMY_RELOC_LITUSE_TLSGD, 1, 1), + DEF(lituse_tlsldm, DUMMY_RELOC_LITUSE_TLSLDM, 1, 1), DEF(gpdisp, BFD_RELOC_ALPHA_GPDISP, 1, 1), DEF(gprelhigh, BFD_RELOC_ALPHA_GPREL_HI16, 0, 0), DEF(gprellow, BFD_RELOC_ALPHA_GPREL_LO16, 0, 0), DEF(gprel, BFD_RELOC_GPREL16, 0, 0), - DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0) + DEF(samegp, BFD_RELOC_ALPHA_BRSGP, 0, 0), + DEF(tlsgd, BFD_RELOC_ALPHA_TLSGD, 0, 1), + DEF(tlsldm, BFD_RELOC_ALPHA_TLSLDM, 0, 1), + DEF(gotdtprel, BFD_RELOC_ALPHA_GOTDTPREL16, 0, 0), + DEF(dtprelhi, BFD_RELOC_ALPHA_DTPREL_HI16, 0, 0), + DEF(dtprello, BFD_RELOC_ALPHA_DTPREL_LO16, 0, 0), + DEF(dtprel, BFD_RELOC_ALPHA_DTPREL16, 0, 0), + DEF(gottprel, BFD_RELOC_ALPHA_GOTTPREL16, 0, 0), + DEF(tprelhi, BFD_RELOC_ALPHA_TPREL_HI16, 0, 0), + DEF(tprello, BFD_RELOC_ALPHA_TPREL_LO16, 0, 0), + DEF(tprel, BFD_RELOC_ALPHA_TPREL16, 0, 0), }; #undef DEF @@ -515,12 +542,17 @@ static const int alpha_num_reloc_op /* Structure to hold explict sequence information. */ struct alpha_reloc_tag { - fixS *slaves; /* head of linked list of !literals */ + fixS *master; /* the literal reloc */ + fixS *slaves; /* head of linked list of lituses */ segT segment; /* segment relocs are in or undefined_section*/ long sequence; /* sequence # */ unsigned n_master; /* # of literals */ unsigned n_slaves; /* # of lituses */ - char multi_section_p; /* True if more than one section was used */ + unsigned saw_tlsgd : 1; /* true if ... */ + unsigned saw_tlsldm : 1; + unsigned saw_lu_tlsgd : 1; + unsigned saw_lu_tlsldm : 1; + unsigned multi_section_p : 1; /* true if more than one section was used */ char string[1]; /* printable form of sequence to hash with */ }; @@ -1223,6 +1255,16 @@ md_apply_fix3 (fixP, valP, seg) #ifdef OBJ_ELF case BFD_RELOC_ALPHA_BRSGP: + case BFD_RELOC_ALPHA_TLSGD: + case BFD_RELOC_ALPHA_TLSLDM: + case BFD_RELOC_ALPHA_GOTDTPREL16: + case BFD_RELOC_ALPHA_DTPREL_HI16: + case BFD_RELOC_ALPHA_DTPREL_LO16: + case BFD_RELOC_ALPHA_DTPREL16: + case BFD_RELOC_ALPHA_GOTTPREL16: + case BFD_RELOC_ALPHA_TPREL_HI16: + case BFD_RELOC_ALPHA_TPREL_LO16: + case BFD_RELOC_ALPHA_TPREL16: return; #endif @@ -1441,6 +1483,16 @@ alpha_force_relocation (f) case BFD_RELOC_ALPHA_BRSGP: case BFD_RELOC_VTABLE_INHERIT: case BFD_RELOC_VTABLE_ENTRY: + case BFD_RELOC_ALPHA_TLSGD: + case BFD_RELOC_ALPHA_TLSLDM: + case BFD_RELOC_ALPHA_GOTDTPREL16: + case BFD_RELOC_ALPHA_DTPREL_HI16: + case BFD_RELOC_ALPHA_DTPREL_LO16: + case BFD_RELOC_ALPHA_DTPREL16: + case BFD_RELOC_ALPHA_GOTTPREL16: + case BFD_RELOC_ALPHA_TPREL_HI16: + case BFD_RELOC_ALPHA_TPREL_LO16: + case BFD_RELOC_ALPHA_TPREL16: return 1; case BFD_RELOC_23_PCREL_S2: @@ -1497,6 +1549,20 @@ alpha_fix_adjustable (f) case BFD_RELOC_ALPHA_HINT: return 1; + case BFD_RELOC_ALPHA_TLSGD: + case BFD_RELOC_ALPHA_TLSLDM: + case BFD_RELOC_ALPHA_GOTDTPREL16: + case BFD_RELOC_ALPHA_DTPREL_HI16: + case BFD_RELOC_ALPHA_DTPREL_LO16: + case BFD_RELOC_ALPHA_DTPREL16: + case BFD_RELOC_ALPHA_GOTTPREL16: + case BFD_RELOC_ALPHA_TPREL_HI16: + case BFD_RELOC_ALPHA_TPREL_LO16: + case BFD_RELOC_ALPHA_TPREL16: + /* ??? No idea why we can't return a reference to .tbss+10, but + we're preventing this in the other assemblers. Follow for now. */ + return 0; + default: return 1; } @@ -1666,7 +1732,6 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr) fixS *fixp; fixS *next; fixS *slave; - unsigned long n_slaves = 0; /* If seginfo is NULL, we did not create this section; don't do anything with it. By using a pointer to a pointer, we can update @@ -1689,21 +1754,39 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr) switch (fixp->fx_r_type) { case BFD_RELOC_ALPHA_LITUSE: - n_slaves++; if (fixp->tc_fix_data.info->n_master == 0) as_bad_where (fixp->fx_file, fixp->fx_line, _("No !literal!%ld was found"), fixp->tc_fix_data.info->sequence); + if (fixp->fx_offset == LITUSE_TLSGD) + { + if (! fixp->tc_fix_data.info->saw_tlsgd) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("No !tlsgd!%ld was found"), + fixp->tc_fix_data.info->sequence); + } + else if (fixp->fx_offset == LITUSE_TLSLDM) + { + if (! fixp->tc_fix_data.info->saw_tlsldm) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("No !tlsldm!%ld was found"), + fixp->tc_fix_data.info->sequence); + } break; case BFD_RELOC_ALPHA_GPDISP_LO16: - n_slaves++; if (fixp->tc_fix_data.info->n_master == 0) as_bad_where (fixp->fx_file, fixp->fx_line, _("No ldah !gpdisp!%ld was found"), fixp->tc_fix_data.info->sequence); break; + case BFD_RELOC_ALPHA_ELF_LITERAL: + if (fixp->tc_fix_data.info->saw_tlsgd + || fixp->tc_fix_data.info->saw_tlsldm) + break; + /* FALLTHRU */ + default: *prevP = fixp; prevP = &fixp->fx_next; @@ -1711,10 +1794,10 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr) } } - /* If there were any dependent relocations, go and add them back to - the chain. They are linked through the next_reloc field in - reverse order, so as we go through the next_reloc chain, we - effectively reverse the chain once again. + /* Go back and re-chain dependent relocations. They are currently + linked through the next_reloc field in reverse order, so as we + go through the next_reloc chain, we effectively reverse the chain + once again. Except if there is more than one !literal for a given sequence number. In that case, the programmer and/or compiler is not sure @@ -1734,6 +1817,27 @@ alpha_adjust_symtab_relocs (abfd, sec, ptr) next = fixp->fx_next; switch (fixp->fx_r_type) { + case BFD_RELOC_ALPHA_TLSGD: + case BFD_RELOC_ALPHA_TLSLDM: + if (!fixp->tc_fix_data.info) + break; + if (fixp->tc_fix_data.info->n_master == 0) + break; + else if (fixp->tc_fix_data.info->n_master > 1) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("too many !literal!%ld for %s"), + fixp->tc_fix_data.info->sequence, + (fixp->fx_r_type == BFD_RELOC_ALPHA_TLSGD + ? "!tlsgd" : "!tlsldm")); + break; + } + + fixp->tc_fix_data.info->master->fx_next = fixp->fx_next; + fixp->fx_next = fixp->tc_fix_data.info->master; + fixp = fixp->fx_next; + /* FALLTHRU */ + case BFD_RELOC_ALPHA_ELF_LITERAL: if (fixp->tc_fix_data.info->n_master == 1 && ! fixp->tc_fix_data.info->multi_section_p) @@ -1820,15 +1924,23 @@ debug_exp (tok, ntok) case O_lituse_base: name = "O_lituse_base"; break; case O_lituse_bytoff: name = "O_lituse_bytoff"; break; case O_lituse_jsr: name = "O_lituse_jsr"; break; + case O_lituse_tlsgd: name = "O_lituse_tlsgd"; break; + case O_lituse_tlsldm: name = "O_lituse_tlsldm"; break; case O_gpdisp: name = "O_gpdisp"; break; case O_gprelhigh: name = "O_gprelhigh"; break; case O_gprellow: name = "O_gprellow"; break; case O_gprel: name = "O_gprel"; break; case O_samegp: name = "O_samegp"; break; - case O_md13: name = "O_md13"; break; - case O_md14: name = "O_md14"; break; - case O_md15: name = "O_md15"; break; - case O_md16: name = "O_md16"; break; + case O_tlsgd: name = "O_tlsgd"; break; + case O_tlsldm: name = "O_tlsldm"; break; + case O_gotdtprel: name = "O_gotdtprel"; break; + case O_dtprelhi: name = "O_dtprelhi"; break; + case O_dtprello: name = "O_dtprello"; break; + case O_dtprel: name = "O_dtprel"; break; + case O_gottprel: name = "O_gottprel"; break; + case O_tprelhi: name = "O_tprelhi"; break; + case O_tprello: name = "O_tprello"; break; + case O_tprel: name = "O_tprel"; break; } fprintf (stderr, ", %s(%s, %s, %d)", name, @@ -2479,7 +2591,7 @@ emit_insn (insn) { const struct alpha_operand *operand = (const struct alpha_operand *) 0; struct alpha_fixup *fixup = &insn->fixups[i]; - struct alpha_reloc_tag *info; + struct alpha_reloc_tag *info = NULL; int size, pcrel; fixS *fixP; @@ -2521,6 +2633,14 @@ emit_insn (insn) case BFD_RELOC_GPREL16: case BFD_RELOC_ALPHA_GPREL_HI16: case BFD_RELOC_ALPHA_GPREL_LO16: + case BFD_RELOC_ALPHA_GOTDTPREL16: + case BFD_RELOC_ALPHA_DTPREL_HI16: + case BFD_RELOC_ALPHA_DTPREL_LO16: + case BFD_RELOC_ALPHA_DTPREL16: + case BFD_RELOC_ALPHA_GOTTPREL16: + case BFD_RELOC_ALPHA_TPREL_HI16: + case BFD_RELOC_ALPHA_TPREL_LO16: + case BFD_RELOC_ALPHA_TPREL16: fixP->fx_no_overflow = 1; break; @@ -2555,7 +2675,10 @@ emit_insn (insn) case BFD_RELOC_ALPHA_ELF_LITERAL: fixP->fx_no_overflow = 1; + if (insn->sequence == 0) + break; info = get_alpha_reloc_tag (insn->sequence); + info->master = fixP; info->n_master++; if (info->segment != now_seg) info->multi_section_p = 1; @@ -2573,12 +2696,31 @@ emit_insn (insn) goto do_lituse; case DUMMY_RELOC_LITUSE_JSR: fixP->fx_offset = LITUSE_JSR; + goto do_lituse; + case DUMMY_RELOC_LITUSE_TLSGD: + fixP->fx_offset = LITUSE_TLSGD; + goto do_lituse; + case DUMMY_RELOC_LITUSE_TLSLDM: + fixP->fx_offset = LITUSE_TLSLDM; + goto do_lituse; do_lituse: fixP->fx_addsy = section_symbol (now_seg); fixP->fx_r_type = BFD_RELOC_ALPHA_LITUSE; info = get_alpha_reloc_tag (insn->sequence); - info->n_slaves++; + if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSGD) + info->saw_lu_tlsgd = 1; + else if (fixup->reloc == DUMMY_RELOC_LITUSE_TLSLDM) + info->saw_lu_tlsldm = 1; + if (++info->n_slaves > 1) + { + if (info->saw_lu_tlsgd) + as_bad (_("too many lituse insns for !lituse_tlsgd!%ld"), + insn->sequence); + else if (info->saw_lu_tlsldm) + as_bad (_("too many lituse insns for !lituse_tlsldm!%ld"), + insn->sequence); + } fixP->tc_fix_data.info = info; fixP->tc_fix_data.next_reloc = info->slaves; info->slaves = fixP; @@ -2586,6 +2728,38 @@ emit_insn (insn) info->multi_section_p = 1; break; + case BFD_RELOC_ALPHA_TLSGD: + fixP->fx_no_overflow = 1; + + if (insn->sequence == 0) + break; + info = get_alpha_reloc_tag (insn->sequence); + if (info->saw_tlsgd) + as_bad (_("duplicate !tlsgd!%ld"), insn->sequence); + else if (info->saw_tlsldm) + as_bad (_("sequence number in use for !tlsldm!%ld"), + insn->sequence); + else + info->saw_tlsgd = 1; + fixP->tc_fix_data.info = info; + break; + + case BFD_RELOC_ALPHA_TLSLDM: + fixP->fx_no_overflow = 1; + + if (insn->sequence == 0) + break; + info = get_alpha_reloc_tag (insn->sequence); + if (info->saw_tlsldm) + as_bad (_("duplicate !tlsldm!%ld"), insn->sequence); + else if (info->saw_tlsgd) + as_bad (_("sequence number in use for !tlsgd!%ld"), + insn->sequence); + else + info->saw_tlsldm = 1; + fixP->tc_fix_data.info = info; + break; + default: if ((int) fixup->reloc < 0) { @@ -2715,7 +2889,6 @@ static const char * const extXh_op[] = { NULL, "extwh", "extlh", "extqh" }; static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" }; static const char * const mskXh_op[] = { NULL, "mskwh", "msklh", "mskqh" }; static const char * const stX_op[] = { "stb", "stw", "stl", "stq" }; -static const char * const ldX_op[] = { "ldb", "ldw", "ldll", "ldq" }; static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL }; /* Implement the ldgp macro. */ diff --git a/gas/expr.h b/gas/expr.h index 9483cafb41..3a4c931673 100644 --- a/gas/expr.h +++ b/gas/expr.h @@ -107,6 +107,8 @@ typedef enum { /* machine dependent operators */ O_md1, O_md2, O_md3, O_md4, O_md5, O_md6, O_md7, O_md8, O_md9, O_md10, O_md11, O_md12, O_md13, O_md14, O_md15, O_md16, + O_md17, O_md18, O_md19, O_md20, O_md21, O_md22, O_md23, O_md24, + O_md25, O_md26, O_md27, O_md28, O_md29, O_md30, O_md31, O_md32, /* this must be the largest value */ O_max } operatorT; diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index ff91d8d3f1..9554e69d0f 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2002-05-30 Richard Henderson + + * gas/alpha/elf-tls-1.s, gas/alpha/elf-tls-1.d: New. + * gas/alpha/elf-tls-2.s, gas/alpha/elf-tls-1.l: New. + * gas/alpha/elf-tls-3.s, gas/alpha/elf-tls-1.l: New. + * gas/alpha/alpha.exp: Run them. + 2002-05-30 Tom Rix * gas/d10v/d10v.exp: Add -gstabs packing, sequence control diff --git a/gas/testsuite/gas/alpha/alpha.exp b/gas/testsuite/gas/alpha/alpha.exp index 89a63345a7..6564cf9e4f 100644 --- a/gas/testsuite/gas/alpha/alpha.exp +++ b/gas/testsuite/gas/alpha/alpha.exp @@ -29,6 +29,9 @@ if { [istarget alpha*-*-*] } then { run_dump_test "elf-reloc-4" run_dump_test "elf-reloc-5" run_list_test "elf-reloc-6" "" + run_dump_test "elf-tls-1" + run_list_test "elf-tls-2" "" + run_list_test "elf-tls-3" "" } run_dump_test "fp" diff --git a/gas/testsuite/gas/alpha/elf-tls-1.d b/gas/testsuite/gas/alpha/elf-tls-1.d new file mode 100644 index 0000000000..7f80de7020 --- /dev/null +++ b/gas/testsuite/gas/alpha/elf-tls-1.d @@ -0,0 +1,29 @@ +#objdump: -r +#name: alpha elf-tls-1 + +.*: file format elf64-alpha + +RELOCATION RECORDS FOR \[\.text\]: +OFFSET TYPE VALUE +0*0000004 TLSGD a +0*0000000 ELF_LITERAL __tls_get_addr +0*0000008 LITUSE \.text\+0x0*0000004 +0*0000008 HINT __tls_get_addr +0*000000c HINT __tls_get_addr +0*0000014 TLSLDM b +0*0000010 ELF_LITERAL __tls_get_addr +0*000000c LITUSE \.text\+0x0*0000005 +0*0000018 TLSGD c +0*000001c TLSLDM d +0*0000020 TLSGD e +0*0000024 TLSLDM f +0*0000028 GOTDTPREL g +0*000002c DTPRELHI h +0*0000030 DTPRELLO i +0*0000034 DTPREL16 j +0*0000038 GOTTPREL k +0*000003c TPRELHI l +0*0000040 TPRELLO m +0*0000044 TPREL16 n + + diff --git a/gas/testsuite/gas/alpha/elf-tls-1.s b/gas/testsuite/gas/alpha/elf-tls-1.s new file mode 100644 index 0000000000..42385d7064 --- /dev/null +++ b/gas/testsuite/gas/alpha/elf-tls-1.s @@ -0,0 +1,24 @@ + .set nomacro + ldq $27, __tls_get_addr($29) !literal!1 + ldq $16, a($29) !tlsgd!1 + jsr $26, ($27), __tls_get_addr !lituse_tlsgd!1 + + jsr $26, ($27), __tls_get_addr !lituse_tlsldm!2 + ldq $27, __tls_get_addr($29) !literal!2 + ldq $16, b($29) !tlsldm!2 + + ldq $16, c($29) !tlsgd + ldq $16, d($29) !tlsldm + + ldq $16, e($29) !tlsgd!3 + ldq $16, f($29) !tlsldm!4 + + ldq $16, g($29) !gotdtprel + ldah $16, h($31) !dtprelhi + lda $16, i($16) !dtprello + lda $16, j($31) !dtprel + + ldq $16, k($29) !gottprel + ldah $16, l($31) !tprelhi + lda $16, m($16) !tprello + lda $16, n($31) !tprel diff --git a/gas/testsuite/gas/alpha/elf-tls-2.l b/gas/testsuite/gas/alpha/elf-tls-2.l new file mode 100644 index 0000000000..4fcee7971c --- /dev/null +++ b/gas/testsuite/gas/alpha/elf-tls-2.l @@ -0,0 +1,9 @@ +.*: Assembler messages: +.*:5: Error: too many lituse insns for !lituse_tlsgd!1 +.*:10: Error: too many lituse insns for !lituse_tlsldm!2 +.*:15: Error: too many lituse insns for !lituse_tlsgd!3 +.*:20: Error: too many lituse insns for !lituse_tlsldm!4 +.*:23: Error: duplicate !tlsgd!5 +.*:26: Error: duplicate !tlsldm!6 +.*:29: Error: sequence number in use for !tlsgd!7 +.*:32: Error: sequence number in use for !tlsldm!8 diff --git a/gas/testsuite/gas/alpha/elf-tls-2.s b/gas/testsuite/gas/alpha/elf-tls-2.s new file mode 100644 index 0000000000..214fe3a4d9 --- /dev/null +++ b/gas/testsuite/gas/alpha/elf-tls-2.s @@ -0,0 +1,32 @@ + .set nomacro + ldq $16, c($29) !tlsgd!1 + ldq $27, __tls_get_addr($29) !literal!1 + jsr $26, ($27), __tls_get_addr !lituse_tlsgd!1 + jsr $26, ($27), __tls_get_addr !lituse_jsr!1 + + ldq $16, d($29) !tlsldm!2 + ldq $27, __tls_get_addr($29) !literal!2 + jsr $26, ($27), __tls_get_addr !lituse_jsr!2 + jsr $26, ($27), __tls_get_addr !lituse_tlsldm!2 + + ldq $16, g($29) !tlsgd!3 + ldq $27, __tls_get_addr($29) !literal!3 + jsr $26, ($27), __tls_get_addr !lituse_tlsgd!3 + jsr $26, ($27), __tls_get_addr !lituse_tlsgd!3 + + ldq $16, h($29) !tlsldm!4 + ldq $27, __tls_get_addr($29) !literal!4 + jsr $26, ($27), __tls_get_addr !lituse_tlsldm!4 + jsr $26, ($27), __tls_get_addr !lituse_tlsldm!4 + + ldq $16, i($29) !tlsgd!5 + ldq $16, i($29) !tlsgd!5 + + ldq $16, j($29) !tlsldm!6 + ldq $16, j($29) !tlsldm!6 + + ldq $16, k($29) !tlsgd!7 + ldq $16, k($29) !tlsldm!7 + + ldq $16, l($29) !tlsldm!8 + ldq $16, l($29) !tlsgd!8 diff --git a/gas/testsuite/gas/alpha/elf-tls-3.l b/gas/testsuite/gas/alpha/elf-tls-3.l new file mode 100644 index 0000000000..51d93e78a8 --- /dev/null +++ b/gas/testsuite/gas/alpha/elf-tls-3.l @@ -0,0 +1,7 @@ +.*: Assembler messages: +.*:3: Error: No !tlsgd!1 was found +.*:6: Error: No !tlsldm!2 was found +.*:18: Error: No !tlsldm!5 was found +.*:22: Error: No !tlsgd!6 was found +.*:8: Error: too many !literal!3 for !tlsgd +.*:12: Error: too many !literal!4 for !tlsldm diff --git a/gas/testsuite/gas/alpha/elf-tls-3.s b/gas/testsuite/gas/alpha/elf-tls-3.s new file mode 100644 index 0000000000..31480dabc3 --- /dev/null +++ b/gas/testsuite/gas/alpha/elf-tls-3.s @@ -0,0 +1,22 @@ + .set nomacro + ldq $27, __tls_get_addr($29) !literal!1 + jsr $26, ($27), __tls_get_addr !lituse_tlsgd!1 + + ldq $27, __tls_get_addr($29) !literal!2 + jsr $26, ($27), __tls_get_addr !lituse_tlsldm!2 + + ldq $16, a($29) !tlsgd!3 + ldq $27, __tls_get_addr($29) !literal!3 + ldq $27, __tls_get_addr($29) !literal!3 + + ldq $16, b($29) !tlsldm!4 + ldq $27, __tls_get_addr($29) !literal!4 + ldq $27, __tls_get_addr($29) !literal!4 + + ldq $16, e($29) !tlsgd!5 + ldq $27, __tls_get_addr($29) !literal!5 + jsr $26, ($27), __tls_get_addr !lituse_tlsldm!5 + + ldq $16, f($29) !tlsldm!6 + ldq $27, __tls_get_addr($29) !literal!6 + jsr $26, ($27), __tls_get_addr !lituse_tlsgd!6 diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index 3be8a53655..905bad1c19 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,10 @@ +2002-05-30 Richard Henderson + + * alpha.h (R_ALPHA_TLSGD, R_ALPHA_TLSLDM, R_ALPHA_DTPMOD64, + R_ALPHA_GOTDTPREL, R_ALPHA_DTPREL64, R_ALPHA_DTPRELHI, + R_ALPHA_DTPRELLO, R_ALPHA_DTPREL16, R_ALPHA_GOTTPREL, R_ALPHA_TPREL64, + R_ALPHA_TPRELHI, R_ALPHA_TPRELLO, R_ALPHA_TPREL16): New. + 2002-05-29 Matt Thomas * vax.h: New file diff --git a/include/elf/alpha.h b/include/elf/alpha.h index e937b81478..70168d60ad 100644 --- a/include/elf/alpha.h +++ b/include/elf/alpha.h @@ -99,6 +99,21 @@ START_RELOC_NUMBERS (elf_alpha_reloc_type) STO_ALPHA_STD_GPLOAD. */ RELOC_NUMBER (R_ALPHA_BRSGP, 28) + /* Thread-Local Storage. */ + RELOC_NUMBER (R_ALPHA_TLSGD, 29) + RELOC_NUMBER (R_ALPHA_TLSLDM, 30) + RELOC_NUMBER (R_ALPHA_DTPMOD64, 31) + RELOC_NUMBER (R_ALPHA_GOTDTPREL, 32) + RELOC_NUMBER (R_ALPHA_DTPREL64, 33) + RELOC_NUMBER (R_ALPHA_DTPRELHI, 34) + RELOC_NUMBER (R_ALPHA_DTPRELLO, 35) + RELOC_NUMBER (R_ALPHA_DTPREL16, 36) + RELOC_NUMBER (R_ALPHA_GOTTPREL, 37) + RELOC_NUMBER (R_ALPHA_TPREL64, 38) + RELOC_NUMBER (R_ALPHA_TPRELHI, 39) + RELOC_NUMBER (R_ALPHA_TPRELLO, 40) + RELOC_NUMBER (R_ALPHA_TPREL16, 41) + END_RELOC_NUMBERS (R_ALPHA_max) #endif /* _ELF_ALPHA_H */ -- 2.34.1