OpenRISC BFD fixups for Glibc:

or1k: Fix static linking when with .rela.got relocations
  or1k: Fix dynamic TLS symbol flag
  or1k: Add TLS mask to handle multiple model access
  or1k: Fix issue with multiple PCREL relocations
  or1k: TLS offset to use tcb size and section alignment
  or1k: refactor: Rename p to sec_relocs
  or1k: refactor: Rename s to sgot and splt
  or1k: Add dynamic flag to tpoff

bfd	* elf32-or1k.c (or1k_elf_finish_dynamic_symbol): Rename srela
	to relgot.
	(or1k_elf_relocate_section): Access srelgot via
	htab->root.srelgot.  Add assertions for srelgot->contents.
	Introduce local variable for srelgot to not reuse global
	sreloc.
	(or1k_elf_relocate_section): Fixup dynamic symbol detection.
	(or1k_set_got_and_rela_sizes): New function.
	(or1k_initial_exec_offset): New function.
	(TLS_GD, TLS_IE, TLS_LD, TLS_LE): Redefine macros as masks.
	(or1k_elf_relocate_section): Allow for TLS to handle multiple
	model access.
	(or1k_elf_check_relocs): Use OR to set TLS access.
	(allocate_dynrelocs): Use or1k_set_got_and_rela_sizes to set
	sizes.
	(or1k_elf_size_dynamic_sections): Use
	or1k_set_got_and_rela_sizes to set sizes.
	(or1k_elf_relocate_section): Fixup PCREL relocation calculation.
	(TCB_SIZE): New macro.
	(tpoff): Use TCB_SIZE and alignment to calculate offset.
	(allocate_dynrelocs, readonly_dynrelocs, or1k_elf_check_relocs)
	(or1k_elf_size_dynamic_sections): Rename p to sec_relocs.
	(allocate_dynrelocs): Rename s to splt or sgot based on usage.
	(tpoff): Add dynamic boolean argument.
	(or1k_elf_relocate_section): Pass dynamic flag to tpoff.
This commit is contained in:
Stafford Horne
2020-05-19 14:26:33 +01:00
committed by Nick Clifton
parent 164446e04c
commit 7e94cf6cb0
2 changed files with 264 additions and 132 deletions

View File

@ -1,3 +1,31 @@
2020-05-19 Stafford Horne <shorne@gmail.com>
* elf32-or1k.c (or1k_elf_finish_dynamic_symbol): Rename srela
to relgot.
(or1k_elf_relocate_section): Access srelgot via
htab->root.srelgot. Add assertions for srelgot->contents.
Introduce local variable for srelgot to not reuse global
sreloc.
(or1k_elf_relocate_section): Fixup dynamic symbol detection.
(or1k_set_got_and_rela_sizes): New function.
(or1k_initial_exec_offset): New function.
(TLS_GD, TLS_IE, TLS_LD, TLS_LE): Redefine macros as masks.
(or1k_elf_relocate_section): Allow for TLS to handle multiple
model access.
(or1k_elf_check_relocs): Use OR to set TLS access.
(allocate_dynrelocs): Use or1k_set_got_and_rela_sizes to set
sizes.
(or1k_elf_size_dynamic_sections): Use
or1k_set_got_and_rela_sizes to set sizes.
(or1k_elf_relocate_section): Fixup PCREL relocation calculation.
(TCB_SIZE): New macro.
(tpoff): Use TCB_SIZE and alignment to calculate offset.
(allocate_dynrelocs, readonly_dynrelocs, or1k_elf_check_relocs)
(or1k_elf_size_dynamic_sections): Rename p to sec_relocs.
(allocate_dynrelocs): Rename s to splt or sgot based on usage.
(tpoff): Add dynamic boolean argument.
(or1k_elf_relocate_section): Pass dynamic flag to tpoff.
2020-05-19 Siddhesh Poyarekar <siddesh.poyarekar@arm.com> 2020-05-19 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* elfnn-aarch64.c (elfNN_aarch64_final_link_relocate): Club * elfnn-aarch64.c (elfNN_aarch64_final_link_relocate): Club

View File

