Fixes done to TLS.

TLS relocations did not support multiple TLS modes for the same
symbol in a single object file.
Refactored how GOT and TLS is implemented. Removed code duplications between
local and global symbols conditioning.

bfd/ChangeLog:

2016-06-14  Cupertino Miranda  <cmiranda@synopsys.com>
  * arc-got.h: Moved got related structures from elf32-arc.c to
    this file. More precisely, tls_type_e, tls_got_entries, got_entry.
  * (arc_get_local_got_ents,
     got_entry_for_type,
     new_got_entry_to_list,
     tls_type_for_reloc,
     symbol_has_entry_of_type,
     get_got_entry_list_for_symbol,
     arc_got_entry_type_for_reloc,
     ADD_SYMBOL_REF_SEC_AND_RELOC,
     arc_fill_got_info_for_reloc,
     relocate_fix_got_relocs_for_got_info,
     create_got_dynrelocs_for_single_entry,
     create_got_dynrelocs_for_got_info): Added to file.
  * elf32-arc.c: Removed GOT & TLS related structs and functions to
                     arc-got.h.

Signed-off-by: Claudiu Zissulescu <claziss@synopsys.com>
This commit is contained in:
Cupertino Miranda
2016-06-14 22:55:44 +02:00
committed by Claudiu Zissulescu
parent 36897971c8
commit 08759e0fc8
4 changed files with 658 additions and 530 deletions

View File

@ -1,3 +1,17 @@
2016-07-11 Cupertino Miranda <cmiranda@synopsys.com>
* arc-got.h: Moved got related structures from elf32-arc.c to
this file. More precisely, tls_type_e, tls_got_entries, got_entry.
* (arc_get_local_got_ents, got_entry_for_type, new_got_entry_to_list,
tls_type_for_reloc, symbol_has_entry_of_type,
get_got_entry_list_for_symbol, arc_got_entry_type_for_reloc,
ADD_SYMBOL_REF_SEC_AND_RELOC, rc_fill_got_info_for_reloc,
relocate_fix_got_relocs_for_got_info,
create_got_dynrelocs_for_single_entry,
create_got_dynrelocs_for_got_info): Added to file.
* elf32-arc.c: Removed GOT & TLS related structs and functions to
arc-got.h.
2016-07-08 James Bowman <james.bowman@ftdichip.com>
* elf32-ft32.c (ft32_reloc_map): Use R_FT32_32 for BFD_RELOC_32.

511
bfd/arc-got.h Normal file
View File

@ -0,0 +1,511 @@
/* 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 */

View File

@ -35,7 +35,7 @@
# define PR_DEBUG(fmt, args...)
#endif
/* #define ARC_ENABLE_DEBUG 1 */
/* #define ARC_ENABLE_DEBUG 1 */
#ifndef ARC_ENABLE_DEBUG
#define ARC_DEBUG(...)
#else
@ -58,6 +58,7 @@ name_for_global_symbol (struct elf_link_hash_entry *h)
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)); \
@ -103,75 +104,6 @@ const char * dyn_section_names[DYN_SECTION_TYPES_END] =
".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
@ -238,6 +170,32 @@ is_reloc_for_TLS (reloc_howto_type *howto)
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)
@ -345,7 +303,7 @@ arc_elf_howto (unsigned int r_type)
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) \
@ -626,8 +584,8 @@ arc_elf_object_p (bfd * abfd)
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;
}
}
@ -688,27 +646,6 @@ DO_NOTHING:
#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)
@ -752,9 +689,9 @@ 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
@ -768,9 +705,9 @@ middle_endian_convert (bfd_vma insn, bfd_boolean do_it)
{
if (do_it)
{
insn =
((insn & 0xffff0000) >> 16) |
((insn & 0xffff) << 16);
insn
= ((insn & 0xffff0000) >> 16)
| ((insn & 0xffff) << 16);
}
return insn;
}
@ -781,37 +718,37 @@ middle_endian_convert (bfd_vma insn, bfd_boolean do_it)
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:
@ -973,10 +910,10 @@ arc_do_relocation (bfd_byte * contents,
/* 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);
@ -989,11 +926,11 @@ arc_do_relocation (bfd_byte * contents,
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
@ -1040,28 +977,6 @@ arc_do_relocation (bfd_byte * contents,
#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
@ -1089,7 +1004,6 @@ elf_arc_relocate_section (bfd * output_bfd,
{
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;
@ -1178,8 +1092,8 @@ elf_arc_relocate_section (bfd * output_bfd,
/* 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;
}
@ -1249,11 +1163,6 @@ elf_arc_relocate_section (bfd * output_bfd,
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 =
@ -1277,88 +1186,6 @@ elf_arc_relocate_section (bfd * output_bfd,
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
@ -1459,118 +1286,44 @@ elf_arc_relocate_section (bfd * output_bfd,
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
@ -1666,7 +1419,7 @@ elf_arc_relocate_section (bfd * output_bfd,
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)
{
@ -1735,38 +1488,18 @@ arc_create_dynamic_sections (bfd * abfd, struct bfd_link_info *info)
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;
@ -1774,7 +1507,6 @@ elf_arc_check_relocs (bfd * abfd,
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++)
@ -1849,7 +1581,7 @@ elf_arc_check_relocs (bfd * abfd,
/* 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
@ -1880,75 +1612,15 @@ elf_arc_check_relocs (bfd * abfd,
h->needs_plt = 1;
}
if (is_reloc_for_GOT (howto) == TRUE)
/* Add info to the symbol got_entry_list. */
if (is_reloc_for_GOT (howto) == TRUE
|| is_reloc_for_TLS (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)
{
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);
}
}
@ -2026,9 +1698,9 @@ plt_do_relocs_for_symbol (bfd *abfd,
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;
@ -2048,9 +1720,9 @@ plt_do_relocs_for_symbol (bfd *abfd,
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)
@ -2193,7 +1865,7 @@ elf_arc_adjust_dynamic_symbol (struct bfd_link_info *info,
{
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;
@ -2302,84 +1974,15 @@ elf_arc_finish_dynamic_symbol (bfd * output_bfd,
}
}
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)
{
@ -2387,8 +1990,8 @@ GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
+ 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
@ -2444,8 +2047,8 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd,
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;
@ -2483,8 +2086,8 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd,
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
{
@ -2834,7 +2437,7 @@ elf_arc_add_symbol_hook (bfd * abfd,
#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

View File

@ -454,7 +454,7 @@ ARC_RELOC_HOWTO(ARC_TLS_DTPOFF, 67, \
32, \
replace_word32, \
dont, \
( ME ( ( S - TLS_REL ) ) ))
( ME ( S - SECTSTART ) + A ))
ARC_RELOC_HOWTO(ARC_TLS_DTPOFF_S9, 73, \
2, \