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:
parent
3b14682a43
commit
d218dba3f4
@ -42,9 +42,6 @@ struct loongarch_elf_link_hash_entry
|
||||
{
|
||||
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_NORMAL 1
|
||||
#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)
|
||||
{
|
||||
eh = (struct loongarch_elf_link_hash_entry *) entry;
|
||||
eh->dyn_relocs = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
/* It is referenced by a non-shared object. */
|
||||
if (h != NULL)
|
||||
h->ref_regular = 1;
|
||||
|
||||
if (h && h->type == STT_GNU_IFUNC)
|
||||
{
|
||||
if (htab->elf.dynobj == NULL)
|
||||
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
|
||||
&& !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
|
||||
/* 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)
|
||||
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;
|
||||
|
||||
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
|
||||
relocations we need for this symbol. */
|
||||
if (h != NULL)
|
||||
head = &((struct loongarch_elf_link_hash_entry *) h)->dyn_relocs;
|
||||
head = &h->dyn_relocs;
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
|
||||
@ -986,13 +1010,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
{
|
||||
struct bfd_link_info *info;
|
||||
struct loongarch_elf_link_hash_table *htab;
|
||||
struct loongarch_elf_link_hash_entry *eh;
|
||||
struct elf_dyn_relocs *p;
|
||||
|
||||
if (h->root.type == bfd_link_hash_indirect)
|
||||
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;
|
||||
htab = loongarch_elf_hash_table (info);
|
||||
BFD_ASSERT (htab != NULL);
|
||||
@ -1041,6 +1067,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
gotplt->size += GOT_ENTRY_SIZE;
|
||||
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;
|
||||
}
|
||||
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.
|
||||
Undefined weak syms won't yet be marked as dynamic. */
|
||||
if (h->dynindx == -1 && !h->forced_local
|
||||
&& !bfd_elf_link_record_dynamic_symbol (info, h))
|
||||
return false;
|
||||
if (h->dynindx == -1 && !h->forced_local)
|
||||
{
|
||||
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;
|
||||
h->got.offset = s->size;
|
||||
@ -1091,14 +1140,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
else
|
||||
h->got.offset = MINUS_ONE;
|
||||
|
||||
if (eh->dyn_relocs == NULL)
|
||||
if (h->dyn_relocs == NULL)
|
||||
return true;
|
||||
|
||||
if (SYMBOL_REFERENCES_LOCAL (info, h))
|
||||
{
|
||||
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->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 (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
|
||||
eh->dyn_relocs = NULL;
|
||||
h->dyn_relocs = NULL;
|
||||
else if (h->dynindx == -1 && !h->forced_local
|
||||
/* Make sure this symbol is output as a dynamic symbol.
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
sreloc->size += p->count * sizeof (ElfNN_External_Rela);
|
||||
@ -1129,16 +1178,60 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||
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
|
||||
elfNN_loongarch_allocate_local_dynrelocs (void **slot, void *inf)
|
||||
{
|
||||
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)
|
||||
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
|
||||
@ -1275,6 +1368,11 @@ loongarch_elf_size_dynamic_sections (bfd *output_bfd,
|
||||
/* Allocate global sym .plt and .got entries, and space for global
|
||||
sym dynamic relocs. */
|
||||
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. */
|
||||
htab_traverse (htab->loc_hash_table,
|
||||
(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;
|
||||
}
|
||||
|
||||
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;
|
||||
resolved_local = true;
|
||||
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_dynly || (h && h->dynindx != -1));
|
||||
/* BFD_ASSERT (!resolved_dynly || (h && h->dynindx != -1));. */
|
||||
|
||||
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));
|
||||
|
||||
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_addend = rel->r_addend;
|
||||
@ -2093,6 +2210,25 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||
bfd_reloc_notsupported,
|
||||
is_undefweak, name,
|
||||
"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;
|
||||
|
||||
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;
|
||||
|
||||
if (off == MINUS_ONE)
|
||||
if (off == MINUS_ONE
|
||||
&& h->type != STT_GNU_IFUNC)
|
||||
{
|
||||
fatal = (loongarch_reloc_is_fatal
|
||||
(info, input_bfd, input_section, rel, howto,
|
||||
@ -2284,6 +2421,33 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||
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)
|
||||
|| (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;
|
||||
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);
|
||||
h->got.offset |= 1;
|
||||
}
|
||||
@ -2516,9 +2702,19 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
||||
}
|
||||
else /* if (resolved_dynly) */
|
||||
{
|
||||
outrel.r_info =
|
||||
ELFNN_R_INFO (h->dynindx, R_LARCH_TLS_TPRELNN);
|
||||
outrel.r_addend = 0;
|
||||
/* Static linking has no .dynsym table. */
|
||||
if (!htab->elf.dynamic_sections_created)
|
||||
{
|
||||
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,
|
||||
&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);
|
||||
const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
|
||||
asection *plt = NULL;
|
||||
|
||||
if (h->plt.offset != MINUS_ONE)
|
||||
{
|
||||
size_t i, plt_idx;
|
||||
asection *gotplt, *relplt;
|
||||
asection *plt, *gotplt, *relplt;
|
||||
bfd_vma got_address;
|
||||
uint32_t plt_entry[PLT_ENTRY_INSNS];
|
||||
bfd_byte *loc;
|
||||
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)
|
||||
{
|
||||
BFD_ASSERT ((h->type == STT_GNU_IFUNC
|
||||
@ -2653,6 +2843,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
|
||||
plt = htab->elf.splt;
|
||||
gotplt = htab->elf.sgotplt;
|
||||
relplt = htab->elf.srelplt;
|
||||
plt_idx = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
|
||||
got_address =
|
||||
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;
|
||||
gotplt = htab->elf.igotplt;
|
||||
relplt = htab->elf.irelplt;
|
||||
plt_idx = h->plt.offset / PLT_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);
|
||||
|
||||
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_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;
|
||||
|
||||
if (h->type == STT_GNU_IFUNC)
|
||||
if (h->def_regular
|
||||
&& h->type == STT_GNU_IFUNC)
|
||||
{
|
||||
if (elf_hash_table (info)->dynamic_sections_created
|
||||
&& SYMBOL_REFERENCES_LOCAL (info, h))
|
||||
if(h->plt.offset == MINUS_ONE)
|
||||
{
|
||||
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);
|
||||
if (htab->elf.splt == NULL)
|
||||
srela = htab->elf.irelplt;
|
||||
|
||||
if (SYMBOL_REFERENCES_LOCAL (info, h))
|
||||
{
|
||||
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
|
||||
{
|
||||
BFD_ASSERT (plt);
|
||||
rela.r_info
|
||||
= ELFNN_R_INFO (0, (bfd_link_pic (info)
|
||||
? R_LARCH_RELATIVE : R_LARCH_NONE));
|
||||
rela.r_addend =
|
||||
plt->output_section->vma + plt->output_offset + h->plt.offset;
|
||||
bfd_put_NN (output_bfd, rela.r_addend, sgot->contents + off);
|
||||
asection *plt;
|
||||
/* For non-shared object, we can't use .got.plt, which
|
||||
contains the real function address if we need pointer
|
||||
equality. We load the GOT entry with the PLT entry. */
|
||||
plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
|
||||
bfd_put_NN (output_bfd,
|
||||
(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))
|
||||
@ -2885,10 +3103,8 @@ loongarch_elf_finish_dynamic_sections (bfd *output_bfd,
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((plt = htab->elf.splt))
|
||||
gotplt = htab->elf.sgotplt;
|
||||
else if ((plt = htab->elf.iplt))
|
||||
gotplt = htab->elf.igotplt;
|
||||
plt = htab->elf.splt;
|
||||
gotplt = htab->elf.sgotplt;
|
||||
|
||||
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 *ind)
|
||||
{
|
||||
struct loongarch_elf_link_hash_entry *edir, *eind;
|
||||
struct elf_link_hash_entry *edir, *eind;
|
||||
|
||||
edir = (struct loongarch_elf_link_hash_entry *) dir;
|
||||
eind = (struct loongarch_elf_link_hash_entry *) ind;
|
||||
edir = dir;
|
||||
eind = ind;
|
||||
|
||||
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)
|
||||
{
|
||||
edir->tls_type = eind->tls_type;
|
||||
eind->tls_type = GOT_UNKNOWN;
|
||||
loongarch_elf_hash_entry(edir)->tls_type
|
||||
= 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);
|
||||
}
|
||||
|
@ -31,3 +31,11 @@ extern reloc_howto_type *
|
||||
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);
|
||||
|
||||
/* 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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user