@ -873,12 +873,19 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
{ BFD_RELOC_OR1K_PLTA26, R_OR1K_PLTA26 }, { BFD_RELOC_OR1K_PLTA26, R_OR1K_PLTA26 },
}; };
/* tls_type is a mask used to track how each symbol is accessed,
it may be accessed via multiple types of TLS access methods.
We track this for sizing (allocating got + relocation section space) and
for how to process relocations. */
#define TLS_UNKNOWN 0 #define TLS_UNKNOWN 0
#define TLS_NONE 1 #define TLS_NONE 1
#define TLS_GD 2 #define TLS_GD 2
#define TLS_LD 3 #define TLS_LD 4
#define TLS_IE 4 #define TLS_IE 8
#define TLS_LE 5 #define TLS_LE 16
/* The size of the TLS thread control block, used to offset LE access. */
#define TCB_SIZE 16
/* ELF linker hash entry. */ /* ELF linker hash entry. */
struct elf_or1k_link_hash_entry struct elf_or1k_link_hash_entry
@ -1043,19 +1050,49 @@ or1k_info_to_howto_rela (bfd * abfd,
return TRUE; return TRUE;
} }
/* Return the relocation value for @tpoff relocations.. */ /* Return the relocation value for @tpoff relocations.. */
static bfd_vma static bfd_vma
tpoff (struct bfd_link_info *info, bfd_vma address) tpoff (struct bfd_link_info *info, bfd_vma address, bfd_boolean dynamic)
{ {
struct elf_link_hash_table *htab = elf_hash_table (info);
bfd_vma base;
/* If tls_sec is NULL, we should have signalled an error already. */ /* If tls_sec is NULL, we should have signalled an error already. */
if (elf_hash_table (info)->tls_sec == NULL) if (htab->tls_sec == NULL)
return 0; return 0;
if (dynamic)
return address - htab->tls_sec->vma;
else
{
/* On or1k, the tp points to just after the tcb, if we have an alignment
greater than the tcb size we need to offset by the alignment difference. */
base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power)
- TCB_SIZE;
/* The thread pointer on or1k stores the address after the TCB where /* The thread pointer on or1k stores the address after the TCB where
the data is, just compute the difference. No need to compensate the data is, just compute the difference. No need to compensate
for the size of TCB. */ for the size of TCB. */
return (address - elf_hash_table (info)->tls_sec->vma); return address - htab->tls_sec->vma + base;
}
}
/* If we have both IE and GD accesses to a symbol the IE relocations should be
offset by 8 bytes because the got contains both GD and IE entries. */
static bfd_vma
or1k_initial_exec_offset (reloc_howto_type *howto, unsigned char tls_type_mask)
{
switch (howto->type)
{
case R_OR1K_TLS_IE_HI16:
case R_OR1K_TLS_IE_LO16:
case R_OR1K_TLS_IE_PG21:
case R_OR1K_TLS_IE_LO13:
case R_OR1K_TLS_IE_AHI16:
return (tls_type_mask & TLS_GD) != 0 ? 8 : 0;
default:
return 0;
}
} }
/* Like _bfd_final_link_relocate, but handles non-contiguous fields. */ /* Like _bfd_final_link_relocate, but handles non-contiguous fields. */
@ -1226,7 +1263,6 @@ or1k_elf_relocate_section (bfd *output_bfd,
Elf_Internal_Rela *rel; Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend; Elf_Internal_Rela *relend;
struct elf_or1k_link_hash_table *htab = or1k_elf_hash_table (info); struct elf_or1k_link_hash_table *htab = or1k_elf_hash_table (info);
bfd *dynobj;
asection *sreloc; asection *sreloc;
bfd_vma *local_got_offsets; bfd_vma *local_got_offsets;
asection *sgot, *splt; asection *sgot, *splt;
@ -1236,7 +1272,6 @@ or1k_elf_relocate_section (bfd *output_bfd,
if (htab == NULL) if (htab == NULL)
return FALSE; return FALSE;
dynobj = htab->root.dynobj;
local_got_offsets = elf_local_got_offsets (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd);
sreloc = elf_section_data (input_section)->sreloc; sreloc = elf_section_data (input_section)->sreloc;
@ -1416,7 +1451,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
/* We need to generate a R_OR1K_RELATIVE reloc /* We need to generate a R_OR1K_RELATIVE reloc
for the dynamic linker. */ for the dynamic linker. */
srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); srelgot = htab->root.srelgot;
BFD_ASSERT (srelgot != NULL); BFD_ASSERT (srelgot != NULL);
outrel.r_offset = got_base + off; outrel.r_offset = got_base + off;
@ -1591,54 +1626,80 @@ or1k_elf_relocate_section (bfd *output_bfd,
{ {
bfd_vma gotoff; bfd_vma gotoff;
Elf_Internal_Rela rela; Elf_Internal_Rela rela;
asection *srelgot;
bfd_byte *loc; bfd_byte *loc;
int dynamic; bfd_boolean dynamic;
int indx = 0;
unsigned char tls_type;
sreloc = bfd_get_section_by_name (dynobj, ".rela.got"); srelgot = htab->root.srelgot;
/* Mark as TLS related GOT entry by setting /* Mark as TLS related GOT entry by setting
bit 2 as well as bit 1. */ bit 2 to indcate TLS and bit 1 to indicate GOT. */
if (h != NULL) if (h != NULL)
{ {
gotoff = h->got.offset; gotoff = h->got.offset;
tls_type = ((struct elf_or1k_link_hash_entry *) h)->tls_type;
h->got.offset |= 3; h->got.offset |= 3;
} }
else else
{ {
unsigned char *local_tls_type;
gotoff = local_got_offsets[r_symndx]; gotoff = local_got_offsets[r_symndx];
local_tls_type = (unsigned char *) elf_or1k_local_tls_type (input_bfd);
tls_type = local_tls_type == NULL ? TLS_NONE
: local_tls_type[r_symndx];
local_got_offsets[r_symndx] |= 3; local_got_offsets[r_symndx] |= 3;
} }
/* Only process the relocation once. */ /* Only process the relocation once. */
if (gotoff & 1) if ((gotoff & 1) != 0)
{ {
relocation = sgot->output_offset + (gotoff & ~3); gotoff += or1k_initial_exec_offset (howto, tls_type);
/* The PG21 and LO13 relocs are pc-relative, while the
rest are GOT relative. */
relocation = got_base + (gotoff & ~3);
if (!(r_type == R_OR1K_TLS_GD_PG21
|| r_type == R_OR1K_TLS_GD_LO13
|| r_type == R_OR1K_TLS_IE_PG21
|| r_type == R_OR1K_TLS_IE_LO13))
relocation -= got_sym_value;
break; break;
} }
BFD_ASSERT (elf_hash_table (info)->hgot == NULL BFD_ASSERT (elf_hash_table (info)->hgot == NULL
|| elf_hash_table (info)->hgot->root.u.def.value == 0); || elf_hash_table (info)->hgot->root.u.def.value == 0);
/* Dynamic entries will require relocations. if we do not need if (h != NULL)
{
bfd_boolean dyn = htab->root.dynamic_sections_created;
bfd_boolean pic = bfd_link_pic (info);
if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, pic, h)
&& (!pic || !SYMBOL_REFERENCES_LOCAL (info, h)))
indx = h->dynindx;
}
/* Dynamic entries will require relocations. If we do not need
them we will just use the default R_OR1K_NONE and them we will just use the default R_OR1K_NONE and
not set anything. */ not set anything. */
dynamic = bfd_link_pic (info) dynamic = (bfd_link_pic (info) || indx != 0)
|| (sec && (sec->flags & SEC_ALLOC) != 0 && (h == NULL
&& h != NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& (h->root.type == bfd_link_hash_defweak || !h->def_regular)); || h->root.type != bfd_link_hash_undefweak);
/* Shared GD. */ /* Shared GD. */
if (dynamic if (dynamic && ((tls_type & TLS_GD) != 0))
&& (howto->type == R_OR1K_TLS_GD_HI16
|| howto->type == R_OR1K_TLS_GD_LO16
|| howto->type == R_OR1K_TLS_GD_PG21
|| howto->type == R_OR1K_TLS_GD_LO13))
{ {
int i; int i;
/* Add DTPMOD and DTPOFF GOT and rela entries. */ /* Add DTPMOD and DTPOFF GOT and rela entries. */
for (i = 0; i < 2; ++i) for (i = 0; i < 2; ++i)
{ {
BFD_ASSERT (srelgot->contents != NULL);
rela.r_offset = got_base + gotoff + i*4; rela.r_offset = got_base + gotoff + i*4;
if (h != NULL && h->dynindx != -1) if (h != NULL && h->dynindx != -1)
{ {
@ -1650,30 +1711,33 @@ or1k_elf_relocate_section (bfd *output_bfd,
{ {
rela.r_info = ELF32_R_INFO (0, rela.r_info = ELF32_R_INFO (0,
(i == 0 ? R_OR1K_TLS_DTPMOD : R_OR1K_TLS_DTPOFF)); (i == 0 ? R_OR1K_TLS_DTPMOD : R_OR1K_TLS_DTPOFF));
rela.r_addend = tpoff (info, relocation); rela.r_addend =
(i == 0 ? 0 : tpoff (info, relocation, dynamic));
} }
loc = sreloc->contents; loc = srelgot->contents;
loc += sreloc->reloc_count++ * loc += (srelgot->reloc_count++
sizeof (Elf32_External_Rela); * sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
bfd_put_32 (output_bfd, 0, sgot->contents + gotoff + i*4); bfd_put_32 (output_bfd, 0, sgot->contents + gotoff + i*4);
} }
} }
/* Static GD. */ /* Static GD. */
else if (howto->type == R_OR1K_TLS_GD_HI16 else if ((tls_type & TLS_GD) != 0)
|| howto->type == R_OR1K_TLS_GD_LO16
|| howto->type == R_OR1K_TLS_GD_PG21
|| howto->type == R_OR1K_TLS_GD_LO13)
{ {
bfd_put_32 (output_bfd, 1, sgot->contents + gotoff); bfd_put_32 (output_bfd, 1, sgot->contents + gotoff);
bfd_put_32 (output_bfd, tpoff (info, relocation), bfd_put_32 (output_bfd, tpoff (info, relocation, dynamic),
sgot->contents + gotoff + 4); sgot->contents + gotoff + 4);
} }
gotoff += or1k_initial_exec_offset (howto, tls_type);
/* Shared IE. */ /* Shared IE. */
else if (dynamic) if (dynamic && ((tls_type & TLS_IE) != 0))
{ {
BFD_ASSERT (srelgot->contents != NULL);
/* Add TPOFF GOT and rela entries. */ /* Add TPOFF GOT and rela entries. */
rela.r_offset = got_base + gotoff; rela.r_offset = got_base + gotoff;
if (h != NULL && h->dynindx != -1) if (h != NULL && h->dynindx != -1)
@ -1684,21 +1748,19 @@ or1k_elf_relocate_section (bfd *output_bfd,
else else
{ {
rela.r_info = ELF32_R_INFO (0, R_OR1K_TLS_TPOFF); rela.r_info = ELF32_R_INFO (0, R_OR1K_TLS_TPOFF);
rela.r_addend = tpoff (info, relocation); rela.r_addend = tpoff (info, relocation, dynamic);
} }
loc = sreloc->contents; loc = srelgot->contents;
loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
bfd_put_32 (output_bfd, 0, sgot->contents + gotoff); bfd_put_32 (output_bfd, 0, sgot->contents + gotoff);
} }
/* Static IE. */ /* Static IE. */
else else if ((tls_type & TLS_IE) != 0)
{ bfd_put_32 (output_bfd, tpoff (info, relocation, dynamic),
bfd_put_32 (output_bfd, tpoff (info, relocation),
sgot->contents + gotoff); sgot->contents + gotoff);
}
/* The PG21 and LO13 relocs are pc-relative, while the /* The PG21 and LO13 relocs are pc-relative, while the
rest are GOT relative. */ rest are GOT relative. */
@ -1716,7 +1778,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
case R_OR1K_TLS_LE_AHI16: case R_OR1K_TLS_LE_AHI16:
case R_OR1K_TLS_LE_SLO16: case R_OR1K_TLS_LE_SLO16:
/* Relocation is offset from TP. */ /* Relocation is offset from TP. */
relocation = tpoff (info, relocation); relocation = tpoff (info, relocation, 0);
break; break;
case R_OR1K_TLS_DTPMOD: case R_OR1K_TLS_DTPMOD:
@ -1895,7 +1957,7 @@ or1k_elf_check_relocs (bfd *abfd,
/* Record TLS type. */ /* Record TLS type. */
if (h != NULL) if (h != NULL)
((struct elf_or1k_link_hash_entry *) h)->tls_type = tls_type; ((struct elf_or1k_link_hash_entry *) h)->tls_type |= tls_type;
else else
{ {
unsigned char *local_tls_type; unsigned char *local_tls_type;
@ -1912,7 +1974,7 @@ or1k_elf_check_relocs (bfd *abfd,
return FALSE; return FALSE;
elf_or1k_local_tls_type (abfd) = local_tls_type; elf_or1k_local_tls_type (abfd) = local_tls_type;
} }
local_tls_type[r_symndx] = tls_type; local_tls_type[r_symndx] |= tls_type;
} }
switch (r_type) switch (r_type)
@ -2047,7 +2109,7 @@ or1k_elf_check_relocs (bfd *abfd,
&& (h->root.type == bfd_link_hash_defweak && (h->root.type == bfd_link_hash_defweak
|| !h->def_regular))) || !h->def_regular)))
{ {
struct elf_dyn_relocs *p; struct elf_dyn_relocs *sec_relocs;
struct elf_dyn_relocs **head; struct elf_dyn_relocs **head;
/* When creating a shared object, we must copy these /* When creating a shared object, we must copy these
@ -2115,24 +2177,26 @@ or1k_elf_check_relocs (bfd *abfd,
head = (struct elf_dyn_relocs **) vpp; head = (struct elf_dyn_relocs **) vpp;
} }
p = *head; sec_relocs = *head;
if (p == NULL || p->sec != sec) /* Allocate this sections dynamic reolcations structure if this
is a new section. */
if (sec_relocs == NULL || sec_relocs->sec != sec)
{ {
size_t amt = sizeof *p; size_t amt = sizeof *sec_relocs;
p = ((struct elf_dyn_relocs *) sec_relocs = ((struct elf_dyn_relocs *)
bfd_alloc (htab->root.dynobj, amt)); bfd_alloc (htab->root.dynobj, amt));
if (p == NULL) if (sec_relocs == NULL)
return FALSE; return FALSE;
p->next = *head; sec_relocs->next = *head;
*head = p; *head = sec_relocs;
p->sec = sec; sec_relocs->sec = sec;
p->count = 0; sec_relocs->count = 0;
p->pc_count = 0; sec_relocs->pc_count = 0;
} }
p->count += 1; sec_relocs->count += 1;
if (r_type == R_OR1K_INSN_REL_26) if (r_type == R_OR1K_INSN_REL_26)
p->pc_count += 1; sec_relocs->pc_count += 1;
} }
} }
break; break;
@ -2402,14 +2466,14 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
&& (h->got.offset & 2) == 0) /* Homemade TLS check. */ && (h->got.offset & 2) == 0) /* Homemade TLS check. */
{ {
asection *sgot; asection *sgot;
asection *srela; asection *srelgot;
Elf_Internal_Rela rela; Elf_Internal_Rela rela;
/* This symbol has an entry in the global offset table. Set it /* This symbol has an entry in the global offset table. Set it
up. */ up. */
sgot = htab->root.sgot; sgot = htab->root.sgot;
srela = htab->root.srelgot; srelgot = htab->root.srelgot;
BFD_ASSERT (sgot != NULL && srela != NULL); BFD_ASSERT (sgot != NULL && srelgot != NULL);
rela.r_offset = (sgot->output_section->vma rela.r_offset = (sgot->output_section->vma
+ sgot->output_offset + sgot->output_offset
@ -2435,10 +2499,10 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
rela.r_addend = 0; rela.r_addend = 0;
} }
loc = srela->contents; loc = srelgot->contents;
loc += srela->reloc_count * sizeof (Elf32_External_Rela); loc += srelgot->reloc_count * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
++srela->reloc_count; ++srelgot->reloc_count;
} }
if (h->needs_copy) if (h->needs_copy)
@ -2492,15 +2556,17 @@ or1k_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
static asection * static asection *
readonly_dynrelocs (struct elf_link_hash_entry *h) readonly_dynrelocs (struct elf_link_hash_entry *h)
{ {
struct elf_dyn_relocs *p; struct elf_dyn_relocs *sec_relocs;
struct elf_or1k_link_hash_entry *eh = (struct elf_or1k_link_hash_entry *) h; struct elf_or1k_link_hash_entry *eh = (struct elf_or1k_link_hash_entry *) h;
for (p = eh->dyn_relocs; p != NULL; p = p->next) for (sec_relocs = eh->dyn_relocs;
sec_relocs != NULL;
sec_relocs = sec_relocs->next)
{ {
asection *s = p->sec->output_section; asection *s = sec_relocs->sec->output_section;
if (s != NULL && (s->flags & SEC_READONLY) != 0) if (s != NULL && (s->flags & SEC_READONLY) != 0)
return p->sec; return sec_relocs->sec;
} }
return NULL; return NULL;
} }
@ -2634,6 +2700,56 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
return _bfd_elf_adjust_dynamic_copy (info, h, s); return _bfd_elf_adjust_dynamic_copy (info, h, s);
} }
/* Caclulate an update the sizes required for a symbol in the GOT and
RELA relocation section based on the TLS_TYPE and whether or not the symbol
is DYNAMIC.
Symbols with TLS_GD access require 8 bytes in the GOT and, if dynamic,
require two relocation entries. Symbols with TLS_IE access require 4 bytes
in the GOT and, if dynamic, require one relocation entry. Symbols may have
both TLS_GD and TLS_IE access to be accounted for.
Other symbols require 4 bytes in the GOT table and, if dynamic, require one
relocation entry. */
static void
or1k_set_got_and_rela_sizes (const unsigned char tls_type,
const bfd_boolean dynamic,
bfd_vma *got_size,
bfd_vma *rela_size)
{
bfd_boolean is_tls_entry = FALSE;
/* TLS GD requires two GOT entries and two relocs. */
if ((tls_type & TLS_GD) != 0)
{
*got_size += 8;
is_tls_entry = TRUE;
}
if ((tls_type & TLS_IE) != 0)
{
*got_size += 4;
is_tls_entry = TRUE;
}
if (is_tls_entry == FALSE)
*got_size += 4;
if (dynamic)
{
if ((tls_type & TLS_GD) != 0)
*rela_size += 2 * sizeof (Elf32_External_Rela);
if ((tls_type & TLS_IE) != 0)
*rela_size += sizeof (Elf32_External_Rela);
if (is_tls_entry == FALSE)
*rela_size += sizeof (Elf32_External_Rela);
}
}
/* Allocate space in .plt, .got and associated reloc sections for /* Allocate space in .plt, .got and associated reloc sections for
dynamic relocs. */ dynamic relocs. */
@ -2643,7 +2759,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
struct bfd_link_info *info; struct bfd_link_info *info;
struct elf_or1k_link_hash_table *htab; struct elf_or1k_link_hash_table *htab;
struct elf_or1k_link_hash_entry *eh; struct elf_or1k_link_hash_entry *eh;
struct elf_dyn_relocs *p; struct elf_dyn_relocs *sec_relocs;
if (h->root.type == bfd_link_hash_indirect) if (h->root.type == bfd_link_hash_indirect)
return TRUE; return TRUE;
@ -2669,14 +2785,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
{ {
asection *s = htab->root.splt; asection *splt = htab->root.splt;
/* If this is the first .plt entry, make room for the special /* If this is the first .plt entry, make room for the special
first entry. */ first entry. */
if (s->size == 0) if (splt->size == 0)
s->size = PLT_ENTRY_SIZE; splt->size = PLT_ENTRY_SIZE;
h->plt.offset = s->size; h->plt.offset = splt->size;
/* If this symbol is not defined in a regular file, and we are /* If this symbol is not defined in a regular file, and we are
not generating a shared library, then set the symbol to this not generating a shared library, then set the symbol to this
@ -2686,12 +2802,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
if (! bfd_link_pic (info) if (! bfd_link_pic (info)
&& !h->def_regular) && !h->def_regular)
{ {
h->root.u.def.section = s; h->root.u.def.section = splt;
h->root.u.def.value = h->plt.offset; h->root.u.def.value = h->plt.offset;
} }
/* Make room for this entry. */ /* Make room for this entry. */
s->size += PLT_ENTRY_SIZE; splt->size += PLT_ENTRY_SIZE;
/* We also need to make an entry in the .got.plt section, which /* We also need to make an entry in the .got.plt section, which
will be placed in the .got section by the linker script. */ will be placed in the .got section by the linker script. */
@ -2714,7 +2830,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
if (h->got.refcount > 0) if (h->got.refcount > 0)
{ {
asection *s; asection *sgot;
bfd_boolean dyn; bfd_boolean dyn;
unsigned char tls_type; unsigned char tls_type;
@ -2727,25 +2843,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
return FALSE; return FALSE;
} }
s = htab->root.sgot; sgot = htab->root.sgot;
h->got.offset = s->size; h->got.offset = sgot->size;
tls_type = ((struct elf_or1k_link_hash_entry *) h)->tls_type; tls_type = ((struct elf_or1k_link_hash_entry *) h)->tls_type;
/* TLS GD requires two GOT and two relocs. */
if (tls_type == TLS_GD)
s->size += 8;
else
s->size += 4;
dyn = htab->root.dynamic_sections_created; dyn = htab->root.dynamic_sections_created;
if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)) dyn = WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h);
{ or1k_set_got_and_rela_sizes (tls_type, dyn,
if (tls_type == TLS_GD) &sgot->size, &htab->root.srelgot->size);
htab->root.srelgot->size += 2 * sizeof (Elf32_External_Rela);
else
htab->root.srelgot->size += sizeof (Elf32_External_Rela);
}
} }
else else
h->got.offset = (bfd_vma) -1; h->got.offset = (bfd_vma) -1;
@ -2765,14 +2872,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
{ {
struct elf_dyn_relocs **pp; struct elf_dyn_relocs **pp;
for (pp = &eh->dyn_relocs; (p = *pp) != NULL;) for (pp = &eh->dyn_relocs; (sec_relocs = *pp) != NULL;)
{ {
p->count -= p->pc_count; sec_relocs->count -= sec_relocs->pc_count;
p->pc_count = 0; sec_relocs->pc_count = 0;
if (p->count == 0) if (sec_relocs->count == 0)
*pp = p->next; *pp = sec_relocs->next;
else else
pp = &p->next; pp = &sec_relocs->next;
} }
} }
@ -2828,10 +2935,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
} }
/* Finally, allocate space. */ /* Finally, allocate space. */
for (p = eh->dyn_relocs; p != NULL; p = p->next) for (sec_relocs = eh->dyn_relocs;
sec_relocs != NULL;
sec_relocs = sec_relocs->next)
{ {
asection *sreloc = elf_section_data (p->sec)->sreloc; asection *sreloc = elf_section_data (sec_relocs->sec)->sreloc;
sreloc->size += p->count * sizeof (Elf32_External_Rela); sreloc->size += sec_relocs->count * sizeof (Elf32_External_Rela);
} }
return TRUE; return TRUE;
@ -2911,26 +3020,28 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
for (s = ibfd->sections; s != NULL; s = s->next) for (s = ibfd->sections; s != NULL; s = s->next)
{ {
struct elf_dyn_relocs *p; struct elf_dyn_relocs *sec_relocs;
for (p = ((struct elf_dyn_relocs *) for (sec_relocs = ((struct elf_dyn_relocs *)
elf_section_data (s)->local_dynrel); elf_section_data (s)->local_dynrel);
p != NULL; sec_relocs != NULL;
p = p->next) sec_relocs = sec_relocs->next)
{ {
if (! bfd_is_abs_section (p->sec) if (! bfd_is_abs_section (sec_relocs->sec)
&& bfd_is_abs_section (p->sec->output_section)) && bfd_is_abs_section (sec_relocs->sec->output_section))
{ {
/* Input section has been discarded, either because /* Input section has been discarded, either because
it is a copy of a linkonce section or due to it is a copy of a linkonce section or due to
linker script /DISCARD/, so we'll be discarding linker script /DISCARD/, so we'll be discarding
the relocs too. */ the relocs too. */
} }
else if (p->count != 0) else if (sec_relocs->count != 0)
{ {
srel = elf_section_data (p->sec)->sreloc; srel = elf_section_data (sec_relocs->sec)->sreloc;
srel->size += p->count * sizeof (Elf32_External_Rela); srel->size += sec_relocs->count
if ((p->sec->output_section->flags & SEC_READONLY) != 0) * sizeof (Elf32_External_Rela);
if ((sec_relocs->sec->output_section->flags & SEC_READONLY)
!= 0)
info->flags |= DF_TEXTREL; info->flags |= DF_TEXTREL;
} }
} }
@ -2950,20 +3061,13 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
{ {
if (*local_got > 0) if (*local_got > 0)
{ {
*local_got = s->size; unsigned char tls_type = (local_tls_type == NULL)
? TLS_UNKNOWN
: *local_tls_type;
/* TLS GD requires two GOT and two relocs. */ *local_got = s->size;
if (local_tls_type != NULL && *local_tls_type == TLS_GD) or1k_set_got_and_rela_sizes (tls_type, bfd_link_pic (info),
s->size += 8; &s->size, &srel->size);
else
s->size += 4;
if (bfd_link_pic (info))
{
if (local_tls_type != NULL && *local_tls_type == TLS_GD)
srel->size += 2 * sizeof (Elf32_External_Rela);
else
srel->size += sizeof (Elf32_External_Rela);
}
} }
else else