/* X86-64 specific support for 64-bit ELF
- Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Contributed by Jan Hubicka <jh@suse.cz>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
return 0;
}
+static reloc_howto_type *
+elf64_x86_64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < (sizeof (x86_64_elf_howto_table)
+ / sizeof (x86_64_elf_howto_table[0]));
+ i++)
+ if (x86_64_elf_howto_table[i].name != NULL
+ && strcasecmp (x86_64_elf_howto_table[i].name, r_name) == 0)
+ return &x86_64_elf_howto_table[i];
+
+ return NULL;
+}
+
/* Given an x86_64 ELF reloc type, fill in an arelent structure. */
static void
}
static int
-elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type, int is_local)
+elf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type,
+ struct elf_link_hash_entry *h)
{
if (info->shared)
return r_type;
case R_X86_64_GOTPC32_TLSDESC:
case R_X86_64_TLSDESC_CALL:
case R_X86_64_GOTTPOFF:
- if (is_local)
+ if (h == NULL)
return R_X86_64_TPOFF32;
return R_X86_64_GOTTPOFF;
case R_X86_64_TLSLD:
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
- r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL);
+ r_type = elf64_x86_64_tls_transition (info, r_type, h);
switch (r_type)
{
case R_X86_64_TLSLD:
}
r_type = ELF64_R_TYPE (rel->r_info);
- r_type = elf64_x86_64_tls_transition (info, r_type, h != NULL);
+ r_type = elf64_x86_64_tls_transition (info, r_type, h);
switch (r_type)
{
case R_X86_64_TLSLD:
{
struct elf64_x86_64_link_hash_table *htab;
asection *s;
- unsigned int power_of_two;
/* If this is a function, put it in the procedure linkage table. We
will fill in the contents of the procedure linkage table later,
h->needs_copy = 1;
}
- /* We need to figure out the alignment required for this symbol. I
- have no idea how ELF linkers handle this. 16-bytes is the size
- of the largest type that requires hard alignment -- long double. */
- /* FIXME: This is VERY ugly. Should be fixed for all architectures using
- this construct. */
- power_of_two = bfd_log2 (h->size);
- if (power_of_two > 4)
- power_of_two = 4;
-
- /* Apply the required alignment. */
s = htab->sdynbss;
- s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
- if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s))
- {
- if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two))
- return FALSE;
- }
- /* Define the symbol as being at this point in the section. */
- h->root.u.def.section = s;
- h->root.u.def.value = s->size;
-
- /* Increment the section size to make room for the symbol. */
- s->size += h->size;
-
- return TRUE;
+ return _bfd_elf_adjust_dynamic_copy (h, s);
}
/* Allocate space in .plt, .got and associated reloc sections for
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
- if (info->relocatable)
- return TRUE;
-
htab = elf64_x86_64_hash_table (info);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
h, sec, relocation,
unresolved_reloc, warned);
}
+
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. Avoid any special processing. */
+ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
+ if (info->relocatable)
+ continue;
+
/* When generating a shared object, the relocations handled here are
copied into the output file to be resolved at run time. */
switch (r_type)
/* FIXME: The ABI says the linker should make sure the value is
the same when it's zeroextended to 64 bit. */
- /* r_symndx will be zero only for relocs against symbols
- from removed linkonce sections, or sections discarded by
- a linker script. */
- if (r_symndx == 0
- || (input_section->flags & SEC_ALLOC) == 0)
+ if ((input_section->flags & SEC_ALLOC) == 0)
break;
if ((info->shared
{
asection *osec;
+ /* We are turning this relocation into one
+ against a section symbol. It would be
+ proper to subtract the symbol's value,
+ osec->vma, from the emitted reloc addend,
+ but ld.so expects buggy relocs. */
osec = sec->output_section;
sindx = elf_section_data (osec)->dynindx;
- BFD_ASSERT (sindx > 0);
+ if (sindx == 0)
+ {
+ asection *oi = htab->elf.text_index_section;
+ sindx = elf_section_data (oi)->dynindx;
+ }
+ BFD_ASSERT (sindx != 0);
}
outrel.r_info = ELF64_R_INFO (sindx, r_type);
case R_X86_64_GOTPC32_TLSDESC:
case R_X86_64_TLSDESC_CALL:
case R_X86_64_GOTTPOFF:
- r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL);
+ r_type = elf64_x86_64_tls_transition (info, r_type, h);
tls_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx];
unsigned int i;
static unsigned char tlsgd[8]
= { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 };
+ unsigned long tls_r_symndx;
+ struct elf_link_hash_entry *tls_h;
/* GD->LE transition.
.byte 0x66; leaq foo@tlsgd(%rip), %rdi
- .word 0x6666; rex64; call __tls_get_addr@plt
+ .word 0x6666; rex64; call __tls_get_addr
Change it into:
movq %fs:0, %rax
leaq foo@tpoff(%rax), %rax */
contents + rel->r_offset + 4 + i)
== tlsgd[i+4]);
BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+ tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
+ BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
+ tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
+ BFD_ASSERT (tls_h != NULL
+ && tls_h->root.root.string != NULL
+ && strcmp (tls_h->root.root.string,
+ "__tls_get_addr") == 0);
+ BFD_ASSERT ((! info->shared
+ && ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32)
+ || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
memcpy (contents + rel->r_offset - 4,
"\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
16);
bfd_put_32 (output_bfd, tpoff (info, relocation),
contents + rel->r_offset + 8);
- /* Skip R_X86_64_PLT32. */
+ /* Skip R_X86_64_PC32/R_X86_64_PLT32. */
rel++;
continue;
}
case R_X86_64_TLSLD:
if (! info->shared)
{
+ unsigned long tls_r_symndx;
+ struct elf_link_hash_entry *tls_h;
+
/* LD->LE transition:
Ensure it is:
- leaq foo@tlsld(%rip), %rdi; call __tls_get_addr@plt.
+ leaq foo@tlsld(%rip), %rdi; call __tls_get_addr.
We change it into:
.word 0x6666; .byte 0x66; movl %fs:0, %rax. */
BFD_ASSERT (rel->r_offset >= 3);
BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4)
== 0xe8);
BFD_ASSERT (rel + 1 < relend);
- BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
+ tls_r_symndx = ELF64_R_SYM (rel[1].r_info);
+ BFD_ASSERT (tls_r_symndx >= symtab_hdr->sh_info);
+ tls_h = sym_hashes[tls_r_symndx - symtab_hdr->sh_info];
+ BFD_ASSERT (tls_h != NULL
+ && tls_h->root.root.string != NULL
+ && strcmp (tls_h->root.root.string,
+ "__tls_get_addr") == 0);
+ BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PC32
+ || ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32);
memcpy (contents + rel->r_offset - 3,
"\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
- /* Skip R_X86_64_PLT32. */
+ /* Skip R_X86_64_PC32/R_X86_64_PLT32. */
rel++;
continue;
}
#define bfd_elf64_bfd_link_hash_table_create \
elf64_x86_64_link_hash_table_create
#define bfd_elf64_bfd_reloc_type_lookup elf64_x86_64_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup \
+ elf64_x86_64_reloc_name_lookup
#define elf_backend_adjust_dynamic_symbol elf64_x86_64_adjust_dynamic_symbol
#define elf_backend_check_relocs elf64_x86_64_check_relocs
#define elf_backend_relocate_section elf64_x86_64_relocate_section
#define elf_backend_size_dynamic_sections elf64_x86_64_size_dynamic_sections
#define elf_backend_always_size_sections elf64_x86_64_always_size_sections
+#define elf_backend_init_index_section _bfd_elf_init_1_index_section
#define elf_backend_plt_sym_val elf64_x86_64_plt_sym_val
#define elf_backend_object_p elf64_x86_64_elf_object_p
#define bfd_elf64_mkobject elf64_x86_64_mkobject
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf64-x86-64-freebsd"
-/* The kernel recognizes executables as valid only if they carry a
- "FreeBSD" label in the ELF header. So we put this label on all
- executables and (for simplicity) also all other object files. */
-
-static void
-elf64_x86_64_fbsd_post_process_headers (bfd * abfd,
- struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
-{
- Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */
-
- i_ehdrp = elf_elfheader (abfd);
-
- /* Put an ABI label supported by FreeBSD >= 4.1. */
- i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
-}
+#undef ELF_OSABI
+#define ELF_OSABI ELFOSABI_FREEBSD
#undef elf_backend_post_process_headers
-#define elf_backend_post_process_headers elf64_x86_64_fbsd_post_process_headers
+#define elf_backend_post_process_headers _bfd_elf_set_osabi
#undef elf64_bed
#define elf64_bed elf64_x86_64_fbsd_bed