mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-25 21:41:47 +08:00
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:

committed by
Claudiu Zissulescu

parent
36897971c8
commit
08759e0fc8
@ -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
511
bfd/arc-got.h
Normal 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 */
|
661
bfd/elf32-arc.c
661
bfd/elf32-arc.c
@ -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
|
||||
|
@ -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, \
|
||||
|
Reference in New Issue
Block a user