aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog28
-rw-r--r--bfd/bfd-in2.h15
-rw-r--r--bfd/elf64-alpha.c1324
-rw-r--r--bfd/libbfd.h13
-rw-r--r--bfd/reloc.c29
-rw-r--r--gas/ChangeLog18
-rw-r--r--gas/config/tc-alpha.c223
-rw-r--r--gas/expr.h2
-rw-r--r--gas/testsuite/ChangeLog7
-rw-r--r--gas/testsuite/gas/alpha/alpha.exp3
-rw-r--r--gas/testsuite/gas/alpha/elf-tls-1.d29
-rw-r--r--gas/testsuite/gas/alpha/elf-tls-1.s24
-rw-r--r--gas/testsuite/gas/alpha/elf-tls-2.l9
-rw-r--r--gas/testsuite/gas/alpha/elf-tls-2.s32
-rw-r--r--gas/testsuite/gas/alpha/elf-tls-3.l7
-rw-r--r--gas/testsuite/gas/alpha/elf-tls-3.s22
-rw-r--r--include/elf/ChangeLog7
-rw-r--r--include/elf/alpha.h15
18 files changed, 1391 insertions, 416 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index c1e6aad..9cc7518 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,31 @@
+2002-05-30 Richard Henderson <rth@redhat.com>
+
+ * 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 <ralf.habacker@freenet.de>
* peXXigen.c (pe_print_idata): Remove double printed
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 6d82737..000fee6 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 94b4ebe..7099ba5 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 cbb6390..6cba829 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 60d40aa..8af90fc 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -1963,6 +1963,35 @@ ENUMDOC
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
Bits 27..2 of the relocation address shifted right 2 bits;
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 979573b..84fac45 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,21 @@
+2002-05-30 Richard Henderson <rth@redhat.com>
+
+ * 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 <seufer@csv.ica.uni-stuttgart.de>
* config/tc-mips.c (mips_gprel_offset): New variable.
diff --git a/gas/config/tc-alpha.c b/gas/config/tc-alpha.c
index 7746f99..1ba7aca 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 9483caf..3a4c931 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 ff91d8d..9554e69 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2002-05-30 Richard Henderson <rth@redhat.com>
+
+ * 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 <trix@redhat.com>
* 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 89a6334..6564cf9 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 0000000..7f80de7
--- /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 0000000..42385d7
--- /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 0000000..4fcee79
--- /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 0000000..214fe3a
--- /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 0000000..51d93e7
--- /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 0000000..31480da
--- /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 3be8a53..905bad1 100644
--- a/include/elf/ChangeLog
+++ b/include/elf/ChangeLog
@@ -1,3 +1,10 @@
+2002-05-30 Richard Henderson <rth@redhat.com>
+
+ * 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 <matt@3am-software.com>
* vax.h: New file
diff --git a/include/elf/alpha.h b/include/elf/alpha.h
index e937b81..70168d6 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 */