/* ARC-specific support for 32-bit ELF
- Copyright (C) 1994-2018 Free Software Foundation, Inc.
+ Copyright (C) 1994-2019 Free Software Foundation, Inc.
Contributed by Cupertino Miranda (cmiranda@synopsys.com).
This file is part of BFD, the Binary File Descriptor library.
} \
}
-
-/* The default symbols representing the init and fini dyn values.
- TODO: Check what is the relation of those strings with arclinux.em
- and DT_INIT. */
-#define INIT_SYM_STRING "_init"
-#define FINI_SYM_STRING "_fini"
-
-char * init_str = INIT_SYM_STRING;
-char * fini_str = FINI_SYM_STRING;
-
#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
case VALUE: \
return "R_" #TYPE; \
const char * symbol_name;
};
+/* ARC ELF linker hash entry. */
+struct elf_arc_link_hash_entry
+{
+ struct elf_link_hash_entry root;
+
+ /* Track dynamic relocs copied for this symbol. */
+ struct elf_dyn_relocs *dyn_relocs;
+
+ struct got_entry *got_ents;
+};
+
+
/* Should be included at this location due to static declarations
defined before this point. */
#include "arc-got.h"
unsigned char elf_reloc_val;
};
-/* ARC ELF linker hash entry. */
-struct elf_arc_link_hash_entry
-{
- struct elf_link_hash_entry root;
-
- /* Track dynamic relocs copied for this symbol. */
- struct elf_dyn_relocs *dyn_relocs;
-};
-
/* ARC ELF linker hash table. */
struct elf_arc_link_hash_table
{
struct bfd_hash_table *table,
const char *string)
{
+ struct elf_arc_link_hash_entry * ret =
+ (struct elf_arc_link_hash_entry *) entry;
+
/* Allocate the structure if it has not already been allocated by a
subclass. */
- if (entry == NULL)
- {
- entry = (struct bfd_hash_entry *)
- bfd_hash_allocate (table,
- sizeof (struct elf_arc_link_hash_entry));
- if (entry == NULL)
- return entry;
- }
+ if (ret == NULL)
+ ret = (struct elf_arc_link_hash_entry *)
+ bfd_hash_allocate (table, sizeof (struct elf_arc_link_hash_entry));
+ if (ret == NULL)
+ return (struct bfd_hash_entry *) ret;
/* Call the allocation method of the superclass. */
- entry = _bfd_elf_link_hash_newfunc (entry, table, string);
- if (entry != NULL)
+ ret = ((struct elf_arc_link_hash_entry *)
+ _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+ table, string));
+ if (ret != NULL)
{
- struct elf_arc_link_hash_entry *eh;
-
- eh = (struct elf_arc_link_hash_entry *) entry;
- eh->dyn_relocs = NULL;
+ ret->dyn_relocs = NULL;
+ ret->got_ents = NULL;
}
- return entry;
+ return (struct bfd_hash_entry *) ret;
}
/* Destroy an ARC ELF linker hash table. */
return NULL;
}
- ret->elf.init_got_refcount.refcount = 0;
- ret->elf.init_got_refcount.glist = NULL;
- ret->elf.init_got_offset.offset = 0;
- ret->elf.init_got_offset.glist = NULL;
-
ret->elf.root.hash_table_free = elf_arc_link_hash_table_free;
return &ret->elf.root;
bfd_boolean result = TRUE;
const char *sec_name = get_elf_backend_data (ibfd)->obj_attrs_section;
char *tagname = NULL;
- int offset = 0;
/* Skip the linker stubs file. This preserves previous behavior
of accepting unknown attributes in the first input file - but
out_attr[i].i = in_attr[i].i;
break;
+ /* The CPU name is given by the vendor, just choose an
+ existing one if missing or different. There are no fail
+ criteria if they different or both missing. */
case Tag_ARC_CPU_name:
+ if (!out_attr[i].s && in_attr[i].s)
+ out_attr[i].s = _bfd_elf_attr_strdup (obfd, in_attr[i].s);
break;
case Tag_ARC_ABI_rf16:
BFD_ASSERT (in_attr[i].i < 3);
BFD_ASSERT (out_attr[i].i < 3);
- if (out_attr[i].i != 0 && in_attr[i].i != 0
+ if (out_attr[i].i == 0)
+ out_attr[i].i = in_attr[i].i;
+ else if (out_attr[i].i != 0 && in_attr[i].i != 0
&& out_attr[i].i != in_attr[i].i)
{
_bfd_error_handler
if (!tagname)
tagname = "ABI exceptions";
- if (out_attr[i].i != 0 && in_attr[i].i != 0
+ if (out_attr[i].i == 0)
+ out_attr[i].i = in_attr[i].i;
+ else if (out_attr[i].i != 0 && in_attr[i].i != 0
&& out_attr[i].i != in_attr[i].i)
{
_bfd_error_handler
&& !bfd_elf_get_obj_attr_int (ibfd, OBJ_ATTR_PROC,
Tag_ARC_CPU_base))
{
- /* Warn if different flags. */
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: uses different e_flags (%#x) fields than "
- "previous modules (%#x)"),
- ibfd, in_flags, out_flags);
if (in_flags && out_flags)
- return FALSE;
+ {
+ /* Warn if different flags. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: uses different e_flags (%#x) fields than "
+ "previous modules (%#x)"),
+ ibfd, in_flags, out_flags);
+ return FALSE;
+ }
/* MWDT doesnt set the eflags hence make sure we choose the
eflags set by gcc. */
in_flags = in_flags > out_flags ? in_flags : out_flags;
+ (reloc_data.reloc_offset))))
#define SECTSTART (bfd_signed_vma) (reloc_data.sym_section->output_section->vma \
+ reloc_data.sym_section->output_offset)
+#define FINAL_SECTSTART \
+ (bfd_signed_vma) (reloc_data.sym_section->output_section->vma)
#define JLI (bfd_signed_vma) (reloc_data.sym_section->output_section->vma)
#define _SDA_BASE_ (bfd_signed_vma) (reloc_data.sdata_begin_symbol_vma)
#define TLS_REL (bfd_signed_vma) \
((elf_hash_table (info))->tls_sec->output_section->vma)
-#define TLS_TBSS (8)
+#define TLS_TBSS (align_power(TCB_SIZE, \
+ reloc_data.sym_section->alignment_power))
#define none (0)
if (sec != NULL && discarded_section (sec))
{
_bfd_clear_contents (howto, input_bfd, input_section,
- contents + rel->r_offset);
+ contents, rel->r_offset);
rel->r_info = 0;
rel->r_addend = 0;
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
{
- struct elf_link_hash_entry *h_old = h;
+ struct elf_arc_link_hash_entry *ah_old =
+ (struct elf_arc_link_hash_entry *) h;
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- if (h->got.glist == 0 && h_old->got.glist != h->got.glist)
- h->got.glist = h_old->got.glist;
+ struct elf_arc_link_hash_entry *ah =
+ (struct elf_arc_link_hash_entry *) h;
+
+ if (ah->got_ents == 0 && ah_old->got_ents != ah->got_ents)
+ ah->got_ents = ah_old->got_ents;
}
/* TODO: Need to validate what was the intention. */
if (is_reloc_for_GOT (howto) && !bfd_link_pic (info))
{
+ struct elf_arc_link_hash_entry *ah =
+ (struct elf_arc_link_hash_entry *) h;
/* TODO: Change it to use arc_do_relocation with
ARC_32 reloc. Try to use ADD_RELA macro. */
bfd_vma relocation =
+ reloc_data.sym_section->output_section->vma)
: 0);
- BFD_ASSERT (h->got.glist);
- bfd_vma got_offset = h->got.glist->offset;
+ BFD_ASSERT (ah->got_ents);
+ bfd_vma got_offset = ah->got_ents->offset;
bfd_put_32 (output_bfd, relocation,
htab->sgot->contents + got_offset);
}
reloc_data.should_relocate = TRUE;
struct got_entry **list
- = get_got_entry_list_for_symbol (output_bfd, r_symndx, h);
+ = get_got_entry_list_for_symbol (input_bfd, r_symndx, h);
reloc_data.got_offset_value
= relocate_fix_got_relocs_for_got_info (list,
if (r_symndx < symtab_hdr->sh_info) /* Is a local symbol. */
h = NULL;
else /* Global one. */
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ {
+ 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;
+ }
+
switch (r_type)
{
- case R_ARC_32:
- case R_ARC_32_ME:
- /* During shared library creation, these relocs should not
- appear in a shared library (as memory will be read only
- and the dynamic linker can not resolve these. However
- the error should not occur for e.g. debugging or
- non-readonly sections. */
- if (h != NULL
- && (bfd_link_dll (info) && !bfd_link_pie (info))
- && (sec->flags & SEC_ALLOC) != 0
- && (sec->flags & SEC_READONLY) != 0
- && ((sec->flags & SEC_CODE) != 0
- || (sec->flags & SEC_DEBUGGING) != 0))
- {
- const char *name;
- if (h)
- name = h->root.root.string;
- else
- /* bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); */
- name = "UNKNOWN";
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: relocation %s against `%s' can not be used"
- " when making a shared object; recompile with -fPIC"),
- abfd,
- arc_elf_howto (r_type)->name,
- name);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
+ case R_ARC_32:
+ case R_ARC_32_ME:
+ /* During shared library creation, these relocs should not
+ appear in a shared library (as memory will be read only
+ and the dynamic linker can not resolve these. However
+ the error should not occur for e.g. debugging or
+ non-readonly sections. */
+ if (h != NULL
+ && (bfd_link_dll (info) && !bfd_link_pie (info))
+ && (sec->flags & SEC_ALLOC) != 0
+ && (sec->flags & SEC_READONLY) != 0
+ && ((sec->flags & SEC_CODE) != 0
+ || (sec->flags & SEC_DEBUGGING) != 0))
+ {
+ const char *name;
+ if (h)
+ name = h->root.root.string;
+ else
+ name = "UNKNOWN";
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against `%s' can not be used"
+ " when making a shared object; recompile with -fPIC"),
+ abfd,
+ arc_elf_howto (r_type)->name,
+ name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
/* In some cases we are not setting the 'non_got_ref'
flag, even though the relocations don't require a GOT
if (h == NULL)
continue;
else
- h->needs_plt = 1;
+ if (h->forced_local == 0)
+ h->needs_plt = 1;
}
/* Add info to the symbol got_entry_list. */
if (is_reloc_for_GOT (howto)
|| is_reloc_for_TLS (howto))
{
+ if (bfd_link_dll (info) && !bfd_link_pie (info)
+ && (r_type == R_ARC_TLS_LE_32 || r_type == R_ARC_TLS_LE_S9))
+ {
+ const char *name;
+ if (h)
+ name = h->root.root.string;
+ else
+ /* bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); */
+ name = "UNKNOWN";
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: relocation %s against `%s' can not be used"
+ " when making a shared object; recompile with -fPIC"),
+ abfd,
+ arc_elf_howto (r_type)->name,
+ name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
if (! _bfd_elf_create_got_section (dynobj, info))
return FALSE;
create respective dynamic relocs. */
/* TODO: Make function to get list and not access the list directly. */
/* TODO: Move function to relocate_section create this relocs eagerly. */
- create_got_dynrelocs_for_got_info (&h->got.glist,
+ struct elf_arc_link_hash_entry *ah =
+ (struct elf_arc_link_hash_entry *) h;
+ create_got_dynrelocs_for_got_info (&ah->got_ents,
output_bfd,
info,
h);
{
struct elf_arc_link_hash_table *arc_htab = elf_arc_hash_table (info);
+ if (arc_htab == NULL)
+ return FALSE;
+
if (h->dynindx == -1
|| (h->root.type != bfd_link_hash_defined
&& h->root.type != bfd_link_hash_defweak)
s = bfd_get_linker_section (dynobj, SECTION); \
break;
+
+struct obfd_info_group {
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+};
+
+static bfd_boolean
+arc_create_forced_local_got_entries_for_tls (struct bfd_hash_entry *bh,
+ void *data)
+{
+ struct elf_arc_link_hash_entry * h =
+ (struct elf_arc_link_hash_entry *) bh;
+ struct obfd_info_group *tmp = (struct obfd_info_group *) data;
+
+ if (h->got_ents != NULL)
+ {
+ BFD_ASSERT (h);
+
+ struct got_entry *list = h->got_ents;
+
+ while (list != NULL)
+ {
+ create_got_dynrelocs_for_single_entry (list, tmp->output_bfd,
+ tmp->info,
+ (struct elf_link_hash_entry *) h);
+ list = list->next;
+ }
+ }
+
+ return TRUE;
+}
+
+
/* Function : elf_arc_finish_dynamic_sections
Brief : Finish up the dynamic sections handling.
Args : output_bfd :
}
}
+ struct obfd_info_group group;
+ group.output_bfd = output_bfd;
+ group.info = info;
+ bfd_hash_traverse (&info->hash->table,
+ arc_create_forced_local_got_entries_for_tls, &group);
+
return TRUE;
}
{
switch (hdr->sh_type)
{
+ case 0x0c: /* MWDT specific section, don't complain about it. */
case SHT_ARC_ATTRIBUTES:
break;