/* ELF support for AArch64.
- Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+ Copyright 2009-2013 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of BFD, the Binary File Descriptor library.
EMPTY_HOWTO (306),
EMPTY_HOWTO (307),
EMPTY_HOWTO (308),
- EMPTY_HOWTO (309),
+
+ /* Set a load-literal immediate field to bits
+ 0x1FFFFC of G(S)-P */
+ HOWTO (R_AARCH64_GOT_LD_PREL19, /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte,1 = short,2 = long) */
+ 19, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_AARCH64_GOT_LD_PREL19", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffe0, /* src_mask */
+ 0xffffe0, /* dst_mask */
+ TRUE), /* pcrel_offset */
+
EMPTY_HOWTO (310),
/* Get to the page for the GOT entry for the symbol
FALSE), /* pcrel_offset */
HOWTO (R_AARCH64_TLSIE_LD_GOTTPREL_PREL19, /* type */
- 0, /* rightshift */
+ 2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
21, /* bitsize */
FALSE, /* pc_relative */
FALSE), /* pcrel_offset */
HOWTO (R_AARCH64_TLSLE_MOVW_TPREL_G2, /* type */
- 8, /* rightshift */
+ 32, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
12, /* bitsize */
FALSE, /* pc_relative */
FALSE), /* pcrel_offset */
HOWTO (R_AARCH64_TLSLE_MOVW_TPREL_G1, /* type */
- 4, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
12, /* bitsize */
FALSE, /* pc_relative */
FALSE), /* pcrel_offset */
HOWTO (R_AARCH64_TLSLE_MOVW_TPREL_G1_NC, /* type */
- 4, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
12, /* bitsize */
FALSE, /* pc_relative */
FALSE), /* pcrel_offset */
HOWTO (R_AARCH64_TLSLE_ADD_TPREL_HI12, /* type */
- 3, /* rightshift */
+ 12, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
12, /* bitsize */
FALSE, /* pc_relative */
static reloc_howto_type elf64_aarch64_tlsdesc_howto_table[] =
{
HOWTO (R_AARCH64_TLSDESC_LD64_PREL19, /* type */
- 0, /* rightshift */
+ 2, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
21, /* bitsize */
TRUE, /* pc_relative */
FALSE), /* pcrel_offset */
HOWTO (R_AARCH64_TLSDESC_OFF_G1, /* type */
- 4, /* rightshift */
+ 16, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
12, /* bitsize */
FALSE, /* pc_relative */
{BFD_RELOC_AARCH64_CALL26, R_AARCH64_CALL26},
/* Relocations for PIC. */
+ {BFD_RELOC_AARCH64_GOT_LD_PREL19, R_AARCH64_GOT_LD_PREL19},
{BFD_RELOC_AARCH64_ADR_GOT_PAGE, R_AARCH64_ADR_GOT_PAGE},
{BFD_RELOC_AARCH64_LD64_GOT_LO12_NC, R_AARCH64_LD64_GOT_LO12_NC},
return NULL;
}
+/* Support for core dump NOTE sections. */
+
+static bfd_boolean
+elf64_aarch64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ int offset;
+ size_t size;
+
+ switch (note->descsz)
+ {
+ default:
+ return FALSE;
+
+ case 408: /* sizeof(struct elf_prstatus) on Linux/arm64. */
+ /* pr_cursig */
+ elf_tdata (abfd)->core->signal
+ = bfd_get_16 (abfd, note->descdata + 12);
+
+ /* pr_pid */
+ elf_tdata (abfd)->core->lwpid
+ = bfd_get_32 (abfd, note->descdata + 32);
+
+ /* pr_reg */
+ offset = 112;
+ size = 272;
+
+ break;
+ }
+
+ /* Make a ".reg/999" section. */
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+ size, note->descpos + offset);
+}
+
#define TARGET_LITTLE_SYM bfd_elf64_littleaarch64_vec
#define TARGET_LITTLE_NAME "elf64-littleaarch64"
#define TARGET_BIG_SYM bfd_elf64_bigaarch64_vec
#define TARGET_BIG_NAME "elf64-bigaarch64"
+#define elf_backend_grok_prstatus elf64_aarch64_grok_prstatus
+
typedef unsigned long int insn32;
/* The linker script knows the section names for placement.
struct elf64_aarch64_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf64_aarch64_link_hash_table);
- ret = bfd_malloc (amt);
+ ret = bfd_zmalloc (amt);
if (ret == NULL)
return NULL;
return NULL;
}
- ret->sdynbss = NULL;
- ret->srelbss = NULL;
-
ret->plt_header_size = PLT_ENTRY_SIZE;
ret->plt_entry_size = PLT_SMALL_ENTRY_SIZE;
-
- ret->sym_cache.abfd = NULL;
ret->obfd = abfd;
-
- ret->stub_bfd = NULL;
- ret->add_stub_section = NULL;
- ret->layout_sections_again = NULL;
- ret->stub_group = NULL;
- ret->bfd_count = 0;
- ret->top_index = 0;
- ret->input_list = NULL;
- ret->tlsdesc_plt = 0;
ret->dt_tlsdesc_got = (bfd_vma) - 1;
if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc,
= (struct elf64_aarch64_link_hash_table *) hash;
bfd_hash_table_free (&ret->stub_hash_table);
- _bfd_generic_link_hash_table_free (hash);
+ _bfd_elf_link_hash_table_free (hash);
}
static bfd_vma
value = PG (value + addend) - PG (place);
break;
+ case R_AARCH64_GOT_LD_PREL19:
+ value = value + addend - place;
+ break;
+
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSDESC_ADR_PAGE:
case R_AARCH64_TLSGD_ADR_PAGE21:
break;
case R_AARCH64_LD_PREL_LO19:
+ case R_AARCH64_GOT_LD_PREL19:
if (old_addend & ((1 << howto->rightshift) - 1))
return bfd_reloc_overflow;
contents = reencode_ld_lit_ofs_19 (contents, addend);
{
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_GOT_LD_PREL19:
return GOT_NORMAL;
case R_AARCH64_TLSGD_ADR_PAGE21:
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_GOT_LD_PREL19:
if (globals->root.sgot == NULL)
BFD_ASSERT (h != NULL);
case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
case R_AARCH64_TLSLE_MOVW_TPREL_G2:
value = aarch64_resolve_relocation (r_type, place, value,
- - tpoff_base (info), weak_undef_p);
+ signed_addend - tpoff_base (info), weak_undef_p);
*unresolved_reloc_p = FALSE;
break;
bfd_reloc.howto = elf64_aarch64_howto_from_type (r_type);
howto = bfd_reloc.howto;
+ if (howto == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%B: unrecognized relocation (0x%x) in section `%A'"),
+ input_bfd, input_section, r_type);
+ return FALSE;
+ }
+
h = NULL;
sym = NULL;
sec = NULL;
return FALSE;
}
- if (r_type >= R_AARCH64_dyn_max)
- {
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
-
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
}
else
/* Update the got entry reference counts for the section being removed. */
static bfd_boolean
-elf64_aarch64_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info ATTRIBUTE_UNUSED,
- asection *sec ATTRIBUTE_UNUSED,
- const Elf_Internal_Rela *
- relocs ATTRIBUTE_UNUSED)
+elf64_aarch64_gc_sweep_hook (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela * relocs)
{
+ struct elf64_aarch64_link_hash_table *htab;
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_aarch64_local_symbol *locals;
+ const Elf_Internal_Rela *rel, *relend;
+
+ if (info->relocatable)
+ return TRUE;
+
+ htab = elf64_aarch64_hash_table (info);
+
+ if (htab == NULL)
+ return FALSE;
+
+ elf_section_data (sec)->local_dynrel = NULL;
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+ sym_hashes = elf_sym_hashes (abfd);
+
+ locals = elf64_aarch64_locals (abfd);
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ {
+ unsigned long r_symndx;
+ unsigned int r_type;
+ struct elf_link_hash_entry *h = NULL;
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ struct elf64_aarch64_link_hash_entry *eh;
+ struct elf_dyn_relocs **pp;
+ struct elf_dyn_relocs *p;
+
+ h = sym_hashes[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;
+ eh = (struct elf64_aarch64_link_hash_entry *) h;
+
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
+ {
+ if (p->sec == sec)
+ {
+ /* Everything must go for SEC. */
+ *pp = p->next;
+ break;
+ }
+ }
+ }
+ else
+ {
+ Elf_Internal_Sym *isym;
+
+ /* A local symbol. */
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache,
+ abfd, r_symndx);
+ if (isym == NULL)
+ return FALSE;
+ }
+
+ r_type = ELF64_R_TYPE (rel->r_info);
+ r_type = aarch64_tls_transition (abfd,info, r_type, h ,r_symndx);
+ switch (r_type)
+ {
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_GOT_LD_PREL19:
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_TLSGD_ADR_PAGE21:
+ case R_AARCH64_TLSGD_ADD_LO12_NC:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12:
+ case R_AARCH64_TLSLE_ADD_TPREL_HI12:
+ case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G2:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case R_AARCH64_TLSDESC_ADR_PAGE:
+ case R_AARCH64_TLSDESC_ADD_LO12_NC:
+ case R_AARCH64_TLSDESC_LD64_LO12_NC:
+ if (h != NULL)
+ {
+ if (h->got.refcount > 0)
+ h->got.refcount -= 1;
+ }
+ else if (locals != NULL)
+ {
+ if (locals[r_symndx].got_refcount > 0)
+ locals[r_symndx].got_refcount -= 1;
+ }
+ break;
+
+ case R_AARCH64_ADR_PREL_PG_HI21_NC:
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ case R_AARCH64_ADR_PREL_LO21:
+ if (h != NULL && info->executable)
+ {
+ if (h->plt.refcount > 0)
+ h->plt.refcount -= 1;
+ }
+ break;
+
+ case R_AARCH64_CALL26:
+ case R_AARCH64_JUMP26:
+ /* If this is a local symbol then we resolve it
+ directly without creating a PLT entry. */
+ if (h == NULL)
+ continue;
+
+ if (h->plt.refcount > 0)
+ h->plt.refcount -= 1;
+ break;
+
+ case R_AARCH64_ABS64:
+ if (h != NULL && info->executable)
+ {
+ if (h->plt.refcount > 0)
+ h->plt.refcount -= 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
return TRUE;
}
struct elf64_aarch64_link_hash_table *htab;
- unsigned long nsyms;
-
if (info->relocatable)
return TRUE;
symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
- nsyms = NUM_SHDR_ENTRIES (symtab_hdr);
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
return FALSE;
}
- if (r_symndx >= nsyms
- /* PR 9934: It is possible to have relocations that do not
- refer to symbols, thus it is also possible to have an
- object file containing relocations but no symbol table. */
- && (r_symndx > 0 || nsyms > 0))
- {
- (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd,
- r_symndx);
- return FALSE;
- }
-
- if (nsyms == 0 || r_symndx < symtab_hdr->sh_info)
+ if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
{
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;
+
+ /* PR15323, ref flags aren't set for references in the same
+ object. */
+ h->root.non_ir_ref = 1;
}
/* Could be done earlier, if h were already available. */
/* RR: We probably want to keep a consistency check that
there are no dangling GOT_PAGE relocs. */
case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_GOT_LD_PREL19:
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSGD_ADR_PAGE21:
case R_AARCH64_TLSGD_ADD_LO12_NC:
case R_AARCH64_ADR_PREL_PG_HI21_NC:
case R_AARCH64_ADR_PREL_PG_HI21:
+ case R_AARCH64_ADR_PREL_LO21:
if (h != NULL && info->executable)
{
/* If this reloc is in a read-only section, we might
}
static enum elf_reloc_type_class
-elf64_aarch64_reloc_type_class (const Elf_Internal_Rela *rela)
+elf64_aarch64_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ const asection *rel_sec ATTRIBUTE_UNUSED,
+ const Elf_Internal_Rela *rela)
{
switch ((int) ELF64_R_TYPE (rela->r_info))
{
/* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. SYM may
be NULL for local symbols. */
if (sym != NULL
- && (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ && (h == elf_hash_table (info)->hdynamic
|| h == elf_hash_table (info)->hgot))
sym->st_shndx = SHN_ABS;
elf64_aarch64_size_info
#define elf_backend_can_refcount 1
-#define elf_backend_can_gc_sections 0
+#define elf_backend_can_gc_sections 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_got_plt 1
#define elf_backend_want_plt_sym 0
#define elf_backend_may_use_rela_p 1
#define elf_backend_default_use_rela_p 1
#define elf_backend_got_header_size (GOT_ENTRY_SIZE * 3)
+#define elf_backend_default_execstack 0
#undef elf_backend_obj_attrs_section
#define elf_backend_obj_attrs_section ".ARM.attributes"