mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-23 03:29:47 +08:00
LoongArch: Fix LD check fails.
Some test cases about ifunc. bfd/ * elfnn-loongarch.c * elfxx-loongarch.h === ld Summary === of expected passes 1430 of expected failures 11 of untested testcases 1 of unsupported tests 154
This commit is contained in:
@ -42,9 +42,6 @@ struct loongarch_elf_link_hash_entry
|
|||||||
{
|
{
|
||||||
struct elf_link_hash_entry elf;
|
struct elf_link_hash_entry elf;
|
||||||
|
|
||||||
/* Track dynamic relocs copied for this symbol. */
|
|
||||||
struct elf_dyn_relocs *dyn_relocs;
|
|
||||||
|
|
||||||
#define GOT_UNKNOWN 0
|
#define GOT_UNKNOWN 0
|
||||||
#define GOT_NORMAL 1
|
#define GOT_NORMAL 1
|
||||||
#define GOT_TLS_GD 2
|
#define GOT_TLS_GD 2
|
||||||
@ -238,7 +235,6 @@ link_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table,
|
|||||||
if (entry != NULL)
|
if (entry != NULL)
|
||||||
{
|
{
|
||||||
eh = (struct loongarch_elf_link_hash_entry *) entry;
|
eh = (struct loongarch_elf_link_hash_entry *) entry;
|
||||||
eh->dyn_relocs = NULL;
|
|
||||||
eh->tls_type = GOT_UNKNOWN;
|
eh->tls_type = GOT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,11 +628,21 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||||||
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* It is referenced by a non-shared object. */
|
||||||
|
if (h != NULL)
|
||||||
|
h->ref_regular = 1;
|
||||||
|
|
||||||
if (h && h->type == STT_GNU_IFUNC)
|
if (h && h->type == STT_GNU_IFUNC)
|
||||||
{
|
{
|
||||||
if (htab->elf.dynobj == NULL)
|
if (htab->elf.dynobj == NULL)
|
||||||
htab->elf.dynobj = abfd;
|
htab->elf.dynobj = abfd;
|
||||||
|
|
||||||
|
/* Create the ifunc sections, iplt and ipltgot, for static
|
||||||
|
executables. */
|
||||||
|
if ((r_type == R_LARCH_64 || r_type == R_LARCH_32)
|
||||||
|
&& !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!htab->elf.splt
|
if (!htab->elf.splt
|
||||||
&& !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
|
&& !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
|
||||||
/* If '.plt' not represent, create '.iplt' to deal with ifunc. */
|
/* If '.plt' not represent, create '.iplt' to deal with ifunc. */
|
||||||
@ -752,6 +758,24 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||||||
|
|
||||||
if (h != NULL)
|
if (h != NULL)
|
||||||
h->non_got_ref = 1;
|
h->non_got_ref = 1;
|
||||||
|
|
||||||
|
if (h != NULL
|
||||||
|
&& (!bfd_link_pic (info)
|
||||||
|
|| h->type == STT_GNU_IFUNC))
|
||||||
|
{
|
||||||
|
/* This reloc might not bind locally. */
|
||||||
|
h->non_got_ref = 1;
|
||||||
|
h->pointer_equality_needed = 1;
|
||||||
|
|
||||||
|
if (!h->def_regular
|
||||||
|
|| (sec->flags & (SEC_CODE | SEC_READONLY)) != 0)
|
||||||
|
{
|
||||||
|
/* We may need a .plt entry if the symbol is a function
|
||||||
|
defined in a shared lib or is a function referenced
|
||||||
|
from the code or read-only section. */
|
||||||
|
h->plt.refcount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_LARCH_GNU_VTINHERIT:
|
case R_LARCH_GNU_VTINHERIT:
|
||||||
@ -790,7 +814,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||||||
/* If this is a global symbol, we count the number of
|
/* If this is a global symbol, we count the number of
|
||||||
relocations we need for this symbol. */
|
relocations we need for this symbol. */
|
||||||
if (h != NULL)
|
if (h != NULL)
|
||||||
head = &((struct loongarch_elf_link_hash_entry *) h)->dyn_relocs;
|
head = &h->dyn_relocs;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Track dynamic relocs needed for local syms too.
|
/* Track dynamic relocs needed for local syms too.
|
||||||
@ -837,7 +861,7 @@ readonly_dynrelocs (struct elf_link_hash_entry *h)
|
|||||||
{
|
{
|
||||||
struct elf_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
for (p = loongarch_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next)
|
for (p = h->dyn_relocs; p != NULL; p = p->next)
|
||||||
{
|
{
|
||||||
asection *s = p->sec->output_section;
|
asection *s = p->sec->output_section;
|
||||||
|
|
||||||
@ -986,13 +1010,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
{
|
{
|
||||||
struct bfd_link_info *info;
|
struct bfd_link_info *info;
|
||||||
struct loongarch_elf_link_hash_table *htab;
|
struct loongarch_elf_link_hash_table *htab;
|
||||||
struct loongarch_elf_link_hash_entry *eh;
|
|
||||||
struct elf_dyn_relocs *p;
|
struct elf_dyn_relocs *p;
|
||||||
|
|
||||||
if (h->root.type == bfd_link_hash_indirect)
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
eh = (struct loongarch_elf_link_hash_entry *) h;
|
if (h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
return true;
|
||||||
|
|
||||||
info = (struct bfd_link_info *) inf;
|
info = (struct bfd_link_info *) inf;
|
||||||
htab = loongarch_elf_hash_table (info);
|
htab = loongarch_elf_hash_table (info);
|
||||||
BFD_ASSERT (htab != NULL);
|
BFD_ASSERT (htab != NULL);
|
||||||
@ -1041,6 +1067,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
gotplt->size += GOT_ENTRY_SIZE;
|
gotplt->size += GOT_ENTRY_SIZE;
|
||||||
relplt->size += sizeof (ElfNN_External_Rela);
|
relplt->size += sizeof (ElfNN_External_Rela);
|
||||||
|
|
||||||
|
/* If this symbol is not defined in a regular file, and we are
|
||||||
|
not generating a shared library, then set the symbol to this
|
||||||
|
location in the .plt. This is required to make function
|
||||||
|
pointers compare as equal between the normal executable and
|
||||||
|
the shared library. */
|
||||||
|
if (!bfd_link_pic(info)
|
||||||
|
&& !h->def_regular)
|
||||||
|
{
|
||||||
|
h->root.u.def.section = plt;
|
||||||
|
h->root.u.def.value = h->plt.offset;
|
||||||
|
}
|
||||||
|
|
||||||
h->needs_plt = 1;
|
h->needs_plt = 1;
|
||||||
}
|
}
|
||||||
while (0);
|
while (0);
|
||||||
@ -1056,9 +1094,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
|
|
||||||
/* Make sure this symbol is output as a dynamic symbol.
|
/* Make sure this symbol is output as a dynamic symbol.
|
||||||
Undefined weak syms won't yet be marked as dynamic. */
|
Undefined weak syms won't yet be marked as dynamic. */
|
||||||
if (h->dynindx == -1 && !h->forced_local
|
if (h->dynindx == -1 && !h->forced_local)
|
||||||
&& !bfd_elf_link_record_dynamic_symbol (info, h))
|
{
|
||||||
return false;
|
if (SYMBOL_REFERENCES_LOCAL (info, h)
|
||||||
|
&& (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
|
||||||
|
&& h->start_stop)
|
||||||
|
{
|
||||||
|
/* The pr21964-4. do nothing. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !bfd_elf_link_record_dynamic_symbol (info, h))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s = htab->elf.sgot;
|
s = htab->elf.sgot;
|
||||||
h->got.offset = s->size;
|
h->got.offset = s->size;
|
||||||
@ -1091,14 +1140,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
else
|
else
|
||||||
h->got.offset = MINUS_ONE;
|
h->got.offset = MINUS_ONE;
|
||||||
|
|
||||||
if (eh->dyn_relocs == NULL)
|
if (h->dyn_relocs == NULL)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (SYMBOL_REFERENCES_LOCAL (info, h))
|
if (SYMBOL_REFERENCES_LOCAL (info, h))
|
||||||
{
|
{
|
||||||
struct elf_dyn_relocs **pp;
|
struct elf_dyn_relocs **pp;
|
||||||
|
|
||||||
for (pp = &eh->dyn_relocs; (p = *pp) != NULL;)
|
for (pp = &h->dyn_relocs; (p = *pp) != NULL;)
|
||||||
{
|
{
|
||||||
p->count -= p->pc_count;
|
p->count -= p->pc_count;
|
||||||
p->pc_count = 0;
|
p->pc_count = 0;
|
||||||
@ -1112,7 +1161,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
if (h->root.type == bfd_link_hash_undefweak)
|
if (h->root.type == bfd_link_hash_undefweak)
|
||||||
{
|
{
|
||||||
if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
|
if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
|
||||||
eh->dyn_relocs = NULL;
|
h->dyn_relocs = NULL;
|
||||||
else if (h->dynindx == -1 && !h->forced_local
|
else if (h->dynindx == -1 && !h->forced_local
|
||||||
/* Make sure this symbol is output as a dynamic symbol.
|
/* Make sure this symbol is output as a dynamic symbol.
|
||||||
Undefined weak syms won't yet be marked as dynamic. */
|
Undefined weak syms won't yet be marked as dynamic. */
|
||||||
@ -1120,7 +1169,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p = eh->dyn_relocs; p != NULL; p = p->next)
|
for (p = h->dyn_relocs; p != NULL; p = p->next)
|
||||||
{
|
{
|
||||||
asection *sreloc = elf_section_data (p->sec)->sreloc;
|
asection *sreloc = elf_section_data (p->sec)->sreloc;
|
||||||
sreloc->size += p->count * sizeof (ElfNN_External_Rela);
|
sreloc->size += p->count * sizeof (ElfNN_External_Rela);
|
||||||
@ -1129,16 +1178,60 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate space in .plt, .got and associated reloc sections for
|
||||||
|
ifunc dynamic relocs. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
elfNN_loongarch_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
|
||||||
|
void *inf)
|
||||||
|
{
|
||||||
|
struct bfd_link_info *info;
|
||||||
|
/* An example of a bfd_link_hash_indirect symbol is versioned
|
||||||
|
symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect)
|
||||||
|
-> __gxx_personality_v0(bfd_link_hash_defined)
|
||||||
|
|
||||||
|
There is no need to process bfd_link_hash_indirect symbols here
|
||||||
|
because we will also be presented with the concrete instance of
|
||||||
|
the symbol and loongarch_elf_copy_indirect_symbol () will have been
|
||||||
|
called to copy all relevant data from the generic to the concrete
|
||||||
|
symbol instance. */
|
||||||
|
if (h->root.type == bfd_link_hash_indirect)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (h->root.type == bfd_link_hash_warning)
|
||||||
|
h = (struct elf_link_hash_entry *) h->root.u.i.link;
|
||||||
|
|
||||||
|
info = (struct bfd_link_info *) inf;
|
||||||
|
|
||||||
|
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
|
||||||
|
here if it is defined and referenced in a non-shared object. */
|
||||||
|
if (h->type == STT_GNU_IFUNC
|
||||||
|
&& h->def_regular)
|
||||||
|
return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
|
||||||
|
&h->dyn_relocs,
|
||||||
|
PLT_ENTRY_SIZE,
|
||||||
|
PLT_HEADER_SIZE,
|
||||||
|
GOT_ENTRY_SIZE,
|
||||||
|
false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate space in .plt, .got and associated reloc sections for
|
||||||
|
ifunc dynamic relocs. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
elfNN_loongarch_allocate_local_dynrelocs (void **slot, void *inf)
|
elfNN_loongarch_allocate_local_dynrelocs (void **slot, void *inf)
|
||||||
{
|
{
|
||||||
struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot;
|
struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot;
|
||||||
|
|
||||||
if (!h->def_regular || !h->ref_regular || !h->forced_local
|
if (h->type != STT_GNU_IFUNC
|
||||||
|
|| !h->def_regular
|
||||||
|
|| !h->ref_regular
|
||||||
|
|| !h->forced_local
|
||||||
|| h->root.type != bfd_link_hash_defined)
|
|| h->root.type != bfd_link_hash_defined)
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
return allocate_dynrelocs (h, inf);
|
return elfNN_loongarch_allocate_ifunc_dynrelocs (h, inf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set DF_TEXTREL if we find any dynamic relocs that apply to
|
/* Set DF_TEXTREL if we find any dynamic relocs that apply to
|
||||||
@ -1275,6 +1368,11 @@ loongarch_elf_size_dynamic_sections (bfd *output_bfd,
|
|||||||
/* Allocate global sym .plt and .got entries, and space for global
|
/* Allocate global sym .plt and .got entries, and space for global
|
||||||
sym dynamic relocs. */
|
sym dynamic relocs. */
|
||||||
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
|
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
|
||||||
|
|
||||||
|
/* Allocate global ifunc sym .plt and .got entries, and space for global
|
||||||
|
ifunc sym dynamic relocs. */
|
||||||
|
elf_link_hash_traverse (&htab->elf, elfNN_loongarch_allocate_ifunc_dynrelocs, info);
|
||||||
|
|
||||||
/* Allocate .plt and .got entries, and space for local ifunc symbols. */
|
/* Allocate .plt and .got entries, and space for local ifunc symbols. */
|
||||||
htab_traverse (htab->loc_hash_table,
|
htab_traverse (htab->loc_hash_table,
|
||||||
(void *) elfNN_loongarch_allocate_local_dynrelocs, info);
|
(void *) elfNN_loongarch_allocate_local_dynrelocs, info);
|
||||||
@ -1976,14 +2074,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
resolved_to_const = true;
|
resolved_to_const = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h && h->type == STT_GNU_IFUNC)
|
/* The ifunc without reference does not generate plt. */
|
||||||
|
if (h && h->type == STT_GNU_IFUNC && h->plt.offset != MINUS_ONE)
|
||||||
{
|
{
|
||||||
if (h->plt.offset == MINUS_ONE)
|
|
||||||
info->callbacks->info ("%X%pB(%pA+0x%v): error: %s against `%s':\n"
|
|
||||||
"STT_GNU_IFUNC must have PLT stub"
|
|
||||||
"\n",
|
|
||||||
input_bfd, input_section,
|
|
||||||
(bfd_vma) rel->r_offset, howto->name, name);
|
|
||||||
defined_local = true;
|
defined_local = true;
|
||||||
resolved_local = true;
|
resolved_local = true;
|
||||||
resolved_dynly = false;
|
resolved_dynly = false;
|
||||||
@ -1995,7 +2088,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
|
|
||||||
BFD_ASSERT (resolved_local + resolved_dynly + resolved_to_const == 1);
|
BFD_ASSERT (resolved_local + resolved_dynly + resolved_to_const == 1);
|
||||||
|
|
||||||
BFD_ASSERT (!resolved_dynly || (h && h->dynindx != -1));
|
/* BFD_ASSERT (!resolved_dynly || (h && h->dynindx != -1));. */
|
||||||
|
|
||||||
BFD_ASSERT (!resolved_local || defined_local);
|
BFD_ASSERT (!resolved_local || defined_local);
|
||||||
|
|
||||||
@ -2026,7 +2119,31 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
&& (input_section->flags & SEC_ALLOC));
|
&& (input_section->flags & SEC_ALLOC));
|
||||||
|
|
||||||
outrel.r_offset += sec_addr (input_section);
|
outrel.r_offset += sec_addr (input_section);
|
||||||
if (resolved_dynly)
|
|
||||||
|
/* A pointer point to a local ifunc symbol. */
|
||||||
|
if(h
|
||||||
|
&& h->type == STT_GNU_IFUNC
|
||||||
|
&& (h->dynindx == -1
|
||||||
|
|| h->forced_local
|
||||||
|
|| bfd_link_executable(info)))
|
||||||
|
{
|
||||||
|
outrel.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
|
||||||
|
outrel.r_addend = (h->root.u.def.value
|
||||||
|
+ h->root.u.def.section->output_section->vma
|
||||||
|
+ h->root.u.def.section->output_offset);
|
||||||
|
|
||||||
|
/* Dynamic relocations are stored in
|
||||||
|
1. .rela.ifunc section in PIC object.
|
||||||
|
2. .rela.got section in dynamic executable.
|
||||||
|
3. .rela.iplt section in static executable. */
|
||||||
|
if (bfd_link_pic (info))
|
||||||
|
sreloc = htab->elf.irelifunc;
|
||||||
|
else if (htab->elf.splt != NULL)
|
||||||
|
sreloc = htab->elf.srelgot;
|
||||||
|
else
|
||||||
|
sreloc = htab->elf.irelplt;
|
||||||
|
}
|
||||||
|
else if (resolved_dynly)
|
||||||
{
|
{
|
||||||
outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
|
outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
|
||||||
outrel.r_addend = rel->r_addend;
|
outrel.r_addend = rel->r_addend;
|
||||||
@ -2093,6 +2210,25 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
bfd_reloc_notsupported,
|
bfd_reloc_notsupported,
|
||||||
is_undefweak, name,
|
is_undefweak, name,
|
||||||
"Internal:");
|
"Internal:");
|
||||||
|
if (resolved_local)
|
||||||
|
{
|
||||||
|
if (!elf_hash_table (info)->tls_sec)
|
||||||
|
{
|
||||||
|
fatal = loongarch_reloc_is_fatal (info, input_bfd,
|
||||||
|
input_section, rel, howto, bfd_reloc_notsupported,
|
||||||
|
is_undefweak, name, "TLS section not be created");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
relocation -= elf_hash_table (info)->tls_sec->vma;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fatal = loongarch_reloc_is_fatal (info, input_bfd,
|
||||||
|
input_section, rel, howto, bfd_reloc_undefined,
|
||||||
|
is_undefweak, name,
|
||||||
|
"TLS LE just can be resolved local only.");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case R_LARCH_SOP_PUSH_TLS_TPREL:
|
case R_LARCH_SOP_PUSH_TLS_TPREL:
|
||||||
@ -2275,7 +2411,8 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
{
|
{
|
||||||
off = h->got.offset;
|
off = h->got.offset;
|
||||||
|
|
||||||
if (off == MINUS_ONE)
|
if (off == MINUS_ONE
|
||||||
|
&& h->type != STT_GNU_IFUNC)
|
||||||
{
|
{
|
||||||
fatal = (loongarch_reloc_is_fatal
|
fatal = (loongarch_reloc_is_fatal
|
||||||
(info, input_bfd, input_section, rel, howto,
|
(info, input_bfd, input_section, rel, howto,
|
||||||
@ -2284,6 +2421,33 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hidden symbol not has .got entry, only .got.plt entry
|
||||||
|
so gprel is (plt - got). */
|
||||||
|
if (off == MINUS_ONE
|
||||||
|
&& h->type == STT_GNU_IFUNC)
|
||||||
|
{
|
||||||
|
if (h->plt.offset == (bfd_vma) -1)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE;
|
||||||
|
off = plt_index * GOT_ENTRY_SIZE;
|
||||||
|
|
||||||
|
if (htab->elf.splt != NULL)
|
||||||
|
{
|
||||||
|
/* Section .plt header is 2 times of plt entry. */
|
||||||
|
off = sec_addr(htab->elf.sgotplt) + off
|
||||||
|
- sec_addr(htab->elf.sgot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Section iplt not has plt header. */
|
||||||
|
off = sec_addr(htab->elf.igotplt) + off
|
||||||
|
- sec_addr(htab->elf.sgot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn, is_pic, h)
|
if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn, is_pic, h)
|
||||||
|| (is_pic && SYMBOL_REFERENCES_LOCAL (info, h)))
|
|| (is_pic && SYMBOL_REFERENCES_LOCAL (info, h)))
|
||||||
{
|
{
|
||||||
@ -2321,6 +2485,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
off &= ~1;
|
off &= ~1;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* The pr21964-4. Create relocate entry. */
|
||||||
|
if (is_pic && h->start_stop)
|
||||||
|
{
|
||||||
|
asection *s;
|
||||||
|
Elf_Internal_Rela outrel;
|
||||||
|
/* We need to generate a R_LARCH_RELATIVE reloc
|
||||||
|
for the dynamic linker. */
|
||||||
|
s = htab->elf.srelgot;
|
||||||
|
if (!s)
|
||||||
|
{
|
||||||
|
fatal = loongarch_reloc_is_fatal (info, input_bfd,
|
||||||
|
input_section, rel, howto,
|
||||||
|
bfd_reloc_notsupported, is_undefweak, name,
|
||||||
|
"Internal: '.rel.got' not represent");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outrel.r_offset = sec_addr (got) + off;
|
||||||
|
outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
|
||||||
|
outrel.r_addend = relocation; /* Link-time addr. */
|
||||||
|
loongarch_elf_append_rela (output_bfd, s, &outrel);
|
||||||
|
}
|
||||||
bfd_put_NN (output_bfd, relocation, got->contents + off);
|
bfd_put_NN (output_bfd, relocation, got->contents + off);
|
||||||
h->got.offset |= 1;
|
h->got.offset |= 1;
|
||||||
}
|
}
|
||||||
@ -2516,9 +2702,19 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||||||
}
|
}
|
||||||
else /* if (resolved_dynly) */
|
else /* if (resolved_dynly) */
|
||||||
{
|
{
|
||||||
outrel.r_info =
|
/* Static linking has no .dynsym table. */
|
||||||
ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_TPRELNN);
|
if (!htab->elf.dynamic_sections_created)
|
||||||
outrel.r_addend = 0;
|
{
|
||||||
|
outrel.r_info =
|
||||||
|
ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN);
|
||||||
|
outrel.r_addend = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outrel.r_info =
|
||||||
|
ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_TPRELNN);
|
||||||
|
outrel.r_addend = 0;
|
||||||
|
}
|
||||||
loongarch_elf_append_rela (output_bfd, htab->elf.srelgot,
|
loongarch_elf_append_rela (output_bfd, htab->elf.srelgot,
|
||||||
&outrel);
|
&outrel);
|
||||||
}
|
}
|
||||||
@ -2628,22 +2824,16 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||||||
{
|
{
|
||||||
struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
|
struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
|
||||||
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
|
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
|
||||||
asection *plt = NULL;
|
|
||||||
|
|
||||||
if (h->plt.offset != MINUS_ONE)
|
if (h->plt.offset != MINUS_ONE)
|
||||||
{
|
{
|
||||||
size_t i, plt_idx;
|
size_t i, plt_idx;
|
||||||
asection *gotplt, *relplt;
|
asection *plt, *gotplt, *relplt;
|
||||||
bfd_vma got_address;
|
bfd_vma got_address;
|
||||||
uint32_t plt_entry[PLT_ENTRY_INSNS];
|
uint32_t plt_entry[PLT_ENTRY_INSNS];
|
||||||
bfd_byte *loc;
|
bfd_byte *loc;
|
||||||
Elf_Internal_Rela rela;
|
Elf_Internal_Rela rela;
|
||||||
|
|
||||||
plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
|
|
||||||
|
|
||||||
/* One of '.plt' and '.iplt' represents. */
|
|
||||||
BFD_ASSERT (!!htab->elf.splt ^ !!htab->elf.iplt);
|
|
||||||
|
|
||||||
if (htab->elf.splt)
|
if (htab->elf.splt)
|
||||||
{
|
{
|
||||||
BFD_ASSERT ((h->type == STT_GNU_IFUNC
|
BFD_ASSERT ((h->type == STT_GNU_IFUNC
|
||||||
@ -2653,6 +2843,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||||||
plt = htab->elf.splt;
|
plt = htab->elf.splt;
|
||||||
gotplt = htab->elf.sgotplt;
|
gotplt = htab->elf.sgotplt;
|
||||||
relplt = htab->elf.srelplt;
|
relplt = htab->elf.srelplt;
|
||||||
|
plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
|
||||||
got_address =
|
got_address =
|
||||||
sec_addr (gotplt) + GOTPLT_HEADER_SIZE + plt_idx * GOT_ENTRY_SIZE;
|
sec_addr (gotplt) + GOTPLT_HEADER_SIZE + plt_idx * GOT_ENTRY_SIZE;
|
||||||
}
|
}
|
||||||
@ -2664,6 +2855,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||||||
plt = htab->elf.iplt;
|
plt = htab->elf.iplt;
|
||||||
gotplt = htab->elf.igotplt;
|
gotplt = htab->elf.igotplt;
|
||||||
relplt = htab->elf.irelplt;
|
relplt = htab->elf.irelplt;
|
||||||
|
plt_idx = h->plt.offset / PLT_ENTRY_SIZE;
|
||||||
got_address = sec_addr (gotplt) + plt_idx * GOT_ENTRY_SIZE;
|
got_address = sec_addr (gotplt) + plt_idx * GOT_ENTRY_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2684,7 +2876,9 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||||||
bfd_put_NN (output_bfd, sec_addr (plt), loc);
|
bfd_put_NN (output_bfd, sec_addr (plt), loc);
|
||||||
|
|
||||||
rela.r_offset = got_address;
|
rela.r_offset = got_address;
|
||||||
if (h->type == STT_GNU_IFUNC && SYMBOL_REFERENCES_LOCAL (info, h))
|
|
||||||
|
/* TRUE if this is a PLT reference to a local IFUNC. */
|
||||||
|
if (PLT_LOCAL_IFUNC_P(info, h))
|
||||||
{
|
{
|
||||||
rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
|
rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
|
||||||
rela.r_addend = (h->root.u.def.value
|
rela.r_addend = (h->root.u.def.value
|
||||||
@ -2733,26 +2927,50 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||||||
|
|
||||||
rela.r_offset = sec_addr (sgot) + off;
|
rela.r_offset = sec_addr (sgot) + off;
|
||||||
|
|
||||||
if (h->type == STT_GNU_IFUNC)
|
if (h->def_regular
|
||||||
|
&& h->type == STT_GNU_IFUNC)
|
||||||
{
|
{
|
||||||
if (elf_hash_table (info)->dynamic_sections_created
|
if(h->plt.offset == MINUS_ONE)
|
||||||
&& SYMBOL_REFERENCES_LOCAL (info, h))
|
|
||||||
{
|
{
|
||||||
asection *sec = h->root.u.def.section;
|
if (htab->elf.splt == NULL)
|
||||||
rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
|
srela = htab->elf.irelplt;
|
||||||
rela.r_addend = (h->root.u.def.value + sec->output_section->vma
|
|
||||||
+ sec->output_offset);
|
if (SYMBOL_REFERENCES_LOCAL (info, h))
|
||||||
bfd_put_NN (output_bfd, 0, sgot->contents + off);
|
{
|
||||||
|
asection *sec = h->root.u.def.section;
|
||||||
|
rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
|
||||||
|
rela.r_addend = h->root.u.def.value + sec->output_section->vma
|
||||||
|
+ sec->output_offset;
|
||||||
|
bfd_put_NN (output_bfd, 0, sgot->contents + off);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BFD_ASSERT ((h->got.offset & 1) == 0);
|
||||||
|
BFD_ASSERT (h->dynindx != -1);
|
||||||
|
rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
|
||||||
|
rela.r_addend = 0;
|
||||||
|
bfd_put_NN (output_bfd, (bfd_vma) 0, sgot->contents + off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(bfd_link_pic (info))
|
||||||
|
{
|
||||||
|
rela.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
|
||||||
|
rela.r_addend = 0;
|
||||||
|
bfd_put_NN (output_bfd, rela.r_addend, sgot->contents + off);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BFD_ASSERT (plt);
|
asection *plt;
|
||||||
rela.r_info
|
/* For non-shared object, we can't use .got.plt, which
|
||||||
= ELFNN_R_INFO (0, (bfd_link_pic (info)
|
contains the real function address if we need pointer
|
||||||
? R_LARCH_RELATIVE : R_LARCH_NONE));
|
equality. We load the GOT entry with the PLT entry. */
|
||||||
rela.r_addend =
|
plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
|
||||||
plt->output_section->vma + plt->output_offset + h->plt.offset;
|
bfd_put_NN (output_bfd,
|
||||||
bfd_put_NN (output_bfd, rela.r_addend, sgot->contents + off);
|
(plt->output_section->vma
|
||||||
|
+ plt->output_offset
|
||||||
|
+ h->plt.offset),
|
||||||
|
sgot->contents + off);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
|
else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
|
||||||
@ -2885,10 +3103,8 @@ loongarch_elf_finish_dynamic_sections (bfd *output_bfd,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((plt = htab->elf.splt))
|
plt = htab->elf.splt;
|
||||||
gotplt = htab->elf.sgotplt;
|
gotplt = htab->elf.sgotplt;
|
||||||
else if ((plt = htab->elf.iplt))
|
|
||||||
gotplt = htab->elf.igotplt;
|
|
||||||
|
|
||||||
if (plt && 0 < plt->size)
|
if (plt && 0 < plt->size)
|
||||||
{
|
{
|
||||||
@ -3017,10 +3233,10 @@ loongarch_elf_copy_indirect_symbol (struct bfd_link_info *info,
|
|||||||
struct elf_link_hash_entry *dir,
|
struct elf_link_hash_entry *dir,
|
||||||
struct elf_link_hash_entry *ind)
|
struct elf_link_hash_entry *ind)
|
||||||
{
|
{
|
||||||
struct loongarch_elf_link_hash_entry *edir, *eind;
|
struct elf_link_hash_entry *edir, *eind;
|
||||||
|
|
||||||
edir = (struct loongarch_elf_link_hash_entry *) dir;
|
edir = dir;
|
||||||
eind = (struct loongarch_elf_link_hash_entry *) ind;
|
eind = ind;
|
||||||
|
|
||||||
if (eind->dyn_relocs != NULL)
|
if (eind->dyn_relocs != NULL)
|
||||||
{
|
{
|
||||||
@ -3055,8 +3271,9 @@ loongarch_elf_copy_indirect_symbol (struct bfd_link_info *info,
|
|||||||
|
|
||||||
if (ind->root.type == bfd_link_hash_indirect && dir->got.refcount < 0)
|
if (ind->root.type == bfd_link_hash_indirect && dir->got.refcount < 0)
|
||||||
{
|
{
|
||||||
edir->tls_type = eind->tls_type;
|
loongarch_elf_hash_entry(edir)->tls_type
|
||||||
eind->tls_type = GOT_UNKNOWN;
|
= loongarch_elf_hash_entry(eind)->tls_type;
|
||||||
|
loongarch_elf_hash_entry(eind)->tls_type = GOT_UNKNOWN;
|
||||||
}
|
}
|
||||||
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
|
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
|
||||||
}
|
}
|
||||||
|
@ -31,3 +31,11 @@ extern reloc_howto_type *
|
|||||||
loongarch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name);
|
loongarch_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name);
|
||||||
|
|
||||||
bool loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto, bfd_vma *fix_val);
|
bool loongarch_adjust_reloc_bitsfield (reloc_howto_type *howto, bfd_vma *fix_val);
|
||||||
|
|
||||||
|
/* TRUE if this is a PLT reference to a local IFUNC. */
|
||||||
|
#define PLT_LOCAL_IFUNC_P(INFO, H) \
|
||||||
|
((H)->dynindx == -1 \
|
||||||
|
|| ((bfd_link_executable (INFO) \
|
||||||
|
|| ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT) \
|
||||||
|
&& (H)->def_regular \
|
||||||
|
&& (H)->type == STT_GNU_IFUNC))
|
||||||
|
Reference in New Issue
Block a user