--- /dev/null
+/* ARC-specific support for 32-bit ELF
+ Copyright (C) 1994-2016 Free Software Foundation, Inc.
+ Contributed by Cupertino Miranda (cmiranda@synopsys.com).
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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. */
+
+#ifndef ARC_GOT_H
+#define ARC_GOT_H
+
+enum tls_type_e
+{
+ GOT_UNKNOWN = 0,
+ GOT_NORMAL,
+ GOT_TLS_GD,
+ GOT_TLS_IE,
+ GOT_TLS_LE
+};
+
+enum tls_got_entries
+{
+ TLS_GOT_NONE = 0,
+ TLS_GOT_MOD,
+ TLS_GOT_OFF,
+ TLS_GOT_MOD_AND_OFF
+};
+
+struct got_entry
+{
+ struct got_entry *next;
+ enum tls_type_e type;
+ bfd_vma offset;
+ bfd_boolean processed;
+ bfd_boolean created_dyn_relocation;
+ enum tls_got_entries existing_entries;
+};
+
+static struct got_entry **
+arc_get_local_got_ents (bfd * abfd)
+{
+ static struct got_entry **local_got_ents = NULL;
+
+ if (local_got_ents == NULL)
+ {
+ size_t size;
+ Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
+
+ size = symtab_hdr->sh_info * sizeof (bfd_vma);
+ local_got_ents = (struct got_entry **)
+ bfd_alloc (abfd, sizeof (struct got_entry *) * size);
+ if (local_got_ents == NULL)
+ return FALSE;
+
+ memset (local_got_ents, 0, sizeof (struct got_entry *) * size);
+ elf_local_got_ents (abfd) = local_got_ents;
+ }
+
+ return local_got_ents;
+}
+
+static struct got_entry *
+got_entry_for_type (struct got_entry **list,
+ enum tls_type_e type)
+{
+ struct got_entry **p = list;
+ while (*p != NULL)
+ {
+ if ((*p)->type == type)
+ return *p;
+ p = &((*p)->next);
+ }
+ return NULL;
+}
+
+static void
+new_got_entry_to_list (struct got_entry **list,
+ enum tls_type_e type,
+ bfd_vma offset,
+ enum tls_got_entries existing_entries)
+{
+ /* Find list end. Avoid having multiple entries of the same
+ type. */
+ struct got_entry **p = list;
+ while (*p != NULL)
+ {
+ if ((*p)->type == type)
+ return;
+ p = &((*p)->next);
+ }
+
+ struct got_entry *entry
+ = (struct got_entry *) malloc (sizeof (struct got_entry));
+
+ entry->type = type;
+ entry->offset = offset;
+ entry->next = NULL;
+ entry->processed = FALSE;
+ entry->created_dyn_relocation = FALSE;
+ entry->existing_entries = existing_entries;
+
+ ARC_DEBUG ("New GOT got entry added to list: "
+ "type: %d, offset: %d, existing_entries:%d\n",
+ type, offset, existing_entries);
+
+ /* Add the entry to the end of the list. */
+ *p = entry;
+}
+
+static enum tls_type_e
+tls_type_for_reloc (reloc_howto_type *howto)
+{
+ enum tls_type_e ret = GOT_UNKNOWN;
+ if (is_reloc_for_GOT (howto))
+ ret = GOT_NORMAL;
+ else
+ {
+ switch (howto->type)
+ {
+ case R_ARC_TLS_GD_GOT:
+ ret = GOT_TLS_GD;
+ break;
+ case R_ARC_TLS_IE_GOT:
+ ret = GOT_TLS_IE;
+ break;
+ case R_ARC_TLS_LE_32:
+ ret = GOT_TLS_LE;
+ break;
+ default:
+ ret = GOT_UNKNOWN;
+ break;
+ }
+ }
+ return ret;
+};
+
+static struct got_entry **
+get_got_entry_list_for_symbol (bfd *abfd,
+ unsigned long r_symndx,
+ struct elf_link_hash_entry *h)
+{
+ if (h != NULL)
+ {
+ return &h->got.glist;
+ }
+ else
+ {
+ struct got_entry **local_got_ents
+ = arc_get_local_got_ents (abfd);
+ return &local_got_ents[r_symndx];
+ }
+}
+
+
+static enum tls_type_e
+arc_got_entry_type_for_reloc (reloc_howto_type *howto)
+{
+ enum tls_type_e type = GOT_UNKNOWN;
+
+ if (is_reloc_for_GOT (howto))
+ type = GOT_NORMAL;
+ else if (is_reloc_for_TLS (howto))
+ {
+ switch (howto->type)
+ {
+ case R_ARC_TLS_GD_GOT:
+ type = GOT_TLS_GD;
+ break;
+ case R_ARC_TLS_IE_GOT:
+ type = GOT_TLS_IE;
+ break;
+ default:
+ break;
+ }
+ }
+ return type;
+}
+
+#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
+ htab->s##SECNAME->size; \
+ { \
+ if (COND_FOR_RELOC) \
+ { \
+ htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \
+ ARC_DEBUG ("arc_info: Added reloc space in " \
+ #SECNAME " section at " __FILE__ \
+ ":%d for symbol %s\n", \
+ __LINE__, name_for_global_symbol (H)); \
+ } \
+ if (H) \
+ if (h->dynindx == -1 && !h->forced_local) \
+ if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
+ return FALSE; \
+ htab->s##SECNAME->size += 4; \
+ } \
+
+static bfd_boolean
+arc_fill_got_info_for_reloc (enum tls_type_e type,
+ struct got_entry **list,
+ struct bfd_link_info * info,
+ struct elf_link_hash_entry *h)
+{
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ if (got_entry_for_type (list, type) != NULL)
+ return TRUE;
+
+ switch (type)
+ {
+ case GOT_NORMAL:
+ {
+ bfd_vma offset
+ = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
+ || h != NULL, h);
+ new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
+ }
+ break;
+
+
+ case GOT_TLS_GD:
+ {
+ bfd_vma offset
+ = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
+ bfd_vma ATTRIBUTE_UNUSED notneeded
+ = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
+ new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF);
+ }
+ break;
+ case GOT_TLS_IE:
+ case GOT_TLS_LE:
+ {
+ bfd_vma offset
+ = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
+ new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
+ }
+ break;
+
+ default:
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+
+static bfd_vma
+relocate_fix_got_relocs_for_got_info (struct got_entry **list_p,
+ enum tls_type_e type,
+ struct bfd_link_info * info,
+ bfd *output_bfd,
+ unsigned long r_symndx,
+ Elf_Internal_Sym *local_syms,
+ asection **local_sections,
+ struct elf_link_hash_entry *h,
+ struct arc_relocation_data *reloc_data)
+{
+
+ if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
+ return 0;
+
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+ struct got_entry *entry = NULL;
+
+ entry = got_entry_for_type (list_p, type);
+ BFD_ASSERT (entry);
+
+ if (h == NULL
+ || (! elf_hash_table (info)->dynamic_sections_created
+ || (bfd_link_pic (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h))))
+ {
+ const char ATTRIBUTE_UNUSED *symbol_name;
+ static const char local_name[] = "(local)";
+ asection *tls_sec = NULL;
+ bfd_vma sym_value = 0;
+
+ if (h != NULL)
+ {
+ // TODO: This should not be here.
+ reloc_data->sym_value = h->root.u.def.value;
+ reloc_data->sym_section = h->root.u.def.section;
+
+ sym_value = h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset;
+
+ tls_sec = elf_hash_table (info)->tls_sec;
+
+ symbol_name = h->root.root.string;
+ }
+ else
+ {
+ Elf_Internal_Sym *sym = local_syms + r_symndx;
+ asection *sec = local_sections[r_symndx];
+
+ sym_value = sym->st_value
+ + sec->output_section->vma
+ + sec->output_offset;
+
+ tls_sec = elf_hash_table (info)->tls_sec;
+
+ symbol_name = local_name;
+ }
+
+
+ if (entry && entry->processed == FALSE)
+ {
+ switch (entry->type)
+ {
+ case GOT_TLS_GD:
+ {
+ BFD_ASSERT (tls_sec && tls_sec->output_section);
+ bfd_vma sec_vma = tls_sec->output_section->vma;
+
+ bfd_put_32 (output_bfd,
+ sym_value - sec_vma,
+ htab->sgot->contents + entry->offset
+ + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
+ ? 4 : 0));
+
+ ARC_DEBUG ("arc_info: FIXED -> %s value = 0x%x "
+ "@ 0x%x, for symbol %s\n",
+ (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
+ "GOT_TLS_IE"),
+ sym_value - sec_vma,
+ htab->sgot->contents + entry->offset
+ + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
+ ? 4 : 0),
+ symbol_name);
+ }
+ break;
+
+ case GOT_TLS_IE:
+ {
+ BFD_ASSERT (tls_sec && tls_sec->output_section);
+ bfd_vma ATTRIBUTE_UNUSED sec_vma
+ = tls_sec->output_section->vma;
+
+ ARC_DEBUG ("arc_info: FIXED -> %s value = 0x%x "
+ "@ 0x%x, for symbol %s\n",
+ (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
+ "GOT_TLS_IE"),
+ sym_value - sec_vma,
+ htab->sgot->contents + entry->offset
+ + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
+ ? 4 : 0),
+ symbol_name);
+ }
+ break;
+
+ case GOT_NORMAL:
+ {
+ bfd_vma sec_vma
+ = reloc_data->sym_section->output_section->vma
+ + reloc_data->sym_section->output_offset;
+
+ if (h->root.type != bfd_link_hash_undefweak)
+ {
+ bfd_put_32 (output_bfd,
+ reloc_data->sym_value + sec_vma,
+ htab->sgot->contents + entry->offset);
+
+ ARC_DEBUG ("arc_info: PATCHED: 0x%08x "
+ "@ 0x%08x for sym %s in got offset 0x%x\n",
+ reloc_data->sym_value + sec_vma,
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + entry->offset,
+ symbol_name,
+ entry->offset);
+ }
+ else
+ {
+ ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
+ "@ 0x%08x for sym %s in got offset 0x%x "
+ "(is undefweak)\n",
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + entry->offset,
+ symbol_name,
+ entry->offset);
+ }
+ }
+ break;
+ default:
+ BFD_ASSERT (0);
+ break;
+ }
+ entry->processed = TRUE;
+ }
+ }
+
+ return entry->offset;
+}
+
+static void
+create_got_dynrelocs_for_single_entry (struct got_entry *list,
+ bfd *output_bfd,
+ struct bfd_link_info * info,
+ struct elf_link_hash_entry *h)
+{
+ if (list == NULL)
+ return;
+
+ bfd_vma got_offset = list->offset;
+
+ if (list->type == GOT_NORMAL
+ && list->created_dyn_relocation == FALSE)
+ {
+ if (bfd_link_pic (info)
+ && h != NULL
+ && (info->symbolic || h->dynindx == -1)
+ && h->def_regular)
+ {
+ ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
+ }
+ /* Do not fully understand the side effects of this condition.
+ The relocation space might still being reserved. Perhaps
+ I should clear its value. */
+ else if (h != NULL && h->dynindx != -1)
+ {
+ ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
+ }
+ list->created_dyn_relocation = TRUE;
+ }
+ else if (list->existing_entries != TLS_GOT_NONE
+ && list->created_dyn_relocation == FALSE)
+ {
+ /* TODO TLS: This is not called for local symbols.
+ In order to correctly implement TLS, this should also
+ be called for all local symbols with tls got entries.
+ Should be moved to relocate_section in order to make it
+ work for local symbols. */
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+ enum tls_got_entries e = list->existing_entries;
+
+ BFD_ASSERT (list->type != GOT_TLS_GD
+ || list->existing_entries == TLS_GOT_MOD_AND_OFF);
+
+ bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
+
+ if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
+ {
+ ADD_RELA (output_bfd, got, got_offset, dynindx,
+ R_ARC_TLS_DTPMOD, 0);
+ ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
+GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
+ list->type,
+ got_offset,
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + got_offset,
+ dynindx, 0);
+ }
+ if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
+ {
+ bfd_vma addend = 0;
+ if (list->type == GOT_TLS_IE)
+ addend = bfd_get_32 (output_bfd,
+ htab->sgot->contents + got_offset);
+
+ ADD_RELA (output_bfd, got,
+ got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
+ dynindx,
+ (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
+ : R_ARC_TLS_DTPOFF),
+ addend);
+
+ ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
+GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
+ list->type,
+ got_offset,
+ htab->sgot->output_section->vma
+ + htab->sgot->output_offset + got_offset,
+ dynindx, addend);
+ }
+ list->created_dyn_relocation = TRUE;
+ }
+}
+
+static void
+create_got_dynrelocs_for_got_info (struct got_entry **list_p,
+ bfd *output_bfd,
+ struct bfd_link_info * info,
+ struct elf_link_hash_entry *h)
+{
+ if (list_p == NULL)
+ return;
+
+ struct got_entry *list = *list_p;
+ /* Traverse the list of got entries for this symbol. */
+ while (list)
+ {
+ create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
+ list = list->next;
+ }
+}
+
+#undef ADD_SYMBOL_REF_SEC_AND_RELOC
+
+#endif /* ARC_GOT_H */
# define PR_DEBUG(fmt, args...)
#endif
-/* #define ARC_ENABLE_DEBUG 1 */
+/* #define ARC_ENABLE_DEBUG 1 */
#ifndef ARC_ENABLE_DEBUG
#define ARC_DEBUG(...)
#else
Elf_Internal_Rela _rel; \
bfd_byte * _loc; \
\
+ BFD_ASSERT (_htab->srel##SECTION &&_htab->srel##SECTION->contents); \
_loc = _htab->srel##SECTION->contents \
+ ((_htab->srel##SECTION->reloc_count) \
* sizeof (Elf32_External_Rela)); \
".rela.plt"
};
-enum tls_type_e
-{
- GOT_UNKNOWN = 0,
- GOT_NORMAL,
- GOT_TLS_GD,
- GOT_TLS_IE,
- GOT_TLS_LE
-};
-
-enum tls_got_entries
-{
- TLS_GOT_NONE = 0,
- TLS_GOT_MOD,
- TLS_GOT_OFF,
- TLS_GOT_MOD_AND_OFF
-};
-
-struct got_entry
-{
- struct got_entry *next;
- enum tls_type_e type;
- bfd_vma offset;
- bfd_boolean processed;
- bfd_boolean created_dyn_relocation;
- enum tls_got_entries existing_entries;
-};
-
-static void
-new_got_entry_to_list (struct got_entry **list,
- enum tls_type_e type,
- bfd_vma offset,
- enum tls_got_entries existing_entries)
-{
- /* Find list end. Avoid having multiple entries of the same
- type. */
- struct got_entry **p = list;
- while (*p != NULL)
- {
- if ((*p)->type == type)
- return;
- p = &((*p)->next);
- }
-
- struct got_entry *entry =
- (struct got_entry *) malloc (sizeof(struct got_entry));
-
- entry->type = type;
- entry->offset = offset;
- entry->next = NULL;
- entry->processed = FALSE;
- entry->created_dyn_relocation = FALSE;
- entry->existing_entries = existing_entries;
-
- /* Add the entry to the end of the list. */
- *p = entry;
-}
-
-static bfd_boolean
-symbol_has_entry_of_type (struct got_entry *list, enum tls_type_e type)
-{
- while (list != NULL)
- {
- if (list->type == type)
- return TRUE;
- list = list->next;
- }
-
- return FALSE;
-}
/* The default symbols representing the init and fini dyn values.
TODO: Check what is the relation of those strings with arclinux.em
return (strstr (howto->name, "TLS") != NULL) ? TRUE : FALSE;
}
+struct arc_relocation_data
+{
+ bfd_signed_vma reloc_offset;
+ bfd_signed_vma reloc_addend;
+ bfd_signed_vma got_offset_value;
+
+ bfd_signed_vma sym_value;
+ asection * sym_section;
+
+ reloc_howto_type *howto;
+
+ asection * input_section;
+
+ bfd_signed_vma sdata_begin_symbol_vma;
+ bfd_boolean sdata_begin_symbol_vma_set;
+ bfd_signed_vma got_symbol_vma;
+
+ bfd_boolean should_relocate;
+
+ const char * symbol_name;
+};
+
+/* Should be included at this location due to static declarations
+ * defined before this point. */
+#include "arc-got.h"
+
#define arc_bfd_get_8(A,B,C) bfd_get_8(A,B)
#define arc_bfd_get_16(A,B,C) bfd_get_16(A,B)
#define arc_bfd_get_32(A,B,C) bfd_get_32(A,B)
struct arc_reloc_map
{
bfd_reloc_code_real_type bfd_reloc_val;
- unsigned char elf_reloc_val;
+ unsigned char elf_reloc_val;
};
#define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
mach = bfd_mach_arc_arcv2;
break;
default:
- mach = (e_machine == EM_ARC_COMPACT) ?
- bfd_mach_arc_arc700 : bfd_mach_arc_arcv2;
+ mach = (e_machine == EM_ARC_COMPACT)
+ ? bfd_mach_arc_arc700 : bfd_mach_arc_arcv2;
break;
}
}
#define BFD_DEBUG_PIC(...)
-struct arc_relocation_data
-{
- bfd_signed_vma reloc_offset;
- bfd_signed_vma reloc_addend;
- bfd_signed_vma got_offset_value;
-
- bfd_signed_vma sym_value;
- asection * sym_section;
-
- reloc_howto_type *howto;
-
- asection * input_section;
-
- bfd_signed_vma sdata_begin_symbol_vma;
- bfd_boolean sdata_begin_symbol_vma_set;
- bfd_signed_vma got_symbol_vma;
-
- bfd_boolean should_relocate;
-
- const char * symbol_name;
-};
static void
debug_arc_reloc (struct arc_relocation_data reloc_data)
(unsigned int) reloc_data.input_section->output_offset,
(unsigned int) reloc_data.input_section->output_section->vma);
PR_DEBUG ( " changed_address = 0x%08x\n",
- (unsigned int) (reloc_data.input_section->output_section->vma +
- reloc_data.input_section->output_offset +
- reloc_data.reloc_offset));
+ (unsigned int) (reloc_data.input_section->output_section->vma
+ + reloc_data.input_section->output_offset
+ + reloc_data.reloc_offset));
PR_DEBUG (" file: %s\n", reloc_data.input_section->owner->filename);
}
else
{
if (do_it)
{
- insn =
- ((insn & 0xffff0000) >> 16) |
- ((insn & 0xffff) << 16);
+ insn
+ = ((insn & 0xffff0000) >> 16)
+ | ((insn & 0xffff) << 16);
}
return insn;
}
static inline bfd_reloc_status_type
arc_special_overflow_checks (const struct arc_relocation_data reloc_data,
- bfd_signed_vma relocation,
+ bfd_signed_vma relocation,
struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
switch (reloc_data.howto->type)
{
case R_ARC_NPS_CMEM16:
if (((relocation >> 16) & 0xffff) != NPS_CMEM_HIGH_VALUE)
- {
- if (reloc_data.reloc_addend == 0)
- (*_bfd_error_handler)
- (_("%B(%A+0x%lx): CMEM relocation to `%s' is invalid, "
- "16 MSB should be 0x%04x (value is 0x%lx)"),
- reloc_data.input_section->owner,
- reloc_data.input_section,
- reloc_data.reloc_offset,
- reloc_data.symbol_name,
- NPS_CMEM_HIGH_VALUE,
- (relocation));
- else
- (*_bfd_error_handler)
- (_("%B(%A+0x%lx): CMEM relocation to `%s+0x%lx' is invalid, "
- "16 MSB should be 0x%04x (value is 0x%lx)"),
- reloc_data.input_section->owner,
- reloc_data.input_section,
- reloc_data.reloc_offset,
- reloc_data.symbol_name,
- reloc_data.reloc_addend,
- NPS_CMEM_HIGH_VALUE,
- (relocation));
- return bfd_reloc_overflow;
- }
+ {
+ if (reloc_data.reloc_addend == 0)
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): CMEM relocation to `%s' is invalid, "
+ "16 MSB should be 0x%04x (value is 0x%lx)"),
+ reloc_data.input_section->owner,
+ reloc_data.input_section,
+ reloc_data.reloc_offset,
+ reloc_data.symbol_name,
+ NPS_CMEM_HIGH_VALUE,
+ (relocation));
+ else
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): CMEM relocation to `%s+0x%lx' is invalid, "
+ "16 MSB should be 0x%04x (value is 0x%lx)"),
+ reloc_data.input_section->owner,
+ reloc_data.input_section,
+ reloc_data.reloc_offset,
+ reloc_data.symbol_name,
+ reloc_data.reloc_addend,
+ NPS_CMEM_HIGH_VALUE,
+ (relocation));
+ return bfd_reloc_overflow;
+ }
break;
default:
/* Check for relocation overflow. */
if (reloc_data.howto->complain_on_overflow != complain_overflow_dont)
flag = bfd_check_overflow (reloc_data.howto->complain_on_overflow,
- reloc_data.howto->bitsize,
- reloc_data.howto->rightshift,
- bfd_arch_bits_per_address (abfd),
- relocation);
+ reloc_data.howto->bitsize,
+ reloc_data.howto->rightshift,
+ bfd_arch_bits_per_address (abfd),
+ relocation);
else
flag = arc_special_overflow_checks (reloc_data, relocation, info);
DEBUG_ARC_RELOC (reloc_data);
PR_DEBUG (
- "Relocation value = signed -> %d, unsigned -> %u"
- ", hex -> (0x%08x)\n",
- (int) relocation,
- (unsigned int) relocation,
- (unsigned int) relocation);
+ "Relocation value = signed -> %d, unsigned -> %u"
+ ", hex -> (0x%08x)\n",
+ (int) relocation,
+ (unsigned int) relocation,
+ (unsigned int) relocation);
return flag;
}
#undef DEBUG_ARC_RELOC
#undef ARC_RELOC_HOWTO
-static struct got_entry **
-arc_get_local_got_ents (bfd * abfd)
-{
- static struct got_entry **local_got_ents = NULL;
-
- if (local_got_ents == NULL)
- {
- size_t size;
- Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
-
- size = symtab_hdr->sh_info * sizeof (bfd_vma);
- local_got_ents = (struct got_entry **)
- bfd_alloc (abfd, sizeof(struct got_entry *) * size);
- if (local_got_ents == NULL)
- return FALSE;
-
- memset (local_got_ents, 0, sizeof(struct got_entry *) * size);
- elf_local_got_ents (abfd) = local_got_ents;
- }
-
- return local_got_ents;
-}
/* Relocate an arc ELF section.
Function : elf_arc_relocate_section
{
Elf_Internal_Shdr * symtab_hdr;
struct elf_link_hash_entry ** sym_hashes;
- struct got_entry ** local_got_ents;
Elf_Internal_Rela * rel;
Elf_Internal_Rela * wrel;
Elf_Internal_Rela * relend;
/* TODO: Verify this condition. */
{
reloc_data.sdata_begin_symbol_vma =
- (h2->root.u.def.value +
- h2->root.u.def.section->output_section->vma);
+ (h2->root.u.def.value
+ + h2->root.u.def.section->output_section->vma);
reloc_data.sdata_begin_symbol_vma_set = TRUE;
}
if (r_symndx < symtab_hdr->sh_info) /* A local symbol. */
{
- struct got_entry *entry;
-
- local_got_ents = arc_get_local_got_ents (output_bfd);
- entry = local_got_ents[r_symndx];
-
reloc_data.sym_value = sym->st_value;
reloc_data.sym_section = sec;
reloc_data.symbol_name =
reloc_data.reloc_addend = rel->r_addend;
}
- if ((is_reloc_for_GOT (howto)
- || is_reloc_for_TLS (howto)) && entry != NULL)
- {
- if (is_reloc_for_TLS (howto))
- while (entry->type == GOT_NORMAL && entry->next != NULL)
- entry = entry->next;
-
- if (is_reloc_for_GOT (howto))
- while (entry->type != GOT_NORMAL && entry->next != NULL)
- entry = entry->next;
-
- if (entry->type == GOT_TLS_GD && entry->processed == FALSE)
- {
- bfd_vma sym_vma = sym->st_value
- + sec->output_section->vma
- + sec->output_offset;
-
- /* Create dynamic relocation for local sym. */
- ADD_RELA (output_bfd, got, entry->offset, 0,
- R_ARC_TLS_DTPMOD, 0);
- ADD_RELA (output_bfd, got, entry->offset+4, 0,
- R_ARC_TLS_DTPOFF, 0);
-
- bfd_vma sec_vma = sec->output_section->vma
- + sec->output_offset;
- bfd_put_32 (output_bfd, sym_vma - sec_vma,
- htab->sgot->contents + entry->offset + 4);
-
- ARC_DEBUG ("arc_info: FIXED -> GOT_TLS_GD value "
- "= 0x%x @ 0x%x, for symbol %s\n",
- sym_vma - sec_vma,
- htab->sgot->contents + entry->offset + 4,
- "(local)");
-
- entry->processed = TRUE;
- }
- if (entry->type == GOT_TLS_IE && entry->processed == FALSE)
- {
- bfd_vma sym_vma = sym->st_value
- + sec->output_section->vma
- + sec->output_offset;
- bfd_vma sec_vma = htab->tls_sec->output_section->vma;
- bfd_put_32 (output_bfd, sym_vma - sec_vma,
- htab->sgot->contents + entry->offset);
- /* TODO: Check if this type of relocs is the cause
- for all the ARC_NONE dynamic relocs. */
-
- ARC_DEBUG ("arc_info: FIXED -> GOT_TLS_IE value = "
- "0x%x @ 0x%x, for symbol %s\n",
- sym_vma - sec_vma,
- htab->sgot->contents + entry->offset,
- "(local)");
-
- entry->processed = TRUE;
- }
- if (entry->type == GOT_NORMAL && entry->processed == FALSE)
- {
- bfd_vma sec_vma = reloc_data.sym_section->output_section->vma
- + reloc_data.sym_section->output_offset;
-
- bfd_put_32 (output_bfd, reloc_data.sym_value + sec_vma,
- htab->sgot->contents + entry->offset);
-
- ARC_DEBUG ("arc_info: PATCHED: 0x%08x @ 0x%08x for "
- "sym %s in got offset 0x%x\n",
- reloc_data.sym_value + sec_vma,
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + entry->offset,
- "(local)",
- entry->offset);
- entry->processed = TRUE;
- }
-
- reloc_data.got_offset_value = entry->offset;
- ARC_DEBUG ("arc_info: GOT_ENTRY = %d, offset = 0x%x, "
- "vma = 0x%x for symbol %s\n",
- entry->type, entry->offset,
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + entry->offset,
- "(local)");
- }
-
BFD_ASSERT (htab->sgot != NULL || !is_reloc_for_GOT (howto));
if (htab->sgot != NULL)
reloc_data.got_symbol_vma = htab->sgot->output_section->vma
rel->r_offset, TRUE);
}
- if (h->got.glist != NULL)
- {
- struct got_entry *entry = h->got.glist;
-
- if (is_reloc_for_GOT (howto) || is_reloc_for_TLS (howto))
- {
- if (! elf_hash_table (info)->dynamic_sections_created
- || (bfd_link_pic (info)
- && SYMBOL_REFERENCES_LOCAL (info, h)))
- {
- reloc_data.sym_value = h->root.u.def.value;
- reloc_data.sym_section = h->root.u.def.section;
-
- if (is_reloc_for_TLS (howto))
- while (entry->type == GOT_NORMAL && entry->next != NULL)
- entry = entry->next;
-
- if (entry->processed == FALSE
- && (entry->type == GOT_TLS_GD
- || entry->type == GOT_TLS_IE))
- {
- bfd_vma sym_value = h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset;
-
- bfd_vma sec_vma =
- elf_hash_table (info)->tls_sec->output_section->vma;
-
- bfd_put_32 (output_bfd,
- sym_value - sec_vma,
- htab->sgot->contents + entry->offset
- + (entry->existing_entries == TLS_GOT_MOD_AND_OFF ? 4 : 0));
-
- ARC_DEBUG ("arc_info: FIXED -> %s value = 0x%x "
- "@ 0x%x, for symbol %s\n",
- (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
- "GOT_TLS_IE"),
- sym_value - sec_vma,
- htab->sgot->contents + entry->offset
- + (entry->existing_entries == TLS_GOT_MOD_AND_OFF ? 4 : 0),
- h->root.root.string);
-
- entry->processed = TRUE;
- }
-
- if (entry->type == GOT_TLS_IE && entry->processed == FALSE)
- {
- bfd_vma sec_vma = htab->tls_sec->output_section->vma;
- bfd_put_32 (output_bfd,
- reloc_data.sym_value - sec_vma,
- htab->sgot->contents + entry->offset);
- }
-
- if (entry->type == GOT_NORMAL && entry->processed == FALSE)
- {
- bfd_vma sec_vma =
- reloc_data.sym_section->output_section->vma
- + reloc_data.sym_section->output_offset;
-
- if (h->root.type != bfd_link_hash_undefweak)
- {
- bfd_put_32 (output_bfd,
- reloc_data.sym_value + sec_vma,
- htab->sgot->contents + entry->offset);
-
- ARC_DEBUG ("arc_info: PATCHED: 0x%08x "
- "@ 0x%08x for sym %s in got offset 0x%x\n",
- reloc_data.sym_value + sec_vma,
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + entry->offset,
- h->root.root.string,
- entry->offset);
- }
- else
- {
- ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
- "@ 0x%08x for sym %s in got offset 0x%x "
- "(is undefweak)\n",
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + entry->offset,
- h->root.root.string,
- entry->offset);
- }
-
- entry->processed = TRUE;
- }
- }
- }
-
- reloc_data.got_offset_value = entry->offset;
-
- ARC_DEBUG ("arc_info: GOT_ENTRY = %d, offset = 0x%x, "
- "vma = 0x%x for symbol %s\n",
- entry->type, entry->offset,
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + entry->offset,
- h->root.root.string);
- }
-
BFD_ASSERT (htab->sgot != NULL || !is_reloc_for_GOT (howto));
if (htab->sgot != NULL)
reloc_data.got_symbol_vma = htab->sgot->output_section->vma
+ htab->sgot->output_offset;
}
+ if ((is_reloc_for_GOT (howto)
+ || is_reloc_for_TLS (howto)))
+ {
+ struct got_entry **list
+ = get_got_entry_list_for_symbol (output_bfd, r_symndx, h);
+
+ reloc_data.got_offset_value
+ = relocate_fix_got_relocs_for_got_info (list,
+ tls_type_for_reloc (howto),
+ info,
+ output_bfd,
+ r_symndx,
+ local_syms,
+ local_sections,
+ h,
+ &reloc_data);
+
+ if (h == NULL)
+ {
+ create_got_dynrelocs_for_single_entry (
+ got_entry_for_type (list,
+ arc_got_entry_type_for_reloc (howto)),
+ output_bfd, info, NULL);
+ }
+ }
switch (r_type)
{
case R_ARC_32:
case R_ARC_32_ME:
case R_ARC_PC32:
case R_ARC_32_PCREL:
- if ((bfd_link_pic (info) || bfd_link_pie (info))
+ if ((bfd_link_pic (info))// || bfd_link_pie (info))
&& ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL)
|| (h != NULL
&& h->dynindx != -1
DEBUG_ARC_RELOC (reloc_data);
/* Make sure we have with a dynamic linker. In case of GOT and PLT
- the sym_section should point to .got or .plt respectively. */
+ the sym_section should point to .got or .plt respectively. */
if ((is_reloc_for_GOT (howto) || is_reloc_for_PLT (howto))
&& reloc_data.sym_section == NULL)
{
return ds;
}
-#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
- htab->s##SECNAME->size; \
- { \
- if (COND_FOR_RELOC) \
- { \
- htab->srel##SECNAME->size += sizeof (Elf32_External_Rela); \
- ARC_DEBUG ("arc_info: Added reloc space in " \
- #SECNAME " section at " __FILE__ \
- ":%d for symbol\n", \
- __LINE__, name_for_global_symbol (H)); \
- } \
- if (H) \
- if (h->dynindx == -1 && !h->forced_local) \
- if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
- return FALSE; \
- htab->s##SECNAME->size += 4; \
- }
-
static bfd_boolean
-elf_arc_check_relocs (bfd * abfd,
+elf_arc_check_relocs (bfd * abfd,
struct bfd_link_info * info,
asection * sec,
const Elf_Internal_Rela * relocs)
{
Elf_Internal_Shdr * symtab_hdr;
struct elf_link_hash_entry ** sym_hashes;
- struct got_entry ** local_got_ents;
const Elf_Internal_Rela * rel;
const Elf_Internal_Rela * rel_end;
bfd * dynobj;
asection * sreloc = NULL;
- struct elf_link_hash_table * htab = elf_hash_table (info);
if (bfd_link_relocatable (info))
return TRUE;
dynobj = (elf_hash_table (info))->dynobj;
symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
sym_hashes = elf_sym_hashes (abfd);
- local_got_ents = arc_get_local_got_ents (abfd);
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
/* FALLTHROUGH */
case R_ARC_PC32:
case R_ARC_32_PCREL:
- if ((bfd_link_pic (info) || bfd_link_pie (info))
+ if ((bfd_link_pic (info))// || bfd_link_pie (info))
&& ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL)
|| (h != NULL
&& h->dynindx != -1
h->needs_plt = 1;
}
- if (is_reloc_for_GOT (howto) == TRUE)
- {
- if (h == NULL)
- {
- /* Local symbol. */
- if (local_got_ents[r_symndx] == NULL)
- {
- bfd_vma offset =
- ADD_SYMBOL_REF_SEC_AND_RELOC (got,
- bfd_link_pic (info),
- NULL);
- new_got_entry_to_list (&(local_got_ents[r_symndx]),
- GOT_NORMAL, offset, TLS_GOT_NONE);
- }
- }
- else
- {
- /* Global symbol. */
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (h->got.glist == NULL)
- {
- bfd_vma offset =
- ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
- new_got_entry_to_list (&h->got.glist,
- GOT_NORMAL, offset, TLS_GOT_NONE);
- }
- }
- }
-
- if (is_reloc_for_TLS (howto) == TRUE)
+ /* Add info to the symbol got_entry_list. */
+ if (is_reloc_for_GOT (howto) == TRUE
+ || is_reloc_for_TLS (howto) == TRUE)
{
- enum tls_type_e type = GOT_UNKNOWN;
-
- switch (r_type)
- {
- case R_ARC_TLS_GD_GOT:
- type = GOT_TLS_GD;
- break;
- case R_ARC_TLS_IE_GOT:
- type = GOT_TLS_IE;
- break;
- default:
- break;
- }
-
- struct got_entry **list = NULL;
- if (h != NULL)
- list = &(h->got.glist);
- else
- list = &(local_got_ents[r_symndx]);
-
- if (type != GOT_UNKNOWN && !symbol_has_entry_of_type (*list, type))
- {
- enum tls_got_entries entries = TLS_GOT_NONE;
- bfd_vma offset =
- ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
-
- if (type == GOT_TLS_GD)
- {
- bfd_vma ATTRIBUTE_UNUSED notneeded =
- ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
- entries = TLS_GOT_MOD_AND_OFF;
- }
-
- if (entries == TLS_GOT_NONE)
- entries = TLS_GOT_OFF;
-
- new_got_entry_to_list (list, type, offset, entries);
- }
+ arc_fill_got_info_for_reloc (
+ arc_got_entry_type_for_reloc (howto),
+ get_got_entry_list_for_symbol (abfd, r_symndx, h),
+ info,
+ h);
}
}
switch (SYM_ONLY (reloc->symbol))
{
case SGOT:
- relocation =
- htab->sgotplt->output_section->vma +
- htab->sgotplt->output_offset + symbol_got_offset;
+ relocation
+ = htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset + symbol_got_offset;
break;
}
relocation += reloc->addend;
section of which is applying the relocation. */
if (IS_MIDDLE_ENDIAN (reloc->symbol) && !bfd_big_endian (abfd))
{
- relocation =
- ((relocation & 0xffff0000) >> 16) |
- ((relocation & 0xffff) << 16);
+ relocation
+ = ((relocation & 0xffff0000) >> 16)
+ | ((relocation & 0xffff) << 16);
}
switch (reloc->size)
{
bfd_vma loc = add_symbol_to_plt (info);
- if (!bfd_link_pic (info) && !h->def_regular)
+ if (bfd_link_executable (info) && !h->def_regular)
{
h->root.u.def.section = htab->splt;
h->root.u.def.value = loc;
}
}
- if (h->got.glist != NULL)
- {
- struct got_entry *list = h->got.glist;
- /* Traverse the list of got entries for this symbol. */
- while (list)
- {
- bfd_vma got_offset = h->got.glist->offset;
-
- if (list->type == GOT_NORMAL
- && list->created_dyn_relocation == FALSE)
- {
- if (bfd_link_pic (info)
- && (info->symbolic || h->dynindx == -1)
- && h->def_regular)
- {
- ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
- }
- /* Do not fully understand the side effects of this condition.
- The relocation space might still being reserved. Perhaps
- I should clear its value. */
- else if (h->dynindx != -1)
- {
- ADD_RELA (output_bfd, got, got_offset, h->dynindx,
- R_ARC_GLOB_DAT, 0);
- }
- list->created_dyn_relocation = TRUE;
- }
- else if (list->existing_entries != TLS_GOT_NONE)
- {
- struct elf_link_hash_table *htab = elf_hash_table (info);
- enum tls_got_entries e = list->existing_entries;
-
- BFD_ASSERT (list->type != GOT_TLS_GD
- || list->existing_entries == TLS_GOT_MOD_AND_OFF);
-
- bfd_vma dynindx = h->dynindx == -1 ? 0 : h->dynindx;
- if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
- {
- ADD_RELA (output_bfd, got, got_offset, dynindx,
- R_ARC_TLS_DTPMOD, 0);
- ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
-GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
- list->type,
- got_offset,
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + got_offset,
- dynindx, 0);
- }
- if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
- {
- bfd_vma addend = 0;
- if (list->type == GOT_TLS_IE)
- addend = bfd_get_32 (output_bfd,
- htab->sgot->contents + got_offset);
-
- ADD_RELA (output_bfd, got,
- got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
- dynindx,
- (list->type == GOT_TLS_IE ?
- R_ARC_TLS_TPOFF : R_ARC_TLS_DTPOFF),
- addend);
-
- ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
-GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
- list->type,
- got_offset,
- htab->sgot->output_section->vma
- + htab->sgot->output_offset + got_offset,
- dynindx, addend);
- }
- }
-
- list = list->next;
- }
-
- h->got.glist = NULL;
- }
+ /* This function traverses list of GOT entries and
+ 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,
+ output_bfd,
+ info,
+ h);
if (h->needs_copy)
{
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
- asection *srelbss =
- bfd_get_section_by_name (h->root.u.def.section->owner,
+ asection *srelbss
+ = bfd_get_section_by_name (h->root.u.def.section->owner,
".rela.bss");
bfd_byte * loc = srelbss->contents
Elf32_External_Dyn *dyncon, *dynconend;
dyncon = (Elf32_External_Dyn *) ds.sdyn->contents;
- dynconend =
- (Elf32_External_Dyn *) (ds.sdyn->contents + ds.sdyn->size);
+ dynconend
+ = (Elf32_External_Dyn *) (ds.sdyn->contents + ds.sdyn->size);
for (; dyncon < dynconend; dyncon++)
{
Elf_Internal_Dyn internal_dyn;
if (asec_ptr->output_section != NULL)
{
internal_dyn.d_un.d_val +=
- (asec_ptr->output_section->vma +
- asec_ptr->output_offset);
+ (asec_ptr->output_section->vma
+ + asec_ptr->output_offset);
}
else
{
#define elf_backend_finish_dynamic_sections elf_arc_finish_dynamic_sections
#define elf_backend_size_dynamic_sections elf_arc_size_dynamic_sections
-#define elf_backend_add_symbol_hook elf_arc_add_symbol_hook
+#define elf_backend_add_symbol_hook elf_arc_add_symbol_hook
#define elf_backend_can_gc_sections 1
#define elf_backend_want_got_plt 1