bfd_elf_generic_reloc, "R_X86_64_16", FALSE, 0xffff, 0xffff, FALSE),
HOWTO(R_X86_64_PC16,0, 1, 16, TRUE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_X86_64_PC16", FALSE, 0xffff, 0xffff, TRUE),
- HOWTO(R_X86_64_8, 0, 0, 8, FALSE, 0, complain_overflow_signed,
+ HOWTO(R_X86_64_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_X86_64_8", FALSE, 0xff, 0xff, FALSE),
HOWTO(R_X86_64_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_X86_64_PC8", FALSE, 0xff, 0xff, TRUE),
HOWTO(R_X86_64_TLSLD, 0, 2, 32, TRUE, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_X86_64_TLSLD", FALSE, 0xffffffff,
0xffffffff, TRUE),
- HOWTO(R_X86_64_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ HOWTO(R_X86_64_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_X86_64_DTPOFF32", FALSE, 0xffffffff,
0xffffffff, FALSE),
HOWTO(R_X86_64_GOTTPOFF, 0, 2, 32, TRUE, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_X86_64_GOTPC32",
FALSE, 0xffffffff, 0xffffffff, TRUE),
+ /* We have a gap in the reloc numbers here.
+ R_X86_64_standard counts the number up to this point, and
+ R_X86_64_vt_offset is the value to subtract from a reloc type of
+ R_X86_64_GNU_VT* to form an index into this table. */
+#define R_X86_64_standard (R_X86_64_GOTPC32 + 1)
+#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard)
+
/* GNU extension to record C++ vtable hierarchy. */
HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, FALSE, 0, complain_overflow_dont,
NULL, "R_X86_64_GNU_VTINHERIT", FALSE, 0, 0, FALSE),
unsigned r_type, i;
r_type = ELF64_R_TYPE (dst->r_info);
- if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT)
+ if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT
+ || r_type >= (unsigned int) R_X86_64_max)
{
- BFD_ASSERT (r_type <= (unsigned int) R_X86_64_GOTPC32);
+ if (r_type >= (unsigned int) R_X86_64_standard)
+ {
+ (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+ abfd, (int) r_type);
+ r_type = R_X86_64_NONE;
+ }
i = r_type;
}
else
- {
- BFD_ASSERT (r_type < (unsigned int) R_X86_64_max);
- i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_GOTPC32 - 1);
- }
+ i = r_type - (unsigned int) R_X86_64_vt_offset;
cache_ptr->howto = &x86_64_elf_howto_table[i];
BFD_ASSERT (r_type == cache_ptr->howto->type);
}
/* Copy the extra info we tack onto an elf_link_hash_entry. */
static void
-elf64_x86_64_copy_indirect_symbol (const struct elf_backend_data *bed,
+elf64_x86_64_copy_indirect_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *dir,
struct elf_link_hash_entry *ind)
{
struct elf64_x86_64_dyn_relocs **pp;
struct elf64_x86_64_dyn_relocs *p;
- if (ind->root.type == bfd_link_hash_indirect)
- abort ();
-
- /* Add reloc counts against the weak sym to the strong sym
+ /* Add reloc counts against the indirect sym to the direct sym
list. Merge any entries against the same section. */
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
{
dir->pointer_equality_needed |= ind->pointer_equality_needed;
}
else
- _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
static bfd_boolean
}
else
{
+ void **vpp;
/* Track dynamic relocs needed for local syms too.
We really need local syms available to do this
easily. Oh well. */
if (s == NULL)
return FALSE;
- head = ((struct elf64_x86_64_dyn_relocs **)
- &elf_section_data (s)->local_dynrel);
+ /* Beware of type punned pointers vs strict aliasing
+ rules. */
+ vpp = &(elf_section_data (s)->local_dynrel);
+ head = (struct elf64_x86_64_dyn_relocs **)vpp;
}
p = *head;
}
}
+ if (h->size == 0)
+ {
+ (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+ h->root.root.string);
+ return TRUE;
+ }
+
/* We must allocate the symbol in our .dynbss section, which will
become part of the .bss section of the executable. There will be
an entry for this symbol in the .dynsym section. The dynamic
{
struct elf64_x86_64_dyn_relocs *p;
- for (p = *((struct elf64_x86_64_dyn_relocs **)
- &elf_section_data (s)->local_dynrel);
+ for (p = (struct elf64_x86_64_dyn_relocs *)
+ (elf_section_data (s)->local_dynrel);
p != NULL;
p = p->next)
{
continue;
}
+ if ((s->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+
/* Allocate memory for the section contents. We use bfd_zalloc
here in case unused entries are not reclaimed before the
section's contents are written out. This should not happen,
&& !((input_section->flags & SEC_DEBUGGING) != 0
&& h->def_dynamic))
(*_bfd_error_handler)
- (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
+ (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
input_bfd,
input_section,
(long) rel->r_offset,
+ howto->name,
h->root.root.string);
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
return TRUE;
}
+/* Hook called by the linker routine which adds symbols from an object
+ file. We use it to put SHN_X86_64_LCOMMON items in .lbss, instead
+ of .bss. */
+
+static bfd_boolean
+elf64_x86_64_add_symbol_hook (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ Elf_Internal_Sym *sym,
+ const char **namep ATTRIBUTE_UNUSED,
+ flagword *flagsp ATTRIBUTE_UNUSED,
+ asection **secp, bfd_vma *valp)
+{
+ asection *lcomm;
+
+ switch (sym->st_shndx)
+ {
+ case SHN_X86_64_LCOMMON:
+ lcomm = bfd_get_section_by_name (abfd, "LARGE_COMMON");
+ if (lcomm == NULL)
+ {
+ lcomm = bfd_make_section_with_flags (abfd,
+ "LARGE_COMMON",
+ (SEC_ALLOC
+ | SEC_IS_COMMON
+ | SEC_LINKER_CREATED));
+ if (lcomm == NULL)
+ return FALSE;
+ elf_section_flags (lcomm) |= SHF_X86_64_LARGE;
+ }
+ *secp = lcomm;
+ *valp = sym->st_size;
+ break;
+ }
+ return TRUE;
+}
+
+
+/* Given a BFD section, try to locate the corresponding ELF section
+ index. */
+
+static bfd_boolean
+elf64_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec, int *index)
+{
+ if (sec == &_bfd_elf_large_com_section)
+ {
+ *index = SHN_X86_64_LCOMMON;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Process a symbol. */
+
+static void
+elf64_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
+ asymbol *asym)
+{
+ elf_symbol_type *elfsym = (elf_symbol_type *) asym;
+
+ switch (elfsym->internal_elf_sym.st_shndx)
+ {
+ case SHN_X86_64_LCOMMON:
+ asym->section = &_bfd_elf_large_com_section;
+ asym->value = elfsym->internal_elf_sym.st_size;
+ /* Common symbol doesn't set BSF_GLOBAL. */
+ asym->flags &= ~BSF_GLOBAL;
+ break;
+ }
+}
+
+static bfd_boolean
+elf64_x86_64_common_definition (Elf_Internal_Sym *sym)
+{
+ return (sym->st_shndx == SHN_COMMON
+ || sym->st_shndx == SHN_X86_64_LCOMMON);
+}
+
+static unsigned int
+elf64_x86_64_common_section_index (asection *sec)
+{
+ if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
+ return SHN_COMMON;
+ else
+ return SHN_X86_64_LCOMMON;
+}
+
+static asection *
+elf64_x86_64_common_section (asection *sec)
+{
+ if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0)
+ return bfd_com_section_ptr;
+ else
+ return &_bfd_elf_large_com_section;
+}
+
+static bfd_boolean
+elf64_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry **sym_hash ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym,
+ asection **psec,
+ bfd_vma *pvalue ATTRIBUTE_UNUSED,
+ unsigned int *pold_alignment ATTRIBUTE_UNUSED,
+ bfd_boolean *skip ATTRIBUTE_UNUSED,
+ bfd_boolean *override ATTRIBUTE_UNUSED,
+ bfd_boolean *type_change_ok ATTRIBUTE_UNUSED,
+ bfd_boolean *size_change_ok ATTRIBUTE_UNUSED,
+ bfd_boolean *newdef ATTRIBUTE_UNUSED,
+ bfd_boolean *newdyn,
+ bfd_boolean *newdyncommon ATTRIBUTE_UNUSED,
+ bfd_boolean *newweak ATTRIBUTE_UNUSED,
+ bfd *abfd ATTRIBUTE_UNUSED,
+ asection **sec,
+ bfd_boolean *olddef ATTRIBUTE_UNUSED,
+ bfd_boolean *olddyn,
+ bfd_boolean *olddyncommon ATTRIBUTE_UNUSED,
+ bfd_boolean *oldweak ATTRIBUTE_UNUSED,
+ bfd *oldbfd,
+ asection **oldsec)
+{
+ /* A normal common symbol and a large common symbol result in a
+ normal common symbol. We turn the large common symbol into a
+ normal one. */
+ if (!*olddyn
+ && h->root.type == bfd_link_hash_common
+ && !*newdyn
+ && bfd_is_com_section (*sec)
+ && *oldsec != *sec)
+ {
+ if (sym->st_shndx == SHN_COMMON
+ && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) != 0)
+ {
+ h->root.u.c.p->section
+ = bfd_make_section_old_way (oldbfd, "COMMON");
+ h->root.u.c.p->section->flags = SEC_ALLOC;
+ }
+ else if (sym->st_shndx == SHN_X86_64_LCOMMON
+ && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) == 0)
+ *psec = *sec = bfd_com_section_ptr;
+ }
+
+ return TRUE;
+}
+
+static int
+elf64_x86_64_additional_program_headers (bfd *abfd)
+{
+ asection *s;
+ int count = 0;
+
+ /* Check to see if we need a large readonly segment. */
+ s = bfd_get_section_by_name (abfd, ".lrodata");
+ if (s && (s->flags & SEC_LOAD))
+ count++;
+
+ /* Check to see if we need a large data segment. Since .lbss sections
+ is placed right after the .bss section, there should be no need for
+ a large data segment just because of .lbss. */
+ s = bfd_get_section_by_name (abfd, ".ldata");
+ if (s && (s->flags & SEC_LOAD))
+ count++;
+
+ return count;
+}
+
+static const struct bfd_elf_special_section
+ elf64_x86_64_special_sections[]=
+{
+ { ".gnu.linkonce.lb", 16, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE},
+ { ".gnu.linkonce.lr", 16, -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE},
+ { ".gnu.linkonce.lt", 16, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR + SHF_X86_64_LARGE},
+ { ".lbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE},
+ { ".ldata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE},
+ { ".lrodata", 8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE},
+ { NULL, 0, 0, 0, 0 }
+};
+
#define TARGET_LITTLE_SYM bfd_elf64_x86_64_vec
#define TARGET_LITTLE_NAME "elf64-x86-64"
#define ELF_ARCH bfd_arch_i386
#define elf_backend_section_from_shdr \
elf64_x86_64_section_from_shdr
+#define elf_backend_section_from_bfd_section \
+ elf64_x86_64_elf_section_from_bfd_section
+#define elf_backend_add_symbol_hook \
+ elf64_x86_64_add_symbol_hook
+#define elf_backend_symbol_processing \
+ elf64_x86_64_symbol_processing
+#define elf_backend_common_section_index \
+ elf64_x86_64_common_section_index
+#define elf_backend_common_section \
+ elf64_x86_64_common_section
+#define elf_backend_common_definition \
+ elf64_x86_64_common_definition
+#define elf_backend_merge_symbol \
+ elf64_x86_64_merge_symbol
+#define elf_backend_special_sections \
+ elf64_x86_64_special_sections
+#define elf_backend_additional_program_headers \
+ elf64_x86_64_additional_program_headers
+
#include "elf64-target.h"