static const bfd_byte elf_m68k_plt0_entry[PLT_ENTRY_SIZE] =
{
0x2f, 0x3b, 0x01, 0x70, /* move.l (%pc,addr),-(%sp) */
- 0, 0, 0, 0, /* replaced with address of .got + 4. */
+ 0, 0, 0, 0, /* replaced with offset to .got + 4. */
0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,addr]) */
- 0, 0, 0, 0, /* replaced with address of .got + 8. */
+ 0, 0, 0, 0, /* replaced with offset to .got + 8. */
0, 0, 0, 0 /* pad out to 20 bytes. */
};
static const bfd_byte elf_m68k_plt_entry[PLT_ENTRY_SIZE] =
{
- 0x4e, 0xfb, 0x01, 0x71, /* jmp ([addr]) */
- 0, 0, 0, 0, /* replaced with address of this symbol in .got. */
+ 0x4e, 0xfb, 0x01, 0x71, /* jmp ([%pc,symbol@GOTPC]) */
+ 0, 0, 0, 0, /* replaced with offset to symbol's .got entry. */
0x2f, 0x3c, /* move.l #offset,-(%sp) */
0, 0, 0, 0, /* replaced with offset into relocation table. */
0x60, 0xff, /* bra.l .plt */
case R_68K_GOT8:
case R_68K_GOT16:
case R_68K_GOT32:
+ if (h != NULL
+ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ break;
+ /* Fall through. */
case R_68K_GOT8O:
case R_68K_GOT16O:
case R_68K_GOT32O:
/* This symbol requires a global offset table entry. */
- if (h != NULL
- && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
- break;
-
if (dynobj == NULL)
{
/* Create the .got section. */
| SEC_LOAD
| SEC_HAS_CONTENTS
| SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
| SEC_READONLY))
|| !bfd_set_section_alignment (dynobj, srelgot, 2))
return false;
case R_68K_PLT8:
case R_68K_PLT16:
case R_68K_PLT32:
- case R_68K_PLT8O:
- case R_68K_PLT16O:
- case R_68K_PLT32O:
/* This symbol requires a procedure linkage table entry. We
actually build the entry in adjust_dynamic_symbol,
- because this might be a case of linking PIC code without
- linking in any dynamic objects, in which case we don't
- need to generate a procedure linkage table after all. */
-
+ because this might be a case of linking PIC code which is
+ never referenced by a dynamic object, in which case we
+ don't need to generate a procedure linkage table entry
+ after all. */
+
/* If this is a local symbol, we resolve it directly without
creating a procedure linkage table entry. */
if (h == NULL)
continue;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ break;
+
+ case R_68K_PLT8O:
+ case R_68K_PLT16O:
+ case R_68K_PLT32O:
+ /* This symbol requires a procedure linkage table entry. */
+
+ if (h == NULL)
+ {
+ /* It does not make sense to have this relocation for a
+ local symbol. FIXME: does it? How to handle it if
+ it does make sense? */
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
/* Make sure this symbol is output as a dynamic symbol. */
if (h->dynindx == -1)
{
case R_68K_16:
case R_68K_32:
if (info->shared
- && (sec->flags & SEC_ALLOC) != 0)
+ && (sec->flags & SEC_ALLOC) != 0
+ && ((ELF32_R_TYPE (rel->r_info) != R_68K_PC8
+ && ELF32_R_TYPE (rel->r_info) != R_68K_PC16
+ && ELF32_R_TYPE (rel->r_info) != R_68K_PC32)
+ || (!info->symbolic
+ || (h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0)))
{
/* When creating a shared object, we must copy these
reloc types into the output file. We create a reloc
| SEC_LOAD
| SEC_HAS_CONTENTS
| SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
| SEC_READONLY))
|| !bfd_set_section_alignment (dynobj, sreloc, 2))
return false;
if (h->type == STT_FUNC
|| (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
{
- if (!elf_hash_table (info)->dynamic_sections_created)
+ if (! info->shared
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0
+ /* We must always create the plt entry if it was referenced
+ by a PLTxxO relocation. In this case we already recorded
+ it as a dynamic symbol. */
+ && h->dynindx == -1)
{
- /* This case can occur if we saw a PLT32 reloc in an input
- file, but none of the input files were dynamic objects.
- In such a case, we don't actually need to build a
- procedure linkage table, and we can just do a PC32 reloc
- instead. */
+ /* This case can occur if we saw a PLTxx reloc in an input
+ file, but the symbol was never referred to by a dynamic
+ object. In such a case, we don't actually need to build
+ a procedure linkage table, and we can just do a PCxx
+ reloc instead. */
BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0);
return true;
}
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1)
+ {
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
+
s = bfd_get_section_by_name (dynobj, ".plt");
BFD_ASSERT (s != NULL);
const char *name;
boolean strip;
- if ((s->flags & SEC_IN_MEMORY) == 0)
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
/* It's OK to base decisions on the section name, because none
struct elf_link_hash_entry **sym_hashes;
bfd_vma *local_got_offsets;
asection *sgot;
- asection *sgotplt;
asection *splt;
asection *sreloc;
Elf_Internal_Rela *rel;
local_got_offsets = elf_local_got_offsets (input_bfd);
sgot = NULL;
- sgotplt = NULL;
splt = NULL;
sreloc = NULL;
case R_68K_GOT8:
case R_68K_GOT16:
case R_68K_GOT32:
- /* Relocation is to the entry for this symbol in the global
- offset table. */
+ /* Relocation is to the address of the entry for this symbol
+ in the global offset table. */
if (h != NULL
&& strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
break;
/* Relocation is the offset of the entry for this symbol in
the global offset table. */
- if (sgot == NULL)
- {
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
- }
-
- if (sgotplt == NULL)
- {
- sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
- BFD_ASSERT (sgotplt != NULL);
- }
-
- if (h != NULL)
- {
- bfd_vma off;
+ {
+ bfd_vma off;
- off = h->got_offset;
- BFD_ASSERT (off != (bfd_vma) -1);
-
- if (!elf_hash_table (info)->dynamic_sections_created
- || (info->shared
- && info->symbolic
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
- {
- /* This is actually a static link, or it is a
- -Bsymbolic link and the symbol is defined
- locally. We must initialize this entry in the
- global offset table. Since the offset must
- always be a multiple of 4, we use the least
- significant bit to record whether we have
- initialized it already.
-
- When doing a dynamic link, we create a .rela.got
- relocation entry to initialize the value. This
- is done in the finish_dynamic_symbol routine. */
- if ((off & 1) != 0)
- off &= ~1;
- else
- {
- bfd_put_32 (output_bfd, relocation,
- sgot->contents + off);
- h->got_offset |= 1;
- }
- }
-
- relocation = sgot->output_offset + off;
- if (r_type == R_68K_GOT8O
- || r_type == R_68K_GOT16O
- || r_type == R_68K_GOT32O)
- relocation -= sgotplt->output_offset;
- }
- else
- {
- bfd_vma off;
-
- BFD_ASSERT (local_got_offsets != NULL
- && local_got_offsets[r_symndx] != (bfd_vma) -1);
-
- off = local_got_offsets[r_symndx];
-
- /* The offset must always be a multiple of 4. We use
- the least significant bit to record whether we have
- already generated the necessary reloc. */
- if ((off & 1) != 0)
- off &= ~1;
- else
- {
- bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+ if (sgot == NULL)
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ }
- if (info->shared)
- {
- asection *srelgot;
- Elf_Internal_Rela outrel;
+ if (h != NULL)
+ {
+ off = h->got_offset;
+ BFD_ASSERT (off != (bfd_vma) -1);
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT (srelgot != NULL);
+ if (!elf_hash_table (info)->dynamic_sections_created
+ || (info->shared
+ && info->symbolic
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+ {
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally. We must initialize this entry in the
+ global offset table. Since the offset must
+ always be a multiple of 4, we use the least
+ significant bit to record whether we have
+ initialized it already.
+
+ When doing a dynamic link, we create a .rela.got
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation,
+ sgot->contents + off);
+ h->got_offset |= 1;
+ }
+ }
+ }
+ else
+ {
+ BFD_ASSERT (local_got_offsets != NULL
+ && local_got_offsets[r_symndx] != (bfd_vma) -1);
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + off);
- outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
- outrel.r_addend = 0;
- bfd_elf32_swap_reloca_out (output_bfd, &outrel,
- (((Elf32_External_Rela *)
- srelgot->contents)
- + srelgot->reloc_count));
- ++srelgot->reloc_count;
- }
+ off = local_got_offsets[r_symndx];
- local_got_offsets[r_symndx] |= 1;
- }
-
- relocation = sgot->output_offset + off;
- if (r_type == R_68K_GOT8O
- || r_type == R_68K_GOT16O
- || r_type == R_68K_GOT32O)
- relocation -= sgotplt->output_offset;
- }
+ /* The offset must always be a multiple of 4. We use
+ the least significant bit to record whether we have
+ already generated the necessary reloc. */
+ if ((off & 1) != 0)
+ off &= ~1;
+ else
+ {
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+
+ if (info->shared)
+ {
+ asection *srelgot;
+ Elf_Internal_Rela outrel;
+
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srelgot != NULL);
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + off);
+ outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+ outrel.r_addend = relocation;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ (((Elf32_External_Rela *)
+ srelgot->contents)
+ + srelgot->reloc_count));
+ ++srelgot->reloc_count;
+ }
+
+ local_got_offsets[r_symndx] |= 1;
+ }
+ }
+ relocation = sgot->output_offset + off;
+ if (r_type == R_68K_GOT8O
+ || r_type == R_68K_GOT16O
+ || r_type == R_68K_GOT32O)
+ {
+ /* This relocation does not use the addend. */
+ rel->r_addend = 0;
+ }
+ else
+ relocation += sgot->output_section->vma;
+ }
break;
case R_68K_PLT8:
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
- /* Resolve a PLT32 reloc against a local symbol directly,
+ /* Resolve a PLTxx reloc against a local symbol directly,
without using the procedure linkage table. */
if (h == NULL)
break;
case R_68K_PLT32O:
/* Relocation is the offset of the entry for this symbol in
the procedure linkage table. */
- BFD_ASSERT (h != NULL);
-
- if (h->plt_offset == (bfd_vma) -1)
- {
- /* We didn't make a PLT entry for this symbol. This
- happens when statically linking PIC code. */
- break;
- }
+ BFD_ASSERT (h != NULL && h->plt_offset == (bfd_vma) -1);
if (splt == NULL)
{
}
relocation = h->plt_offset;
+
+ /* This relocation does not use the addend. */
+ rel->r_addend = 0;
+
break;
case R_68K_PC8:
case R_68K_16:
case R_68K_32:
if (info->shared
- && (input_section->flags & SEC_ALLOC) != 0)
+ && (input_section->flags & SEC_ALLOC) != 0
+ && ((r_type != R_68K_PC8
+ && r_type != R_68K_PC16
+ && r_type != R_68K_PC32)
+ || (!info->symbolic
+ || (h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0)))
{
Elf_Internal_Rela outrel;
+ int relocate;
/* When generating a shared object, these relocations
are copied into the output file to be resolved at run
& ELF_LINK_HASH_DEF_REGULAR) == 0))
{
BFD_ASSERT (h->dynindx != -1);
+ relocate = false;
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
- outrel.r_addend = rel->r_addend;
+ outrel.r_addend = relocation + rel->r_addend;
}
else
{
if (r_type == R_68K_32)
{
+ relocate = true;
outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
outrel.r_addend = relocation + rel->r_addend;
}
abort ();
}
+ relocate = false;
outrel.r_info = ELF32_R_INFO (indx, r_type);
outrel.r_addend = relocation + rel->r_addend;
}
++sreloc->reloc_count;
/* This reloc will be computed at runtime, so there's no
- need to do anything now. */
- continue;
+ need to do anything now, except for R_68K_32
+ relocations that have been turned into
+ R_68K_RELATIVE. */
+ if (!relocate)
+ continue;
}
break;
/* This symbol has an entry in the global offset table. Set it
up. */
-
+
BFD_ASSERT (h->dynindx != -1);
sgot = bfd_get_section_by_name (dynobj, ".got");
if (info->shared
&& info->symbolic
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
- rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+ {
+ rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+ rela.r_addend = bfd_get_32 (output_bfd,
+ sgot->contents + (h->got_offset & ~1));
+ }
else
{
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset);
+ bfd_put_32 (output_bfd, (bfd_vma) 0,
+ sgot->contents + (h->got_offset & ~1));
rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT);
+ rela.r_addend = 0;
}
- rela.r_addend = 0;
bfd_elf32_swap_reloca_out (output_bfd, &rela,
((Elf32_External_Rela *) srela->contents
+ srela->reloc_count));
break;
case DT_RELASZ:
- /* My reading of the SVR4 ABI indicates that the
- procedure linkage table relocs (DT_JMPREL) should be
- included in the overall relocs (DT_RELA). This is
- what Solaris does. However, UnixWare can not handle
- that case. Therefore, we override the DT_RELASZ entry
- here to make it not include the JMPREL relocs. Since
- the linker script arranges for .rela.plt to follow all
+ /* The procedure linkage table relocs (DT_JMPREL) should
+ not be included in the overall relocs (DT_RELA).
+ Therefore, we override the DT_RELASZ entry here to
+ make it not include the JMPREL relocs. Since the
+ linker script arranges for .rela.plt to follow all
other relocation sections, we don't have to worry
about changing the DT_RELA entry. */
- /* FIXME: This comment is from elf32-i386.c, what about
- the SVR4/m68k implementations? */
s = bfd_get_section_by_name (output_bfd, ".rela.plt");
if (s != NULL)
{
-/* 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>.
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));
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 *));
PARAMS((bfd *, struct bfd_link_info *));
\f
-#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;
/* 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. */
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. */
#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 *
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;
return &ret->root.root;
}
\f
+/* 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;
+}
+\f
/* 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)
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
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
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 */
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 */
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 */
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 */
"COPY",
false,
0,
- 0,
+ 0,
true),
HOWTO (R_ALPHA_GLOB_DAT,
"GLOB_DAT",
false,
0,
- 0,
+ 0,
true),
HOWTO (R_ALPHA_JMP_SLOT,
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;
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
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;
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)
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);
+ 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
{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. */
#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"
\f
return bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0);
}
\f
-/* 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. */
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;
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");
- if (s == NULL
- || !bfd_set_section_flags (abfd, s, (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_READONLY))
- || !bfd_set_section_alignment (abfd, s, 3))
- return false;
-
- s = bfd_make_section(abfd, ".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_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED))
|| !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. */
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;
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;
+}
\f
/* Read ECOFF debugging information from a .mdebug section into a
ecoff_debug_info structure. */
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)
{
/* 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,
struct bfd_link_info *info;
asection *s;
struct ecoff_debug_info *debug;
- */
-
+*/
\f
+/* Handle dynamic relocations when doing an Alpha ELF link. */
+
static boolean
elf64_alpha_check_relocs (abfd, info, sec, relocs)
bfd *abfd;
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)
+ 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;
+
+ memset (local_got_entries, 0, 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)
+ {
+ gotent = ((struct alpha_elf_got_entry *)
+ bfd_alloc (abfd,
+ sizeof (struct alpha_elf_got_entry)));
+ if (!gotent)
+ return false;
+
+ gotent->gotobj = abfd;
+ gotent->addend = rel->r_addend;
+ gotent->got_offset = -1;
+ gotent->flags = 0;
+
+ 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++;
+ }
+ }
+
+ /* 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 */
+
+ 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)
{
- 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))))
+ if (!elf64_alpha_create_got_section (abfd, info))
+ return false;
+
+ /* 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;
+
+ got_created = 1;
+ }
+ break;
+
+ case R_ALPHA_SREL16:
+ case R_ALPHA_SREL32:
+ case R_ALPHA_SREL64:
+ if (h == NULL)
+ break;
+ /* FALLTHRU */
+
+ case R_ALPHA_REFLONG:
+ case R_ALPHA_REFQUAD:
+ if (rel_sec_name == NULL)
+ {
+ 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)
{
- h->root.elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ 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;
}
}
- if (dynobj == NULL)
+ if (h)
{
- elf_hash_table(info)->dynobj = dynobj = abfd;
+ /* 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. */
- /* Create the .got section. */
- if (!elf64_alpha_create_got_section(dynobj, info))
- 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;
- sgot = bfd_get_section_by_name(dynobj, ".got");
- srelgot = bfd_get_section_by_name(dynobj, ".rela.got");
+ 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;
+ }
+ }
+
+ return true;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+ regular object. The current definition is in some section of the
+ dynamic object, but we're not including those sections. We have to
+ change the definition to something the rest of the link can
+ understand. */
+
+static boolean
+elf64_alpha_adjust_dynamic_symbol (info, h)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+{
+ bfd *dynobj;
+ asection *s;
+ struct alpha_elf_link_hash_entry *ah;
+
+ 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)
+ {
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+
+ s = bfd_get_section_by_name(dynobj, ".plt");
+ 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
+ in the .plt. This is required to make function pointers compare
+ equal between the normal executable and the shared library. */
+ if (!info->shared)
+ {
+ h->root.u.def.section = s;
+ h->root.u.def.value = h->plt_offset;
+ }
+
+ /* 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
+ real definition first, and we can just use the same value. */
+ if (h->weakdef != NULL)
+ {
+ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+ || h->weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->weakdef->root.u.def.section;
+ h->root.u.def.value = h->weakdef->root.u.def.value;
+ return true;
+ }
+
+ /* 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 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;
- if (h != NULL)
- {
- if (h->root.got_offset != MINUS_ONE)
+ for (ae = *start; ae ; ae = ae->next)
+ if (ae->gotobj == a && ae->addend == be->addend)
{
- /* We have already allocated space in this .got. */
- break;
+ *pbe = be->next;
+ goto global_found;
}
+ be->gotobj = a;
+ total += 1;
- /* Make sure this becomes a dynamic symbol. */
- if (h->root.dynindx == -1
- && ! _bfd_elf_link_record_dynamic_symbol (info, &h->root))
- return false;
+ global_found:;
+ }
+ }
+ }
- /* Reserve space for a reloc even if we won't use it. */
- srelgot->_raw_size += sizeof(Elf64_External_Rela);
+ alpha_elf_tdata(a)->total_got_entries = total;
+ alpha_elf_tdata(b)->gotobj = a;
+}
- /* Create the relocation in adjust_dynamic_symbol */
+/* Calculate the offsets for the got entries. */
- h->root.got_offset = sgot->_raw_size;
- sgot->_raw_size += 8;
- }
- else
- {
- bfd_vma *lgotoff = elf_local_got_offsets(abfd);
- if (lgotoff == NULL)
- {
- size_t size;
+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;
- size = elf_tdata(abfd)->symtab_hdr.sh_info * sizeof(bfd_vma);
- lgotoff = (bfd_vma *)bfd_alloc(abfd, size);
- if (lgotoff == NULL)
- return false;
+ 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;
+ }
- elf_local_got_offsets(abfd) = lgotoff;
- memset(lgotoff, -1, size);
- }
+ return true;
+}
- 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;
+static void
+elf64_alpha_calc_got_offsets (info)
+ struct bfd_link_info *info;
+{
+ bfd *i, *got_list = alpha_elf_hash_table(info)->got_list;
- 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);
- }
- }
- break;
+ /* 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;
- case R_ALPHA_SREL16:
- case R_ALPHA_SREL32:
- case R_ALPHA_SREL64:
- if (h == NULL)
- break;
- /* FALLTHRU */
+ /* 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);
- case R_ALPHA_REFLONG:
- case R_ALPHA_REFQUAD:
- if (info->shared
- || (h != NULL
- && !(h->root.elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR)))
- {
- /* 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. */
- 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)
- return false;
+ /* 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;
- BFD_ASSERT (strncmp (name, ".rela", 5) == 0
- && strcmp (bfd_get_section_name (abfd, sec),
- name+5) == 0);
+ 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;
- 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;
- }
- }
- sreloc->_raw_size += sizeof (Elf64_External_Rela);
- }
- break;
+ 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;
}
+}
- return true;
+/* 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;
}
-/* Adjust a symbol defined by a dynamic object and referenced by a
- regular object. The current definition is in some section of the
- dynamic object, but we're not including those sections. We have to
- change the definition to something the rest of the link can
- understand. */
+/* Constructs the gots. */
static boolean
-elf64_alpha_adjust_dynamic_symbol (info, h)
+elf64_alpha_always_size_sections (output_bfd, info)
+ bfd *output_bfd;
struct bfd_link_info *info;
- struct elf_link_hash_entry *h;
{
- bfd *dynobj;
- asection *s;
-
- dynobj = elf_hash_table(info)->dynobj;
+ bfd *i, *got_list, *cur_got_obj, **cur_got_tail;
+ int ngots;
- /* 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. */
+ if (info->relocateable)
+ return true;
- if (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+ ngots = 0;
+ got_list = NULL;
+ cur_got_obj = NULL;
+ cur_got_tail = NULL;
+ for (i = info->input_bfds; i ; i = i->link_next)
{
- /* 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))
+ 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)
{
- h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
- return true;
+ /* 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;
}
- s = bfd_get_section_by_name(dynobj, ".plt");
- BFD_ASSERT(s != NULL);
+ 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;
+ }
- /* The first bit of the .plt is reserved. */
- if (s->_raw_size == 0)
- s->_raw_size = PLT_HEADER_SIZE;
+ 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;
- h->plt_offset = s->_raw_size;
+ /* Once the gots have been merged, fill in the got offsets for everything
+ therein. */
+ elf64_alpha_calc_got_offsets (info);
- /* 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
- in the .plt. This is required to make function pointers compare
- equal between the normal executable and the shared library. */
- if (!info->shared)
+ /* 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)
{
- h->root.u.def.section = s;
- h->root.u.def.value = s->_raw_size;
+ s->contents = (bfd_byte *) bfd_zalloc (i, s->_raw_size);
+ if (s->contents == NULL)
+ return false;
}
+ }
- s->_raw_size += PLT_ENTRY_SIZE;
+ return true;
+}
- /* 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);
+/* Work out the sizes of the dynamic relocation entries. */
- return true;
+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 this is a weak symbol, and there is a real definition, the
- processor independent code will have arranged for us to see the
- real definition first, and we can just use the same value. */
- if (h->weakdef != NULL)
+ /* If the symbol is dynamic, we'll need all the relocations in their
+ natural form. */
+ if (alpha_elf_dynamic_symbol_p (&h->root, info))
{
- BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
- || h->weakdef->root.type == bfd_link_hash_defweak);
- h->root.u.def.section = h->weakdef->root.u.def.section;
- h->root.u.def.value = h->weakdef->root.u.def.value;
- return true;
+ 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;
- /* 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
- symbols even in regular objects, does not need the hackery of a
- .dynbss section and COPY dynamic relocations. */
+ 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;
}
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
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
strip = false;
- if (strncmp(name, ".rela", 5) == 0)
+ if (strncmp (name, ".rela", 5) == 0)
{
strip = (s->_raw_size == 0);
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)
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);
}
}
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;
}
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
#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;
{
bfd_byte *p_ldah, *p_lda;
+ BFD_ASSERT(gp != 0);
+
relocation = (input_section->output_section->vma
+ input_section->output_offset
+ rel->r_offset);
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];
-
- /* 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;
+ gotent = h->got_entries;
+ while (gotent->gotobj != gotobj || gotent->addend != addend)
+ gotent = gotent->next;
- srel = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT(srel != NULL);
+ /* 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);
- 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;
+ /* The dynamic relocations for the .got entries are
+ done in finish_dynamic_symbol. */
- 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;
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:
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
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);
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);
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. */
{
bfd *dynobj;
asection *sdyn;
- asection *sgot;
dynobj = elf_hash_table (info)->dynobj;
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
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)
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;
}
else
esym.asym.value = last;
-
+
if (! bfd_ecoff_debug_one_external (abfd, &debug, swap,
name[i], &esym))
return false;
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");
/* 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)
{
#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 \
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 \