aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf64-alpha.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf64-alpha.c')
-rw-r--r--bfd/elf64-alpha.c1748
1 files changed, 1082 insertions, 666 deletions
diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c
index 9888273..ffc612f 100644
--- a/bfd/elf64-alpha.c
+++ b/bfd/elf64-alpha.c
@@ -1,4 +1,4 @@
-/* ALPHA-specific support for 64-bit ELF
+/* Alpha specific support for 64-bit ELF
Copyright 1996 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@tamu.edu>.
@@ -53,18 +53,12 @@ static struct bfd_link_hash_table * elf64_alpha_bfd_link_hash_table_create
static bfd_reloc_status_type elf64_alpha_reloc_nil
PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type elf64_alpha_reloc_bad
+ PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type elf64_alpha_do_reloc_gpdisp
PARAMS((bfd *, bfd_vma, bfd_byte *, bfd_byte *));
static bfd_reloc_status_type elf64_alpha_reloc_gpdisp
PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_push
- PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_store
- PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_psub
- PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
-static bfd_reloc_status_type elf64_alpha_reloc_op_prshift
- PARAMS((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static reloc_howto_type * elf64_alpha_bfd_reloc_type_lookup
PARAMS((bfd *, bfd_reloc_code_real_type));
@@ -99,6 +93,11 @@ struct alpha_elf_link_hash_entry;
static boolean elf64_alpha_output_extsym
PARAMS((struct alpha_elf_link_hash_entry *, PTR));
+static boolean elf64_alpha_can_merge_gots
+ PARAMS((bfd *, bfd *));
+static void elf64_alpha_merge_gots
+ PARAMS((bfd *, bfd *));
+
static boolean elf64_alpha_check_relocs
PARAMS((bfd *, struct bfd_link_info *, asection *sec,
const Elf_Internal_Rela *));
@@ -120,9 +119,6 @@ static boolean elf64_alpha_final_link
PARAMS((bfd *, struct bfd_link_info *));
-#define alpha_elf_tdata(bfd) \
- ((struct alpha_elf_obj_tdata *)elf_tdata(bfd)->tdata)
-
struct alpha_elf_link_hash_entry
{
struct elf_link_hash_entry root;
@@ -130,11 +126,50 @@ struct alpha_elf_link_hash_entry
/* External symbol information. */
EXTR esym;
- unsigned char flags;
+ /* Cumulative flags for all the .got entries. */
+ int flags;
+
/* Contexts (LITUSE) in which a literal was referenced. */
-#define ALPHA_ELF_LINK_HASH_LU_ADDR 01
-#define ALPHA_ELF_LINK_HASH_LU_MEM 02
-#define ALPHA_ELF_LINK_HASH_LU_FUNC 04
+#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
+
+ /* Used to implement multiple .got subsections. */
+ struct alpha_elf_got_entry
+ {
+ struct alpha_elf_got_entry *next;
+
+ /* which .got subsection? */
+ bfd *gotobj;
+
+ /* the addend in effect for this entry. */
+ bfd_vma addend;
+
+ /* the .got offset for this entry. */
+ int got_offset;
+
+ int flags;
+
+ /* An additional flag. */
+#define ALPHA_ELF_GOT_ENTRY_RELOCS_DONE 0x10
+ } *got_entries;
+
+ /* used to count non-got, non-plt relocations for delayed sizing
+ of relocation sections. */
+ struct alpha_elf_reloc_entry
+ {
+ struct alpha_elf_reloc_entry *next;
+
+ /* which .reloc section? */
+ asection *srel;
+
+ /* what kind of relocation? */
+ unsigned long rtype;
+
+ /* how many did we find? */
+ unsigned long count;
+ } *reloc_entries;
};
/* Alpha ELF linker hash table. */
@@ -142,6 +177,10 @@ struct alpha_elf_link_hash_entry
struct alpha_elf_link_hash_table
{
struct elf_link_hash_table root;
+
+ /* The head of a list of .got subsections linked through
+ alpha_elf_tdata(abfd)->got_link_next. */
+ bfd *got_list;
};
/* Look up an entry in a Alpha ELF linker hash table. */
@@ -164,6 +203,19 @@ struct alpha_elf_link_hash_table
#define alpha_elf_hash_table(p) \
((struct alpha_elf_link_hash_table *) ((p)->hash))
+/* Get the object's symbols as our own entry type. */
+
+#define alpha_elf_sym_hashes(abfd) \
+ ((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
+
+/* Should we do dynamic things to this symbol? */
+
+#define alpha_elf_dynamic_symbol_p(h, info) \
+ (((info)->shared && !(info)->symbolic) \
+ || (((h)->elf_link_hash_flags \
+ & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)) \
+ == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
+
/* Create an entry in a Alpha ELF linker hash table. */
static struct bfd_hash_entry *
@@ -196,6 +248,8 @@ elf64_alpha_link_hash_newfunc (entry, table, string)
not been set. -1 means there is no associated ifd. */
ret->esym.ifd = -2;
ret->flags = 0;
+ ret->got_entries = NULL;
+ ret->reloc_entries = NULL;
}
return (struct bfd_hash_entry *) ret;
@@ -224,7 +278,50 @@ elf64_alpha_bfd_link_hash_table_create (abfd)
return &ret->root.root;
}
+/* We have some private fields hanging off of the elf_tdata structure. */
+
+struct alpha_elf_obj_tdata
+{
+ struct elf_obj_tdata root;
+
+ /* For every input file, these are the got entries for that object's
+ local symbols. */
+ struct alpha_elf_got_entry ** local_got_entries;
+
+ /* For every input file, this is the object that owns the got that
+ this input file uses. */
+ bfd *gotobj;
+
+ /* For every got, this is a linked list through the objects using this got */
+ bfd *in_got_link_next;
+ /* For every got, this is a link to the next got subsegment. */
+ bfd *got_link_next;
+
+ /* 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 the sum of the number of *entries* required
+ to hold all of the member object's local got. */
+ int n_local_got_entries;
+};
+
+#define alpha_elf_tdata(abfd) \
+ ((struct alpha_elf_obj_tdata *) (abfd)->tdata.any)
+
+static boolean
+elf64_alpha_mkobject (abfd)
+ bfd *abfd;
+{
+ abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct alpha_elf_obj_tdata));
+ if (abfd->tdata.any == NULL)
+ return false;
+ return true;
+}
+
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
from smaller values. Start with zero, widen, *then* decrement. */
#define MINUS_ONE (((bfd_vma)0) - 1)
@@ -301,13 +398,13 @@ static reloc_howto_type elf64_alpha_howto_table[] =
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
0, /* special_function */
- "LITERAL", /* name */
+ "ELF_LITERAL", /* name */
false, /* partial_inplace */
0xffff, /* src_mask */
0xffff, /* dst_mask */
false), /* pcrel_offset */
- /* This reloc only appears immediately following a LITERAL reloc.
+ /* This reloc only appears immediately following an ELF_LITERAL reloc.
It identifies a use of the literal. The symbol index is special:
1 means the literal address is in the base register of a memory
format instruction; 2 means the literal address is in the byte
@@ -336,7 +433,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
current location; the load will always be done against a register
holding the current address.
- NOTE: Unlike ECOFF, partial inplace relocation is not done. If
+ NOTE: Unlike ECOFF, partial in-place relocation is not done. If
any offset is present in the instructions, it is an offset from
the register to the ldah instruction. This lets us avoid any
stupid hackery like inventing a gp value to do partial relocation
@@ -441,7 +538,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- elf64_alpha_reloc_op_push, /* special_function */
+ elf64_alpha_reloc_bad, /* special_function */
"OP_PUSH", /* name */
false, /* partial_inplace */
0, /* src_mask */
@@ -457,7 +554,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- elf64_alpha_reloc_op_store, /* special_function */
+ elf64_alpha_reloc_bad, /* special_function */
"OP_STORE", /* name */
false, /* partial_inplace */
0, /* src_mask */
@@ -473,7 +570,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- elf64_alpha_reloc_op_psub, /* special_function */
+ elf64_alpha_reloc_bad, /* special_function */
"OP_PSUB", /* name */
false, /* partial_inplace */
0, /* src_mask */
@@ -489,7 +586,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- elf64_alpha_reloc_op_prshift, /* special_function */
+ elf64_alpha_reloc_bad, /* special_function */
"OP_PRSHIFT", /* name */
false, /* partial_inplace */
0, /* src_mask */
@@ -508,7 +605,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
"COPY",
false,
0,
- 0,
+ 0,
true),
HOWTO (R_ALPHA_GLOB_DAT,
@@ -522,7 +619,7 @@ static reloc_howto_type elf64_alpha_howto_table[] =
"GLOB_DAT",
false,
0,
- 0,
+ 0,
true),
HOWTO (R_ALPHA_JMP_SLOT,
@@ -547,13 +644,15 @@ static reloc_howto_type elf64_alpha_howto_table[] =
0,
complain_overflow_dont,
bfd_elf_generic_reloc,
- "RELATIVE",
+ "RELATIVE",
false,
0,
0,
true)
};
+/* A relocation function which doesn't do anything. */
+
static bfd_reloc_status_type
elf64_alpha_reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message)
bfd *abfd;
@@ -569,18 +668,38 @@ elf64_alpha_reloc_nil (abfd, reloc, sym, data, sec, output_bfd, error_message)
return bfd_reloc_ok;
}
+/* A relocation function used for an unsupported reloc. */
+
+static bfd_reloc_status_type
+elf64_alpha_reloc_bad (abfd, reloc, sym, data, sec, output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc;
+ asymbol *sym;
+ PTR data;
+ asection *sec;
+ bfd *output_bfd;
+ char **error_message;
+{
+ if (output_bfd)
+ reloc->address += sec->output_offset;
+ return bfd_reloc_notsupported;
+}
+
+/* Do the work of the GPDISP relocation. */
+
static bfd_reloc_status_type
elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda)
bfd *abfd;
bfd_vma gpdisp;
- bfd_byte *p_ldah, *p_lda;
+ bfd_byte *p_ldah;
+ bfd_byte *p_lda;
{
bfd_reloc_status_type ret = bfd_reloc_ok;
bfd_vma addend;
unsigned long i_ldah, i_lda;
- i_ldah = bfd_get_32(abfd, p_ldah);
- i_lda = bfd_get_32(abfd, p_lda);
+ i_ldah = bfd_get_32 (abfd, p_ldah);
+ i_lda = bfd_get_32 (abfd, p_lda);
/* Complain if the instructions are not correct. */
if (((i_ldah >> 26) & 0x3f) != 0x09
@@ -594,7 +713,7 @@ elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda)
gpdisp += addend;
- if ((bfd_signed_vma)gpdisp < -(bfd_signed_vma)0x80000000
+ if ((bfd_signed_vma) gpdisp < -(bfd_signed_vma)0x80000000
|| gpdisp >= 0x7fff8000)
ret = bfd_reloc_overflow;
@@ -609,6 +728,8 @@ elf64_alpha_do_reloc_gpdisp (abfd, gpdisp, p_ldah, p_lda)
return ret;
}
+/* The special function for the GPDISP reloc. */
+
static bfd_reloc_status_type
elf64_alpha_reloc_gpdisp (abfd, reloc_entry, sym, data, input_section,
output_bfd, err_msg)
@@ -635,7 +756,7 @@ elf64_alpha_reloc_gpdisp (abfd, reloc_entry, sym, data, input_section,
reloc_entry->address + reloc_entry->addend > input_section->_cooked_size)
return bfd_reloc_outofrange;
- /* The gp used in the portion of the output object to which this
+ /* The gp used in the portion of the output object to which this
input object belongs is cached on the input bfd. */
gp = _bfd_get_gp_value (abfd);
@@ -643,184 +764,18 @@ elf64_alpha_reloc_gpdisp (abfd, reloc_entry, sym, data, input_section,
+ input_section->output_offset
+ reloc_entry->address);
- p_ldah = (bfd_byte *)data + reloc_entry->address;
+ p_ldah = (bfd_byte *) data + reloc_entry->address;
p_lda = p_ldah + reloc_entry->addend;
ret = elf64_alpha_do_reloc_gpdisp (abfd, gp - relocation, p_ldah, p_lda);
/* Complain if the instructions are not correct. */
if (ret == bfd_reloc_dangerous)
- {
- *err_msg = "GPDISP relocation did not find ldah and lda instructions";
- }
+ *err_msg = "GPDISP relocation did not find ldah and lda instructions";
return ret;
}
-/* Due to the nature of the stack operations, I don't think more
- that one entry is useful. Test this theory by setting the
- stack size to a minimum. */
-/* FIXME: BFD should not use static variables. */
-#define OP_STACK_SIZE 1
-static bfd_vma elf64_alpha_op_stack[OP_STACK_SIZE];
-static int elf64_alpha_op_tos;
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_push (abfd, reloc_entry, sym, data, input_section,
- output_bfd, err_msg)
- bfd *abfd;
- arelent *reloc_entry;
- asymbol *sym;
- PTR data;
- asection *input_section;
- bfd *output_bfd;
- char **err_msg;
-{
- bfd_reloc_status_type r = bfd_reloc_ok;
- bfd_vma value;
-
- /* Don't do anything if we're not doing a final link. */
- if (output_bfd)
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
-
- if (elf64_alpha_op_tos >= OP_STACK_SIZE)
- {
- *err_msg = "operation stack overflow";
- return bfd_reloc_dangerous;
- }
-
- /* Get the symbol value. */
- /* FIXME: We should fail if this is a dynamic symbol. Check on that. */
- if (bfd_is_und_section (sym->section))
- r = bfd_reloc_undefined;
- if (bfd_is_com_section (sym->section))
- value = 0;
- else
- value = sym->value;
- value += sym->section->output_section->vma;
- value += sym->section->output_offset;
- value += reloc_entry->addend;
-
- elf64_alpha_op_stack[elf64_alpha_op_tos++] = value;
-
- return r;
-}
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_store (abfd, reloc_entry, sym, data, input_section,
- output_bfd, err_msg)
- bfd *abfd;
- arelent *reloc_entry;
- asymbol *sym;
- PTR data;
- asection *input_section;
- bfd *output_bfd;
- char **err_msg;
-{
- int size, offset;
- bfd_vma value;
-
- /* Don't do anything before the final link. */
- if (output_bfd)
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
-
- if (elf64_alpha_op_tos <= 0)
- {
- *err_msg = "operation stack underflow";
- return bfd_reloc_dangerous;
- }
-
- /* The offset and size for this reloc are encoded into the addend
- field by alpha_adjust_reloc_in. */
- offset = (reloc_entry->addend >> 8) & 0xff;
- size = reloc_entry->addend & 0xff;
-
- value = bfd_get_64 (abfd, data + reloc_entry->address);
- value &= ~((((bfd_vma)1 << size) - 1) << offset);
- value |= (elf64_alpha_op_stack[--elf64_alpha_op_tos]
- & (((bfd_vma)1 << size) - 1)) << offset;
- bfd_put_64 (abfd, value, data + reloc_entry->address);
-
- return bfd_reloc_ok;
-}
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_psub (abfd, reloc_entry, sym, data, input_section,
- output_bfd, err_msg)
- bfd *abfd;
- arelent *reloc_entry;
- asymbol *sym;
- PTR data;
- asection *input_section;
- bfd *output_bfd;
- char **err_msg;
-{
- bfd_reloc_status_type r;
- bfd_vma value;
-
- /* Don't do anything before the final link. */
- if (output_bfd)
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
-
- if (elf64_alpha_op_tos <= 0)
- {
- *err_msg = "operation stack underflow";
- return bfd_reloc_dangerous;
- }
-
- if (bfd_is_und_section (sym->section))
- r = bfd_reloc_undefined;
- if (bfd_is_com_section (sym->section))
- value = 0;
- else
- value = sym->value;
- value += sym->section->output_section->vma;
- value += sym->section->output_offset;
- value += reloc_entry->addend;
-
- elf64_alpha_op_stack[elf64_alpha_op_tos-1] -= value;
-
- return r;
-}
-
-static bfd_reloc_status_type
-elf64_alpha_reloc_op_prshift (abfd, reloc_entry, sym, data, input_section,
- output_bfd, err_msg)
- bfd *abfd;
- arelent *reloc_entry;
- asymbol *sym;
- PTR data;
- asection *input_section;
- bfd *output_bfd;
- char **err_msg;
-{
- /* Don't do anything before the final link. */
- if (output_bfd)
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
-
- if (elf64_alpha_op_tos <= 0)
- {
- *err_msg = "operation stack underflow";
- return bfd_reloc_dangerous;
- }
-
- elf64_alpha_op_stack[elf64_alpha_op_tos-1] >>= reloc_entry->addend;
-
- return bfd_reloc_ok;
-}
-
/* A mapping from BFD reloc types to Alpha ELF reloc types. */
struct elf_reloc_map
@@ -836,20 +791,14 @@ static const struct elf_reloc_map elf64_alpha_reloc_map[] =
{BFD_RELOC_64, R_ALPHA_REFQUAD},
{BFD_RELOC_CTOR, R_ALPHA_REFQUAD},
{BFD_RELOC_GPREL32, R_ALPHA_GPREL32},
- {BFD_RELOC_ALPHA_LITERAL, R_ALPHA_LITERAL},
+ {BFD_RELOC_ALPHA_ELF_LITERAL, R_ALPHA_LITERAL},
{BFD_RELOC_ALPHA_LITUSE, R_ALPHA_LITUSE},
{BFD_RELOC_ALPHA_GPDISP, R_ALPHA_GPDISP},
- {BFD_RELOC_23_PCREL_S2, R_ALPHA_BRADDR},
- {BFD_RELOC_ALPHA_HINT, R_ALPHA_HINT},
- {BFD_RELOC_16_PCREL, R_ALPHA_SREL16},
- {BFD_RELOC_32_PCREL, R_ALPHA_SREL32},
- {BFD_RELOC_64_PCREL, R_ALPHA_SREL64},
-#if 0
- {BFD_RELOC_ALPHA_OP_PUSH, R_ALPHA_OP_PUSH},
- {BFD_RELOC_ALPHA_OP_STORE, R_ALPHA_OP_STORE},
- {BFD_RELOC_ALPHA_OP_PSUB, R_ALPHA_OP_PSUB},
- {BFD_RELOC_ALPHA_OP_PRSHIFT, R_ALPHA_OP_PRSHIFT}
-#endif
+ {BFD_RELOC_23_PCREL_S2, R_ALPHA_BRADDR},
+ {BFD_RELOC_ALPHA_HINT, R_ALPHA_HINT},
+ {BFD_RELOC_16_PCREL, R_ALPHA_SREL16},
+ {BFD_RELOC_32_PCREL, R_ALPHA_SREL32},
+ {BFD_RELOC_64_PCREL, R_ALPHA_SREL64},
};
/* Given a BFD reloc type, return a HOWTO structure. */
@@ -897,7 +846,7 @@ elf64_alpha_info_to_howto (abfd, cache_ptr, dst)
#define PLT_ENTRY_WORD2 0x239c0000 /* lda $28, 0($28) */
#define PLT_ENTRY_WORD3 0xc3e00000 /* br $31, plt0 */
-#define RESERVED_GOT_ENTRIES 1
+#define MAX_GOT_ENTRIES (64*1024 / 8)
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
@@ -910,7 +859,7 @@ elf64_alpha_object_p (abfd)
return bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0);
}
-/* Handle a alpha specific section when reading an object file. This
+/* Handle an Alpha specific section when reading an object file. This
is called when elfcode.h finds a section with an unknown type.
FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure
how to. */
@@ -1023,16 +972,18 @@ elf64_alpha_fake_sections (abfd, hdr, sec)
hdr->sh_entsize = 0;
hdr->sh_info = SIZEOF_ALPHA_DYNSYM_SECNAMES;
}
+#endif
else if (strcmp (name, ".sdata") == 0
|| strcmp (name, ".sbss") == 0
|| strcmp (name, ".lit4") == 0
|| strcmp (name, ".lit8") == 0)
hdr->sh_flags |= SHF_ALPHA_GPREL;
-#endif
return true;
}
+/* Return the number of additional phdrs we will need. */
+
static int
elf64_alpha_additional_program_headers (abfd)
bfd *abfd;
@@ -1059,62 +1010,40 @@ elf64_alpha_additional_program_headers (abfd)
return ret;
}
+/* Create the .got section. */
+
static boolean
elf64_alpha_create_got_section(abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
asection *s;
- struct elf_link_hash_entry *h;
if (bfd_get_section_by_name (abfd, ".got"))
return true;
- s = bfd_make_section(abfd, ".rela.got");
+ s = bfd_make_section (abfd, ".got");
if (s == NULL
|| !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_READONLY))
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED))
|| !bfd_set_section_alignment (abfd, s, 3))
return false;
- s = bfd_make_section(abfd, ".got");
- if (s == NULL
- || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY))
- || !bfd_set_section_alignment (abfd, s, 3))
- return false;
-
- s->_raw_size = RESERVED_GOT_ENTRIES * 8;
-
- /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
- (or .got.plt) section. We don't do this in the linker script
- because we don't want to define the symbol if we are not creating
- a global offset table. */
- h = NULL;
- if (!(_bfd_generic_link_add_one_symbol
- (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0,
- (const char *) NULL, false, get_elf_backend_data (abfd)->collect,
- (struct bfd_link_hash_entry **) &h)))
- return false;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
- h->type = STT_OBJECT;
-
- if (info->shared
- && ! _bfd_elf_link_record_dynamic_symbol (info, h))
- return false;
-
- elf_hash_table (info)->hgot = h;
+ alpha_elf_tdata (abfd)->got = s;
return true;
}
+/* Create all the dynamic sections. */
+
static boolean
elf64_alpha_create_dynamic_sections (abfd, info)
bfd *abfd;
struct bfd_link_info *info;
{
- register asection *s;
+ asection *s;
struct elf_link_hash_entry *h;
/* We need to create .plt, .rela.plt, .got, and .rela.got sections. */
@@ -1122,7 +1051,9 @@ elf64_alpha_create_dynamic_sections (abfd, info)
s = bfd_make_section (abfd, ".plt");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
| SEC_CODE))
|| ! bfd_set_section_alignment (abfd, s, 3))
return false;
@@ -1146,21 +1077,51 @@ elf64_alpha_create_dynamic_sections (abfd, info)
s = bfd_make_section (abfd, ".rela.plt");
if (s == NULL
|| !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_READONLY))
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY))
|| ! bfd_set_section_alignment (abfd, s, 3))
return false;
+ /* We may or may not have created a .got section for this object, but
+ we definitely havn't done the rest of the work. */
+
if (!elf64_alpha_create_got_section (abfd, info))
return false;
- return true;
-}
+ s = bfd_make_section(abfd, ".rela.got");
+ if (s == NULL
+ || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY))
+ || !bfd_set_section_alignment (abfd, s, 3))
+ return false;
-/* The structure of the runtile procedure descriptor created by the
- loader for use by the static exception system. */
+ /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the
+ dynobj's .got section. We don't do this in the linker script
+ because we don't want to define the symbol if we are not creating
+ a global offset table. */
+ h = NULL;
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL,
+ alpha_elf_tdata(abfd)->got, (bfd_vma) 0, (const char *) NULL,
+ false, get_elf_backend_data (abfd)->collect,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
-/* FIXME */
+ if (info->shared
+ && ! _bfd_elf_link_record_dynamic_symbol (info, h))
+ return false;
+
+ elf_hash_table (info)->hgot = h;
+
+ return true;
+}
/* Read ECOFF debugging information from a .mdebug section into a
ecoff_debug_info structure. */
@@ -1435,7 +1396,7 @@ elf64_alpha_output_extsym (h, data)
else
{
name = bfd_section_name (output_section->owner, output_section);
-
+
if (strcmp (name, ".text") == 0)
h->esym.asym.sc = scText;
else if (strcmp (name, ".data") == 0)
@@ -1485,23 +1446,23 @@ elf64_alpha_output_extsym (h, data)
{
/* Set type and value for a symbol with a function stub. */
h->esym.asym.st = stProc;
- sec = h->root.root.u.def.section;
+ sec = bfd_get_section_by_name (einfo->abfd, ".plt");
if (sec == NULL)
- h->esym.asym.value = 0;
+ h->esym.asym.value = 0;
else
- {
- output_section = sec->output_section;
- if (output_section != NULL)
- h->esym.asym.value = (h->root.plt_offset
- + sec->output_offset
- + output_section->vma);
- else
- h->esym.asym.value = 0;
- }
+ {
+ output_section = sec->output_section;
+ if (output_section != NULL)
+ h->esym.asym.value = (h->root.plt_offset
+ + sec->output_offset
+ + output_section->vma);
+ else
+ h->esym.asym.value = 0;
+ }
#if 0 /* FIXME? */
h->esym.ifd = 0;
#endif
- }
+ }
if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
h->root.root.root.string,
@@ -1523,9 +1484,10 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug)
struct bfd_link_info *info;
asection *s;
struct ecoff_debug_info *debug;
- */
-
+*/
+/* Handle dynamic relocations when doing an Alpha ELF link. */
+
static boolean
elf64_alpha_check_relocs (abfd, info, sec, relocs)
bfd *abfd;
@@ -1534,152 +1496,173 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
const Elf_Internal_Rela *relocs;
{
bfd *dynobj;
- asection *sgot;
- asection *srelgot;
asection *sreloc;
+ const char *rel_sec_name;
Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
+ 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;
if (info->relocateable)
return true;
- sgot = srelgot = sreloc = NULL;
- symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes(abfd);
dynobj = elf_hash_table(info)->dynobj;
- if (dynobj)
- {
- sgot = bfd_get_section_by_name(dynobj, ".got");
- srelgot = bfd_get_section_by_name(dynobj, ".rela.got");
- }
+ if (dynobj == NULL)
+ elf_hash_table(info)->dynobj = dynobj = abfd;
+
+ sreloc = NULL;
+ 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;
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; ++rel)
{
- unsigned long r_symndx;
+ unsigned long r_symndx, r_type;
struct alpha_elf_link_hash_entry *h;
r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
- h = ((struct alpha_elf_link_hash_entry *)
- sym_hashes[r_symndx - symtab_hdr->sh_info]);
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ h->root.elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+ }
+ r_type = ELF64_R_TYPE (rel->r_info);
- switch (ELF64_R_TYPE (rel->r_info))
+ switch (r_type)
{
case R_ALPHA_LITERAL:
- /* If this is a load of a function symbol and we are building a
- shared library or calling a shared library, then we need a
- .plt entry as well.
+ {
+ struct alpha_elf_got_entry *gotent;
+ int flags = 0;
- We can tell if it is a function either by noticing the
- type of the symbol, or, if the type is undefined, by
- noticing that we have a LITUSE(3) reloc next.
+ 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)
+ {
+ gotent = ((struct alpha_elf_got_entry *)
+ bfd_alloc (abfd,
+ sizeof (struct alpha_elf_got_entry)));
+ if (!gotent)
+ return false;
- Note that it is not fatal to be wrong guessing that a symbol
- is an object, but it is fatal to be wrong guessing that a
- symbol is a function.
+ gotent->gotobj = abfd;
+ gotent->addend = rel->r_addend;
+ gotent->got_offset = -1;
+ gotent->flags = 0;
- Furthermore, the .plt trampoline does not give constant
- function addresses, so if we ever see a function's address
- taken, we cannot do lazy binding on that function. */
+ gotent->next = h->got_entries;
+ h->got_entries = gotent;
- if (h)
- {
- if (rel+1 < relend
- && ELF64_R_TYPE (rel[1].r_info) == R_ALPHA_LITUSE)
- {
- switch (rel[1].r_addend)
- {
- case 1: /* Memory reference */
- h->flags |= ALPHA_ELF_LINK_HASH_LU_MEM;
- break;
- case 3: /* Call reference */
- h->flags |= ALPHA_ELF_LINK_HASH_LU_FUNC;
- break;
- }
- }
- else
- h->flags |= ALPHA_ELF_LINK_HASH_LU_ADDR;
-
- if (h->root.root.type != bfd_link_hash_undefweak
- && (info->shared
- || !(h->root.elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR))
- && (h->root.type == STT_FUNC
- || (h->root.type == STT_NOTYPE
- && (h->flags & ALPHA_ELF_LINK_HASH_LU_FUNC))))
- {
- h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
- }
- }
+ alpha_elf_tdata (abfd)->total_got_entries++;
+ }
+ }
+ else
+ {
+ /* This is a local .got entry -- record for merge. */
+ if (!local_got_entries)
+ {
+ size_t size;
+ size = (symtab_hdr->sh_info
+ * sizeof (struct alpha_elf_got_entry *));
+
+ local_got_entries = ((struct alpha_elf_got_entry **)
+ bfd_alloc (abfd, size));
+ if (!local_got_entries)
+ return false;
- if (dynobj == NULL)
- {
- elf_hash_table(info)->dynobj = dynobj = abfd;
+ memset (local_got_entries, 0, size);
+ alpha_elf_tdata (abfd)->local_got_entries =
+ local_got_entries;
+ }
- /* Create the .got section. */
- if (!elf64_alpha_create_got_section(dynobj, info))
- return false;
+ for (gotent = local_got_entries[ELF64_R_SYM(rel->r_info)];
+ gotent != NULL && gotent->addend != rel->r_addend;
+ gotent = gotent->next)
+ continue;
+ if (!gotent)
+ {
+ gotent = ((struct alpha_elf_got_entry *)
+ bfd_alloc (abfd,
+ sizeof (struct alpha_elf_got_entry)));
+ if (!gotent)
+ return false;
- sgot = bfd_get_section_by_name(dynobj, ".got");
- srelgot = bfd_get_section_by_name(dynobj, ".rela.got");
- }
+ gotent->gotobj = abfd;
+ gotent->addend = rel->r_addend;
+ gotent->got_offset = -1;
+ gotent->flags = 0;
- if (h != NULL)
- {
- if (h->root.got_offset != MINUS_ONE)
- {
- /* We have already allocated space in this .got. */
- break;
- }
+ gotent->next = local_got_entries[ELF64_R_SYM(rel->r_info)];
+ local_got_entries[ELF64_R_SYM(rel->r_info)] = gotent;
- /* Make sure this becomes a dynamic symbol. */
- if (h->root.dynindx == -1
- && ! _bfd_elf_link_record_dynamic_symbol (info, &h->root))
- return false;
+ alpha_elf_tdata(abfd)->total_got_entries++;
+ alpha_elf_tdata(abfd)->n_local_got_entries++;
+ }
+ }
- /* Reserve space for a reloc even if we won't use it. */
- srelgot->_raw_size += sizeof(Elf64_External_Rela);
+ /* 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;
+ }
- /* Create the relocation in adjust_dynamic_symbol */
+ 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 */
- h->root.got_offset = sgot->_raw_size;
- sgot->_raw_size += 8;
- }
- else
+ case R_ALPHA_GPDISP:
+ case R_ALPHA_GPREL32:
+ /* We don't actually use the .got here, but the sections must
+ be created before the linker maps input sections to output
+ sections. */
+ if (!got_created)
{
- bfd_vma *lgotoff = elf_local_got_offsets(abfd);
- if (lgotoff == NULL)
- {
- size_t size;
-
- size = elf_tdata(abfd)->symtab_hdr.sh_info * sizeof(bfd_vma);
- lgotoff = (bfd_vma *)bfd_alloc(abfd, size);
- if (lgotoff == NULL)
- return false;
-
- elf_local_got_offsets(abfd) = lgotoff;
- memset(lgotoff, -1, size);
- }
+ if (!elf64_alpha_create_got_section (abfd, info))
+ return false;
- if (lgotoff[ELF64_R_SYM(rel->r_info)] != MINUS_ONE)
- {
- /* We have already allocated space in the .got. */
- break;
- }
- lgotoff[ELF64_R_SYM(rel->r_info)] = sgot->_raw_size;
- sgot->_raw_size += 8;
+ /* Make sure the object's gotobj is set to itself so
+ that we default to every object with its own .got.
+ We'll merge .gots later once we've collected each
+ object's info. */
+ alpha_elf_tdata(abfd)->gotobj = abfd;
- if (info->shared)
- {
- /* If we are generating a shared object, we need to
- output a R_ALPHA_RELATIVE reloc so that the dynamic
- linker can adjust this GOT entry. */
- srelgot->_raw_size += sizeof(Elf64_External_Rela);
- }
+ got_created = 1;
}
break;
@@ -1692,42 +1675,76 @@ elf64_alpha_check_relocs (abfd, info, sec, relocs)
case R_ALPHA_REFLONG:
case R_ALPHA_REFQUAD:
- if (info->shared
- || (h != NULL
- && !(h->root.elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR)))
+ if (rel_sec_name == NULL)
{
- /* When creating a shared object or referring to a symbol in
- a shared object, we must copy these relocs into the
- object file. We create a reloc section in dynobj and
- make room for the reloc. */
+ rel_sec_name = (bfd_elf_string_from_elf_section
+ (abfd, elf_elfheader(abfd)->e_shstrndx,
+ elf_section_data(sec)->rel_hdr.sh_name));
+ if (rel_sec_name == NULL)
+ return false;
+
+ BFD_ASSERT (strncmp (rel_sec_name, ".rela", 5) == 0
+ && strcmp (bfd_get_section_name (abfd, sec),
+ rel_sec_name+5) == 0);
+ }
+
+ /* We need to create the section here now whether we eventually
+ use it or not so that it gets mapped to an output section by
+ the linker. If not used, we'll kill it in
+ size_dynamic_sections. */
+ if (sreloc == NULL)
+ {
+ sreloc = bfd_get_section_by_name (dynobj, rel_sec_name);
if (sreloc == NULL)
{
- const char *name;
- name = (bfd_elf_string_from_elf_section
- (abfd, elf_elfheader(abfd)->e_shstrndx,
- elf_section_data(sec)->rel_hdr.sh_name));
- if (name == NULL)
+ sreloc = bfd_make_section (dynobj, rel_sec_name);
+ if (sreloc == NULL
+ || !bfd_set_section_flags (dynobj, sreloc,
+ (SEC_ALLOC|SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY))
+ || !bfd_set_section_alignment (dynobj, sreloc, 3))
return false;
+ }
+ }
- BFD_ASSERT (strncmp (name, ".rela", 5) == 0
- && strcmp (bfd_get_section_name (abfd, sec),
- name+5) == 0);
+ if (h)
+ {
+ /* Since we havn't seen all of the input symbols yet, we
+ don't know whether we'll actually need a dynamic relocation
+ entry for this reloc. So make a record of it. Once we
+ find out if this thing needs dynamic relocation we'll
+ expand the relocation sections by the appropriate amount. */
- sreloc = bfd_get_section_by_name (dynobj, name);
- if (sreloc == NULL)
- {
- sreloc = bfd_make_section (dynobj, name);
- if (sreloc == NULL
- || !bfd_set_section_flags (dynobj, sreloc,
- (SEC_ALLOC|SEC_LOAD
- |SEC_HAS_CONTENTS
- |SEC_IN_MEMORY
- |SEC_READONLY))
- || !bfd_set_section_alignment (dynobj, sreloc, 3))
- return false;
- }
+ struct alpha_elf_reloc_entry *rent;
+
+ for (rent = h->reloc_entries; rent; rent = rent->next)
+ if (rent->rtype == r_type && rent->srel == sreloc)
+ break;
+
+ if (!rent)
+ {
+ rent = ((struct alpha_elf_reloc_entry *)
+ bfd_alloc (abfd,
+ sizeof (struct alpha_elf_reloc_entry)));
+ if (!rent)
+ return false;
+
+ rent->srel = sreloc;
+ rent->rtype = r_type;
+ rent->count = 1;
+
+ rent->next = h->reloc_entries;
+ h->reloc_entries = rent;
}
+ else
+ rent->count++;
+ }
+ else if (info->shared)
+ {
+ /* If this is a shared library, we need a RELATIVE reloc. */
sreloc->_raw_size += sizeof (Elf64_External_Rela);
}
break;
@@ -1750,34 +1767,37 @@ elf64_alpha_adjust_dynamic_symbol (info, h)
{
bfd *dynobj;
asection *s;
-
- dynobj = elf_hash_table(info)->dynobj;
-
- /* If this is a function, put it in the procedure linkage table. We
- will fill in the contents of the procedure linkage table later,
- though we could actually do it here. */
+ struct alpha_elf_link_hash_entry *ah;
- if (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+ dynobj = elf_hash_table(info)->dynobj;
+ ah = (struct alpha_elf_link_hash_entry *)h;
+
+ /* Now that we've seen all of the input symbols, finalize our decision
+ about whether this symbol should get a .plt entry. */
+
+ if (h->root.type != bfd_link_hash_undefweak
+ && alpha_elf_dynamic_symbol_p (h, info)
+ && (h->type == STT_FUNC
+ || (h->type == STT_NOTYPE
+ && 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
+ somewhere later. But for now don't bother. */
+ && ah->got_entries)
{
- /* We hadn't seen all of the input symbols or all of the relocations
- when we guessed that we needed a .plt entry. Revise our decision. */
- if ((!info->shared
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
- || (((struct alpha_elf_link_hash_entry *) h)->flags
- & ALPHA_ELF_LINK_HASH_LU_ADDR))
- {
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
- return true;
- }
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
s = bfd_get_section_by_name(dynobj, ".plt");
- BFD_ASSERT(s != NULL);
+ if (!s && !elf64_alpha_create_dynamic_sections (dynobj, info))
+ return false;
/* The first bit of the .plt is reserved. */
if (s->_raw_size == 0)
s->_raw_size = PLT_HEADER_SIZE;
h->plt_offset = s->_raw_size;
+ s->_raw_size += PLT_ENTRY_SIZE;
/* If this symbol is not defined in a regular file, and we are not
generating a shared library, then set the symbol to the location
@@ -1786,18 +1806,18 @@ elf64_alpha_adjust_dynamic_symbol (info, h)
if (!info->shared)
{
h->root.u.def.section = s;
- h->root.u.def.value = s->_raw_size;
+ h->root.u.def.value = h->plt_offset;
}
- s->_raw_size += PLT_ENTRY_SIZE;
-
- /* We also need an entry in the .rela.plt section. */
- s = bfd_get_section_by_name(dynobj, ".rela.plt");
- BFD_ASSERT(s != NULL);
- s->_raw_size += sizeof(Elf64_External_Rela);
+ /* We also need a JMP_SLOT entry in the .rela.plt section. */
+ s = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (s != NULL);
+ s->_raw_size += sizeof (Elf64_External_Rela);
return true;
}
+ else
+ h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
@@ -1812,13 +1832,366 @@ elf64_alpha_adjust_dynamic_symbol (info, h)
}
/* This is a reference to a symbol defined by a dynamic object which
- is not a function. The Alpha, since it uses .got entries for
+ is not a function. The Alpha, since it uses .got entries for all
symbols even in regular objects, does not need the hackery of a
.dynbss section and COPY dynamic relocations. */
return true;
}
+/* Is it possible to merge two object file's .got tables? */
+
+static boolean
+elf64_alpha_can_merge_gots (a, b)
+ bfd *a, *b;
+{
+ int total = alpha_elf_tdata (a)->total_got_entries;
+
+ /* Trivial quick fallout test. */
+ if (total + alpha_elf_tdata (b)->total_got_entries <= MAX_GOT_ENTRIES)
+ return true;
+
+ /* By their nature, local .got entries cannot be merged. */
+ if ((total += alpha_elf_tdata (b)->n_local_got_entries) > MAX_GOT_ENTRIES)
+ return false;
+
+ /* Failing the common trivial comparison, we must effectively
+ perform the merge. Not actually performing the merge means that
+ we don't have to store undo information in case we fail. */
+ {
+ struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes(b);
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata(b)->symtab_hdr;
+ int i, n;
+
+ n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
+ for (i = 0; i < n; ++i)
+ {
+ struct alpha_elf_got_entry *ae, *be;
+ for (be = hashes[i]->got_entries; be ; be = be->next)
+ {
+ if (be->gotobj != b)
+ continue;
+
+ for (ae = hashes[i]->got_entries; ae ; ae = ae->next)
+ if (ae->gotobj == a && ae->addend == be->addend)
+ goto global_found;
+
+ if (++total > MAX_GOT_ENTRIES)
+ return false;
+ global_found:;
+ }
+ }
+ }
+
+ return true;
+}
+
+/* Actually merge two .got tables. */
+
+static void
+elf64_alpha_merge_gots (a, b)
+ bfd *a, *b;
+{
+ int total = alpha_elf_tdata(a)->total_got_entries;
+
+ /* Remember local expansion. */
+ {
+ int e = alpha_elf_tdata(b)->n_local_got_entries;
+ total += e;
+ alpha_elf_tdata(a)->n_local_got_entries += e;
+ }
+
+ /* Let the local .got entries know they are part of a new subsegment. */
+ {
+ struct alpha_elf_got_entry **local_got_entries;
+ local_got_entries = alpha_elf_tdata(b)->local_got_entries;
+ if (local_got_entries)
+ {
+ int i, n;
+
+ n = elf_tdata(b)->symtab_hdr.sh_info;
+ for (i = 0; i < n; ++i)
+ {
+ struct alpha_elf_got_entry *gotent;
+ for (gotent = local_got_entries[i]; gotent; gotent = gotent->next)
+ gotent->gotobj = a;
+ }
+ }
+ }
+
+ /* Merge the global .got entries. */
+ {
+ struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes(b);
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata(b)->symtab_hdr;
+ int i, n;
+
+ n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
+ for (i = 0; i < n; ++i)
+ {
+ struct alpha_elf_got_entry *ae, *be, **pbe, **start;
+ start = &hashes[i]->got_entries;
+ for (pbe = start, be = *start; be ; pbe = &be->next, be = be->next)
+ {
+ if (be->gotobj != b)
+ continue;
+
+ for (ae = *start; ae ; ae = ae->next)
+ if (ae->gotobj == a && ae->addend == be->addend)
+ {
+ *pbe = be->next;
+ goto global_found;
+ }
+ be->gotobj = a;
+ total += 1;
+
+ global_found:;
+ }
+ }
+ }
+
+ alpha_elf_tdata(a)->total_got_entries = total;
+ alpha_elf_tdata(b)->gotobj = a;
+}
+
+/* Calculate the offsets for the got entries. */
+
+static boolean
+elf64_alpha_calc_got_offsets_for_symbol (h, arg)
+ struct alpha_elf_link_hash_entry *h;
+ PTR arg;
+{
+ struct alpha_elf_got_entry *gotent;
+
+ for (gotent = h->got_entries; gotent; gotent = gotent->next)
+ {
+ bfd_size_type *plge = &alpha_elf_tdata (gotent->gotobj)->got->_raw_size;
+ gotent->got_offset = *plge;
+ *plge += 8;
+ }
+
+ return true;
+}
+
+static void
+elf64_alpha_calc_got_offsets (info)
+ struct bfd_link_info *info;
+{
+ bfd *i, *got_list = alpha_elf_hash_table(info)->got_list;
+
+ /* First, zero out the .got sizes, as we may be recalculating the
+ .got after optimizing it. */
+ for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
+ alpha_elf_tdata(i)->got->_raw_size = 0;
+
+ /* Next, fill in the offsets for all the global entries. */
+ alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ elf64_alpha_calc_got_offsets_for_symbol,
+ NULL);
+
+ /* Finally, fill in the offsets for the local entries. */
+ for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
+ {
+ bfd_size_type got_offset = alpha_elf_tdata(i)->got->_raw_size;
+ bfd *j;
+
+ 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)
+ {
+ gotent->got_offset = got_offset;
+ got_offset += 8;
+ }
+ }
+
+ alpha_elf_tdata(i)->got->_raw_size = got_offset;
+ }
+}
+
+/* Remove a section from the output BFD. */
+
+static void
+elf64_alpha_strip_section_from_output (s)
+ asection *s;
+{
+ asection **spp;
+
+ for (spp = &s->output_section->owner->sections;
+ *spp != s->output_section;
+ spp = &(*spp)->next)
+ continue;
+ *spp = s->output_section->next;
+ --s->output_section->owner->section_count;
+}
+
+/* Constructs the gots. */
+
+static boolean
+elf64_alpha_always_size_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ bfd *i, *got_list, *cur_got_obj, **cur_got_tail;
+ int ngots;
+
+ if (info->relocateable)
+ return true;
+
+ ngots = 0;
+ got_list = NULL;
+ cur_got_obj = NULL;
+ cur_got_tail = NULL;
+ for (i = info->input_bfds; i ; i = i->link_next)
+ {
+ bfd *this_got = alpha_elf_tdata (i)->gotobj;
+
+ /* Don't play if there is no .got for this input file. */
+ if (this_got == NULL)
+ continue;
+
+ if (alpha_elf_tdata (this_got)->total_got_entries > MAX_GOT_ENTRIES)
+ {
+ /* Yikes! A single object file has too many entries. */
+ (*_bfd_error_handler)
+ ("%s: .got subsegment exceeds 64K (size %d)",
+ bfd_get_filename(i),
+ alpha_elf_tdata(this_got)->total_got_entries * 8);
+ return false;
+ }
+
+ if (cur_got_obj)
+ {
+ if (elf64_alpha_can_merge_gots (cur_got_obj, i))
+ {
+ elf64_alpha_merge_gots (cur_got_obj, i);
+ *cur_got_tail = i;
+ }
+ else
+ {
+ if (++ngots == 2)
+ {
+ (*info->callbacks->warning)
+ (info, "using multiple gp values", (char *) NULL,
+ output_bfd, (asection *) NULL, (bfd_vma) 0);
+ }
+ *cur_got_tail = NULL;
+ alpha_elf_tdata(cur_got_obj)->got_link_next = got_list;
+ got_list = cur_got_obj;
+ cur_got_obj = i;
+ }
+ }
+ else
+ {
+ ++ngots;
+ cur_got_obj = i;
+ }
+ cur_got_tail = &alpha_elf_tdata(i)->in_got_link_next;
+ }
+
+ if (cur_got_obj)
+ alpha_elf_tdata (cur_got_obj)->got_link_next = got_list;
+ alpha_elf_hash_table (info)->got_list = got_list = cur_got_obj;
+
+ /* Once the gots have been merged, fill in the got offsets for everything
+ therein. */
+ elf64_alpha_calc_got_offsets (info);
+
+ /* Allocate space for all of the .got subsections. */
+ for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
+ {
+ asection *s = alpha_elf_tdata(i)->got;
+ if (s->_raw_size > 0)
+ {
+ s->contents = (bfd_byte *) bfd_zalloc (i, s->_raw_size);
+ if (s->contents == NULL)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Work out the sizes of the dynamic relocation entries. */
+
+static boolean
+elf64_alpha_calc_dynrel_sizes (h, info)
+ struct alpha_elf_link_hash_entry *h;
+ struct bfd_link_info *info;
+{
+ /* If the symbol was defined as a common symbol in a regular object
+ file, and there was no definition in any dynamic object, then the
+ linker will have allocated space for the symbol in a common
+ section but the ELF_LINK_HASH_DEF_REGULAR flag will not have been
+ set. This is done for dynamic symbols in
+ elf_adjust_dynamic_symbol but this is not done for non-dynamic
+ symbols, somehow. */
+ if (((h->root.elf_link_hash_flags
+ & (ELF_LINK_HASH_DEF_REGULAR
+ | ELF_LINK_HASH_REF_REGULAR
+ | ELF_LINK_HASH_DEF_DYNAMIC))
+ == ELF_LINK_HASH_REF_REGULAR)
+ && (h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak)
+ && !(h->root.root.u.def.section->owner->flags & DYNAMIC))
+ {
+ h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ }
+
+ /* If the symbol is dynamic, we'll need all the relocations in their
+ natural form. */
+ if (alpha_elf_dynamic_symbol_p (&h->root, info))
+ {
+ struct alpha_elf_reloc_entry *relent;
+
+ for (relent = h->reloc_entries; relent; relent = relent->next)
+ {
+ relent->srel->_raw_size +=
+ sizeof (Elf64_External_Rela) * relent->count;
+ }
+
+ /* Only add a .rela.got entry if we're not using a .plt entry. */
+ if (h->root.plt_offset == MINUS_ONE)
+ {
+ bfd *dynobj = elf_hash_table(info)->dynobj;
+ struct alpha_elf_got_entry *gotent;
+ bfd_size_type count = 0;
+ asection *srel;
+
+ for (gotent = h->got_entries; gotent ; gotent = gotent->next)
+ count++;
+ if (count > 0)
+ {
+ srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srel != NULL);
+ srel->_raw_size += sizeof (Elf64_External_Rela) * count;
+ }
+ }
+ }
+ /* Otherwise, shared objects require RELATIVE relocs for all REFQUAD
+ and REFLONG relocations. */
+ else if (info->shared)
+ {
+ struct alpha_elf_reloc_entry *relent;
+
+ 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;
+ }
+ }
+
+ return true;
+}
+
/* Set the sizes of the dynamic sections. */
static boolean
@@ -1834,28 +2207,45 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
dynobj = elf_hash_table(info)->dynobj;
BFD_ASSERT(dynobj != NULL);
- if (elf_hash_table(info)->dynamic_sections_created)
+ if (elf_hash_table (info)->dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
if (!info->shared)
{
- s = bfd_get_section_by_name(dynobj, ".interp");
- BFD_ASSERT(s != NULL);
+ s = bfd_get_section_by_name (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
- s->contents = (unsigned char *)ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ }
+
+ /* Now that we've seen all of the input files, we can decide which
+ symbols need dynamic relocation entries and which don't. We've
+ collected information in check_relocs that we can now apply to
+ size the dynamic relocation sections. */
+ alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ elf64_alpha_calc_dynrel_sizes,
+ info);
+
+ /* When building shared libraries, each local .got entry needs a
+ RELATIVE reloc. */
+ if (info->shared)
+ {
+ bfd *i;
+ asection *srel;
+ bfd_size_type count;
+
+ srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srel != NULL);
+
+ 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;
+
+ srel->_raw_size += count * sizeof(Elf64_External_Rela);
}
}
- else
- {
- /* We may have created entries in the .rela.got section.
- However, if we are not creating the dynamic sections, we will
- not actually use these entries. Reset the size of .rel.got,
- which will cause it to get stripped from the output file
- below. */
- s = bfd_get_section_by_name (dynobj, ".rela.got");
- if (s != NULL)
- s->_raw_size = 0;
- }
+ /* else we're not dynamic and by definition we don't need such things. */
/* The check_relocs and adjust_dynamic_symbol entry points have
determined the sizes of the various dynamic sections. Allocate
@@ -1867,12 +2257,12 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
const char *name;
boolean strip;
- if (!(s->flags & SEC_IN_MEMORY))
+ if (!(s->flags & SEC_LINKER_CREATED))
continue;
/* It's OK to base decisions on the section name, because none
of the dynobj section names depend upon the input files. */
- name = bfd_get_section_name(dynobj, s);
+ name = bfd_get_section_name (dynobj, s);
/* If we don't need this section, strip it from the output file.
This is to handle .rela.bss and .rela.plt. We must create it
@@ -1884,7 +2274,7 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
strip = false;
- if (strncmp(name, ".rela", 5) == 0)
+ if (strncmp (name, ".rela", 5) == 0)
{
strip = (s->_raw_size == 0);
@@ -1907,60 +2297,49 @@ elf64_alpha_size_dynamic_sections (output_bfd, info)
s->reloc_count = 0;
}
}
- else if (strcmp(name, ".got") == 0)
- {
- /* If we are generating a shared library, we generate a
- section symbol for each output section. These are local
- symbols, which means that they must come first in the
- dynamic symbol table. That means we must increment the
- dynamic symbol index of every other dynamic symbol. */
- if (info->shared)
- {
- long c[2], i;
- asection *p;
-
- c[0] = 0;
- c[1] = bfd_count_sections(output_bfd);
-
- elf_link_hash_traverse (elf_hash_table(info),
- elf64_alpha_adjust_dynindx,
- (PTR)c);
- elf_hash_table (info)->dynsymcount += c[1];
-
- for (i = 1, p = output_bfd->sections;
- p != NULL;
- p = p->next, i++)
- {
- elf_section_data (p)->dynindx = i;
- /* These symbols will have no names, so we don't need to
- fiddle with dynstr_index. */
- }
- }
- }
else if (strcmp (name, ".plt") != 0)
{
- /* It's not one of our sections, so don't allocate space. */
+ /* It's not one of our dynamic sections, so don't allocate space. */
continue;
}
if (strip)
+ elf64_alpha_strip_section_from_output (s);
+ else
{
- asection **spp;
+ /* Allocate memory for the section contents. */
+ s->contents = (bfd_byte *) bfd_zalloc(dynobj, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ return false;
+ }
+ }
- for (spp = &s->output_section->owner->sections;
- *spp != s->output_section;
- spp = &(*spp)->next)
- continue;
- *spp = s->output_section->next;
- --s->output_section->owner->section_count;
+ /* If we are generating a shared library, we generate a section
+ symbol for each output section. These are local symbols, which
+ means that they must come first in the dynamic symbol table.
+ That means we must increment the dynamic symbol index of every
+ other dynamic symbol. */
+ if (info->shared)
+ {
+ long c[2], i;
+ asection *p;
- continue;
- }
+ c[0] = 0;
+ c[1] = bfd_count_sections (output_bfd);
- /* Allocate memory for the section contents. */
- s->contents = (bfd_byte *) bfd_zalloc(dynobj, s->_raw_size);
- if (s->contents == NULL && s->_raw_size != 0)
- return false;
+ elf_hash_table (info)->dynsymcount += c[1];
+ elf_link_hash_traverse (elf_hash_table(info),
+ elf64_alpha_adjust_dynindx,
+ (PTR) c);
+
+ for (i = 1, p = output_bfd->sections;
+ p != NULL;
+ p = p->next, i++)
+ {
+ elf_section_data (p)->dynindx = i;
+ /* These symbols will have no names, so we don't need to
+ fiddle with dynstr_index. */
+ }
}
if (elf_hash_table (info)->dynamic_sections_created)
@@ -2036,28 +2415,32 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
- asection *sec, *sgot, *splt;
- bfd *dynobj;
+ asection *sec, *sgot, *srel, *srelgot;
+ bfd *dynobj, *gotobj;
bfd_vma gp;
- symtab_hdr = &elf_tdata(input_bfd)->symtab_hdr;
+ srelgot = srel = NULL;
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj)
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ }
/* Find the gp value for this input bfd. */
sgot = NULL;
gp = 0;
- dynobj = elf_hash_table(info)->dynobj;
- if (dynobj)
+ gotobj = alpha_elf_tdata (input_bfd)->gotobj;
+ if (gotobj)
{
- sgot = bfd_get_section_by_name (dynobj, ".got");
- splt = bfd_get_section_by_name (dynobj, ".plt");
-
- gp = _bfd_get_gp_value(dynobj);
+ 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(dynobj, gp);
+ _bfd_set_gp_value (gotobj, gp);
}
}
@@ -2068,7 +2451,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
int r_type;
reloc_howto_type *howto;
unsigned long r_symndx;
- struct elf_link_hash_entry *h;
+ struct alpha_elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
bfd_vma relocation;
bfd_vma addend;
@@ -2119,43 +2502,27 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
}
else
{
- h = elf_sym_hashes(input_bfd)[r_symndx - symtab_hdr->sh_info];
+ h = alpha_elf_sym_hashes (input_bfd)[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *)h->root.u.i.link;
+ while (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
+ if (h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak)
{
- sec = h->root.u.def.section;
-
- /* If the symbol was defined as a common symbol in a
- regular object file, and there was no definition in
- any dynamic object, then the linker will have
- allocated space for the symbol in a common section
- but the ELF_LINK_HASH_DEF_REGULAR flag will not have
- been set. This is done for dynamic symbols in
- elf_adjust_dynamic_symbol but this is not done for
- non-dynamic symbols, somehow. */
- if ((h->elf_link_hash_flags
- & (ELF_LINK_HASH_DEF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_DEF_DYNAMIC))
- == ELF_LINK_HASH_REF_REGULAR
- && !(sec->owner->flags & DYNAMIC))
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ sec = h->root.root.u.def.section;
#if rth_notdef
if ((r_type == R_ALPHA_LITERAL
&& elf_hash_table(info)->dynamic_sections_created
&& (!info->shared
|| !info->symbolic
- || !(h->elf_link_hash_flags
+ || !(h->root.elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR)))
|| (info->shared
&& (!info->symbolic
- || !(h->elf_link_hash_flags
+ || !(h->root.elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR))
&& (input_section->flags & SEC_ALLOC)
&& (r_type == R_ALPHA_REFLONG
@@ -2175,19 +2542,19 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
#endif /* rth_notdef */
else
{
- relocation = (h->root.u.def.value
+ relocation = (h->root.root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
}
- else if (h->root.type == bfd_link_hash_undefweak)
+ else if (h->root.root.type == bfd_link_hash_undefweak)
relocation = 0;
else if (info->shared && !info->symbolic)
relocation = 0;
else
{
if (!((*info->callbacks->undefined_symbol)
- (info, h->root.root.string, input_bfd,
+ (info, h->root.root.root.string, input_bfd,
input_section, rel->r_offset)))
return false;
relocation = 0;
@@ -2201,6 +2568,8 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
{
bfd_byte *p_ldah, *p_lda;
+ BFD_ASSERT(gp != 0);
+
relocation = (input_section->output_section->vma
+ input_section->output_offset
+ rel->r_offset);
@@ -2217,63 +2586,80 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
case R_ALPHA_OP_STORE:
case R_ALPHA_OP_PSUB:
case R_ALPHA_OP_PRSHIFT:
- /* FIXME */
+ /* We hate these silly beasts. */
abort();
case R_ALPHA_LITERAL:
{
- bfd_vma gotoff;
+ struct alpha_elf_got_entry *gotent;
- BFD_ASSERT(gp != 0);
BFD_ASSERT(sgot != NULL);
+ BFD_ASSERT(gp != 0);
+
if (h != NULL)
{
- gotoff = h->got_offset;
- }
- else
- {
- gotoff = elf_local_got_offsets (input_bfd)[r_symndx];
+ gotent = h->got_entries;
+ while (gotent->gotobj != gotobj || gotent->addend != addend)
+ gotent = gotent->next;
- /* Use the lsb as a flag indicating that we've already
- output the relocation entry. */
- if (info->shared)
- if (gotoff & 1)
- gotoff &= ~(bfd_vma)1;
- else
- {
- asection *srel;
- 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);
- srel = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT(srel != NULL);
+ /* The dynamic relocations for the .got entries are
+ done in finish_dynamic_symbol. */
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset + gotoff);
- outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
- outrel.r_addend = 0;
-
- bfd_elf64_swap_reloca_out (output_bfd, &outrel,
- ((Elf64_External_Rela *)
- srel->contents)
- + srel->reloc_count++);
-
- elf_local_got_offsets (input_bfd)[r_symndx] |= 1;
- }
+ gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
+ }
+ }
+ else
+ {
+ gotent = (alpha_elf_tdata(input_bfd)->
+ local_got_entries[r_symndx]);
+ while (gotent->addend != addend)
+ gotent = gotent->next;
+
+ if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
+ {
+ bfd_put_64 (output_bfd, relocation+addend,
+ sgot->contents + gotent->got_offset);
+
+ /* Local got entries need RELATIVE relocs in shared
+ libraries. */
+ if (info->shared)
+ {
+ 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 = 0;
+
+ bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+ ((Elf64_External_Rela *)
+ srelgot->contents)
+ + srelgot->reloc_count++);
+ }
+
+ gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
+ }
}
-
- /* Initialize the .got entry. */
- bfd_put_64 (output_bfd, relocation, sgot->contents + gotoff);
/* Figure the gprel relocation. */
addend = 0;
relocation = (sgot->output_section->vma
+ sgot->output_offset
- + gotoff);
+ + gotent->got_offset);
relocation -= gp;
}
/* overflow handled by _bfd_final_link_relocate */
goto default_reloc;
-
+
case R_ALPHA_GPREL32:
BFD_ASSERT(gp != 0);
relocation -= gp;
@@ -2285,44 +2671,52 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
the instruction rather than the end. */
addend -= 4;
goto default_reloc;
-
+
case R_ALPHA_REFLONG:
case R_ALPHA_REFQUAD:
- if (info->shared
- || (h && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
- {
- asection *srel;
- const char *name;
- Elf_Internal_Rela outrel;
-
- 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);
-
- outrel.r_offset = (input_section->output_section->vma
- + input_section->output_offset
- + rel->r_offset);
- outrel.r_addend = 0;
- if (h)
- {
- BFD_ASSERT(h->dynindx != -1);
- outrel.r_info = ELF64_R_INFO(h->dynindx, r_type);
- relocation = 0;
- }
- else
- {
- outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
- }
+ {
+ Elf_Internal_Rela outrel;
- bfd_elf64_swap_reloca_out (output_bfd, &outrel,
- ((Elf64_External_Rela *)
- srel->contents)
- + srel->reloc_count++);
- }
+ /* Careful here to remember RELATIVE relocations for global
+ variables for symbolic shared objects. */
+
+ if (h && alpha_elf_dynamic_symbol_p (&h->root, info))
+ {
+ BFD_ASSERT(h->root.dynindx != -1);
+ outrel.r_info = ELF64_R_INFO(h->root.dynindx, r_type);
+ outrel.r_addend = addend;
+ addend = 0, relocation = 0;
+ }
+ else if (info->shared)
+ {
+ outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
+ outrel.r_addend = 0;
+ }
+ 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);
+ }
+
+ outrel.r_offset = (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+
+ bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+ ((Elf64_External_Rela *)
+ srel->contents)
+ + srel->reloc_count++);
+ }
goto default_reloc;
default:
@@ -2343,7 +2737,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section,
const char *name;
if (h != NULL)
- name = h->root.root.string;
+ name = h->root.root.root.string;
else
{
name = (bfd_elf_string_from_elf_section
@@ -2383,26 +2777,30 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
if (h->plt_offset != MINUS_ONE)
{
+ /* Fill in the .plt entry for this symbol. */
asection *splt, *sgot, *srel;
Elf_Internal_Rela outrel;
bfd_vma got_addr, plt_addr;
bfd_vma plt_index;
+ struct alpha_elf_got_entry *gotent;
- /* This symbol has an entry in the procedure linkage table. */
+ BFD_ASSERT (h->dynindx != -1);
- BFD_ASSERT(h->dynindx != -1);
- BFD_ASSERT(h->got_offset != MINUS_ONE);
+ /* The first .got entry will be updated by the .plt with the
+ address of the target function. */
+ gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
+ BFD_ASSERT (gotent && gotent->addend == 0);
- splt = bfd_get_section_by_name(dynobj, ".plt");
- BFD_ASSERT(splt != NULL);
- srel = bfd_get_section_by_name(dynobj, ".rela.plt");
- BFD_ASSERT(srel != NULL);
- sgot = bfd_get_section_by_name(dynobj, ".got");
- BFD_ASSERT(sgot != NULL);
+ splt = bfd_get_section_by_name (dynobj, ".plt");
+ BFD_ASSERT (splt != NULL);
+ srel = bfd_get_section_by_name (dynobj, ".rela.plt");
+ BFD_ASSERT (srel != NULL);
+ sgot = alpha_elf_tdata (gotent->gotobj)->got;
+ BFD_ASSERT (sgot != NULL);
got_addr = (sgot->output_section->vma
- + sgot->output_offset
- + h->got_offset);
+ + sgot->output_offset
+ + gotent->got_offset);
plt_addr = (splt->output_section->vma
+ splt->output_offset
+ h->plt_offset);
@@ -2422,7 +2820,7 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
insn1 = PLT_ENTRY_WORD1 | (hi & 0xffff);
insn2 = PLT_ENTRY_WORD2 | (lo & 0xffff);
insn3 = PLT_ENTRY_WORD3 | ((-(h->plt_offset + 12) >> 2) & 0x1fffff);
-
+
bfd_put_32 (output_bfd, insn1, splt->contents + h->plt_offset);
bfd_put_32 (output_bfd, insn2, splt->contents + h->plt_offset + 4);
bfd_put_32 (output_bfd, insn3, splt->contents + h->plt_offset + 8);
@@ -2444,38 +2842,45 @@ elf64_alpha_finish_dynamic_symbol (output_bfd, info, h, sym)
sym->st_shndx = SHN_UNDEF;
}
- /* Fill in the entry in the global offset table. */
- bfd_put_64 (output_bfd, plt_addr, sgot->contents + h->got_offset);
+ /* Fill in the entries in the .got. */
+ bfd_put_64 (output_bfd, plt_addr, sgot->contents + gotent->got_offset);
+
+ /* Subsequent .got entries will continue to bounce through the .plt. */
+ while ((gotent = gotent->next) != NULL)
+ {
+ sgot = alpha_elf_tdata(gotent->gotobj)->got;
+ BFD_ASSERT(sgot != NULL);
+ BFD_ASSERT(gotent->addend == 0);
+
+ bfd_put_64 (output_bfd, plt_addr,
+ sgot->contents + gotent->got_offset);
+ }
}
- else if (h->got_offset != MINUS_ONE)
+ else if (alpha_elf_dynamic_symbol_p (h, info))
{
- asection *sgot, *srel;
+ /* Fill in the dynamic relocations for this symbol's .got entries. */
+ asection *srel;
Elf_Internal_Rela outrel;
+ struct alpha_elf_got_entry *gotent;
- BFD_ASSERT(h->dynindx != -1);
-
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
srel = bfd_get_section_by_name (dynobj, ".rela.got");
BFD_ASSERT (srel != NULL);
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + h->got_offset);
- outrel.r_addend = 0;
- if (info->shared
- && info->symbolic
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
- outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
- else
+ 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)
{
- bfd_put_64(output_bfd, (bfd_vma)0, sgot->contents + h->got_offset);
- outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_GLOB_DAT);
+ asection *sgot = alpha_elf_tdata (gotent->gotobj)->got;
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + gotent->got_offset);
+ outrel.r_addend = gotent->addend;
+
+ bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+ ((Elf64_External_Rela *)srel->contents
+ + srel->reloc_count++));
}
-
- bfd_elf64_swap_reloca_out (output_bfd, &outrel,
- ((Elf64_External_Rela *)srel->contents
- + srel->reloc_count++));
}
/* Mark some specially defined symbols as absolute. */
@@ -2496,7 +2901,6 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
{
bfd *dynobj;
asection *sdyn;
- asection *sgot;
dynobj = elf_hash_table (info)->dynobj;
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
@@ -2534,8 +2938,8 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
case DT_RELASZ:
/* My interpretation of the TIS v1.1 ELF document indicates
that RELASZ should not include JMPREL. This is not what
- the rest of the BFD does. It is, however, what the
- glibc ld.so wants. Do this fixup here until we found
+ the rest of the BFD does. It is, however, what the
+ glibc ld.so wants. Do this fixup here until we found
out who is right. */
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
if (s)
@@ -2567,32 +2971,16 @@ elf64_alpha_finish_dynamic_sections (output_bfd, info)
bfd_put_32 (output_bfd, PLT_HEADER_WORD2, splt->contents + 4);
bfd_put_32 (output_bfd, PLT_HEADER_WORD3, splt->contents + 8);
bfd_put_32 (output_bfd, PLT_HEADER_WORD4, splt->contents + 12);
-
+
/* The next two words will be filled in by ld.so */
bfd_put_64 (output_bfd, 0, splt->contents + 16);
bfd_put_64 (output_bfd, 0, splt->contents + 24);
- elf_section_data (splt->output_section)->this_hdr.sh_entsize =
+ elf_section_data (splt->output_section)->this_hdr.sh_entsize =
PLT_HEADER_SIZE;
}
}
- /* Set the first entry in the global offset table to the address of
- the dynamic section. */
- sgot = bfd_get_section_by_name (dynobj, ".got");
- if (sgot && sgot->_raw_size > 0)
- {
- if (sdyn == NULL)
- bfd_put_64 (output_bfd, (bfd_vma)0, sgot->contents);
- else
- bfd_put_64 (output_bfd,
- sdyn->output_section->vma + sdyn->output_offset,
- sgot->contents);
-
- elf_section_data (sgot->output_section)->this_hdr.sh_entsize =
- 8 * RESERVED_GOT_ENTRIES;
- }
-
if (info->shared)
{
asection *sdynsym;
@@ -2801,7 +3189,7 @@ elf64_alpha_final_link (abfd, info)
}
else
esym.asym.value = last;
-
+
if (! bfd_ecoff_debug_one_external (abfd, &debug, swap,
name[i], &esym))
return false;
@@ -2919,7 +3307,9 @@ elf64_alpha_final_link (abfd, info)
rtproc_sec = bfd_get_section_by_name (abfd, ".rtproc");
if (rtproc_sec == NULL)
{
- flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ flagword flags = (SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
| SEC_READONLY);
rtproc_sec = bfd_make_section (abfd, ".rtproc");
@@ -3188,6 +3578,27 @@ elf64_alpha_final_link (abfd, info)
/* Now write out the computed sections. */
+ /* The .got subsections... */
+ {
+ bfd *i, *dynobj = elf_hash_table(info)->dynobj;
+ for (i = alpha_elf_hash_table(info)->got_list;
+ i != NULL;
+ i = alpha_elf_tdata(i)->got_link_next)
+ {
+ asection *sgot;
+
+ /* elf_bfd_final_link already did everything in dynobj. */
+ if (i == dynobj)
+ continue;
+
+ sgot = alpha_elf_tdata(i)->got;
+ if (! bfd_set_section_contents (abfd, sgot->output_section,
+ sgot->contents, sgot->output_offset,
+ sgot->_raw_size))
+ return false;
+ }
+ }
+
#ifdef ERIC_neverdef
if (reginfo_sec != (asection *) NULL)
{
@@ -3291,8 +3702,11 @@ elf64_alpha_ecoff_debug_swap =
#define elf_info_to_howto \
elf64_alpha_info_to_howto
+#define bfd_elf64_mkobject \
+ elf64_alpha_mkobject
+
#define elf_backend_object_p \
- elf64_alpha_object_p
+ elf64_alpha_object_p
#define elf_backend_section_from_shdr \
elf64_alpha_section_from_shdr
#define elf_backend_fake_sections \
@@ -3311,6 +3725,8 @@ elf64_alpha_ecoff_debug_swap =
elf64_alpha_create_dynamic_sections
#define elf_backend_adjust_dynamic_symbol \
elf64_alpha_adjust_dynamic_symbol
+#define elf_backend_always_size_sections \
+ elf64_alpha_always_size_sections
#define elf_backend_size_dynamic_sections \
elf64_alpha_size_dynamic_sections
#define elf_backend_relocate_section \