代码拉取完成,页面将自动刷新
同步操作将从 src-anolis-os/binutils 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 7ea119f8dfcdd0b6b5471184bb62b54c453070a6 Mon Sep 17 00:00:00 2001
From: Xing Li <[email protected]>
Date: Tue, 18 Jul 2023 12:33:45 +0800
Subject: [PATCH] ld: Add ifunc support.
---
bfd/elfnn-loongarch.c | 435 ++++++++++++++++++++++++++++----------
gas/config/tc-loongarch.c | 49 +++--
2 files changed, 355 insertions(+), 129 deletions(-)
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index f609a756..93459979 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -21,8 +21,6 @@ loongarch_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
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
@@ -689,14 +687,27 @@ 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;
- if (!htab->elf.splt
+ /* Create 'irelifunc' in PIC object. */
+ if (bfd_link_pic (info)
+ && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
+ return FALSE;
+ /* If '.plt' not represent, create '.iplt' to deal with ifunc. */
+ else if (!htab->elf.splt
+ && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
+ return FALSE;
+ /* 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))
- /* If '.plt' not represent, create '.iplt' to deal with ifunc. */
return FALSE;
if (h->plt.refcount < 0)
@@ -704,8 +715,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
h->plt.refcount++;
h->needs_plt = 1;
- elf_tdata (info->output_bfd)->has_gnu_symbols
- |= elf_gnu_symbol_ifunc;
+ elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc;
}
need_dynreloc = 0;
@@ -713,6 +723,10 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
switch (r_type)
{
case R_LARCH_SOP_PUSH_GPREL:
+ /* For la.global. */
+ if (h)
+ h->pointer_equality_needed = 1;
+
if (!loongarch_elf_record_tls_and_got_reference
(abfd, info, h, r_symndx, GOT_NORMAL))
return FALSE;
@@ -774,12 +788,14 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_LARCH_SOP_PUSH_PCREL:
if (h != NULL)
{
- h->non_got_ref = 1;
+ if (!bfd_link_pic (info))
+ h->non_got_ref = 1;
/* We try to create PLT stub for all non-local function. */
if (h->plt.refcount < 0)
h->plt.refcount = 0;
h->plt.refcount++;
+ h->pointer_equality_needed = 1;
}
break;
@@ -819,8 +835,23 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
Thus, only under pde, it needs pcrel only. We discard it. */
only_need_pcrel = bfd_link_pde (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:
@@ -859,7 +890,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 = &loongarch_elf_hash_entry(h)->dyn_relocs;
else
{
/* Track dynamic relocs needed for local syms too.
@@ -906,7 +937,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 = loongarch_elf_hash_entry(h)->dyn_relocs; p != NULL; p = p->next)
{
asection *s = p->sec->output_section;
@@ -982,6 +1013,10 @@ loongarch_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
return TRUE;
}
+ /* PIC support only. */
+ /* Unnecessary to support copy relocation. */
+// return TRUE;
+
/* This is a reference to a symbol defined by a dynamic object which
is not a function. */
@@ -1067,6 +1102,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
+ if (h->type == STT_GNU_IFUNC
+ && h->def_regular)
+ return TRUE;
+
eh = (struct loongarch_elf_link_hash_entry *) h;
info = (struct bfd_link_info *) inf;
htab = loongarch_elf_hash_table (info);
@@ -1127,6 +1166,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);
@@ -1168,26 +1219,31 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
else
{
s->size += GOT_ENTRY_SIZE;
- if ((WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h)
- && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
- || h->type == STT_GNU_IFUNC)
+ if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
+ && (bfd_link_pic (info)
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
+ h))
+ && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
+ /* Undefined weak symbol in static PIE resolves to 0 without
+ any dynamic relocations. */
htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
}
}
else
h->got.offset = MINUS_ONE;
- if (eh->dyn_relocs == NULL)
+ if (loongarch_elf_hash_entry(h)->dyn_relocs == NULL)
return TRUE;
/* 如果某些函数未被定义,SYMBOL_CALLS_LOCAL返回1;
而SYMBOL_REFERENCES_LOCAL返回0。
似乎是因为未定义的函数可以有plt从而将其转化为local的。 */
- if (SYMBOL_REFERENCES_LOCAL (info, h))
+ if (SYMBOL_CALLS_LOCAL (info, h))
{
struct elf_dyn_relocs **pp;
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
+ for (pp = &loongarch_elf_hash_entry(h)->dyn_relocs; (p = *pp) != NULL; )
{
p->count -= p->pc_count;
p->pc_count = 0;
@@ -1201,15 +1257,21 @@ 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;
- else if (h->dynindx == -1 && !h->forced_local
+ loongarch_elf_hash_entry(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. */
- && !bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
+ if (!bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+
+ if (h->dynindx == -1)
+ loongarch_elf_hash_entry(h)->dyn_relocs = NULL;
+ }
+
}
- for (p = eh->dyn_relocs; p != NULL; p = p->next)
+ for (p = loongarch_elf_hash_entry(h)->dyn_relocs; p != NULL; p = p->next)
{
asection *sreloc = elf_section_data (p->sec)->sreloc;
sreloc->size += p->count * sizeof (ElfNN_External_Rela);
@@ -1218,6 +1280,64 @@ 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 bfd_boolean
+elfNN_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,
+ &loongarch_elf_hash_entry(h)->dyn_relocs,
+ NULL,
+ 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 bfd_boolean
+elfNN_allocate_local_ifunc_dynrelocs (void **slot, void *inf)
+{
+ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) *slot;
+
+ if (h->type != STT_GNU_IFUNC
+ || !h->def_regular
+ || !h->ref_regular
+ || !h->forced_local
+ || h->root.type != bfd_link_hash_defined)
+ abort ();
+
+ return elfNN_allocate_ifunc_dynrelocs (h, inf);
+}
+
static bfd_boolean
elfNN_loongarch_allocate_local_dynrelocs (void **slot, void *inf)
{
@@ -1364,13 +1484,18 @@ loongarch_elf_size_dynamic_sections (bfd *output_bfd,
}
}
+
+ /* Allocate global ifunc sym .plt and .got entries, and space for global
+ ifunc sym dynamic relocs. */
+ elf_link_hash_traverse (&htab->elf, elfNN_allocate_ifunc_dynrelocs, info);
+
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
/* Allocate .plt and .got entries, and space for local ifunc symbols. */
htab_traverse (htab->loc_hash_table,
- elfNN_loongarch_allocate_local_dynrelocs,
- info);
+ (void *) elfNN_allocate_local_ifunc_dynrelocs, info);
+
/* Don't allocate .got.plt section if there are no PLT. */
if (htab->elf.sgotplt
@@ -2006,7 +2131,7 @@ loongarch_elf_relocate_section (bfd *output_bfd,
if (bfd_link_relocatable(info)
&& ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
rel->r_addend += sec->output_offset;
- }
+ }
}
else
{
@@ -2073,7 +2198,7 @@ loongarch_elf_relocate_section (bfd *output_bfd,
resolved_dynly = resolved_local = defined_local = FALSE
, resolved_to_const = TRUE;
- if (h && h->type == STT_GNU_IFUNC)
+ if (h && h->type == STT_GNU_IFUNC && h->plt.offset != MINUS_ONE)
{
/* a. 动态连接器可以直接处理STT_GNU_IFUNC,因为动态连接器可以察觉到
一个动态符号是STT_GNU_IFUNC,从而在装载时执行resolver;
@@ -2165,17 +2290,64 @@ loongarch_elf_relocate_section (bfd *output_bfd,
/* When generating a shared object, these relocations are copied
into the output file to be resolved at run time. */
- outrel.r_offset =
- _bfd_elf_section_offset (output_bfd, info, input_section,
- rel->r_offset);
- unresolved_reloc = !((bfd_vma) -2 <= outrel.r_offset)
- && (input_section->flags & SEC_ALLOC);
+ outrel.r_offset = _bfd_elf_section_offset (output_bfd, info,
+ input_section,
+ rel->r_offset);
+ unresolved_reloc = (!((bfd_vma) -2 <= outrel.r_offset)
+ && (input_section->flags & SEC_ALLOC));
outrel.r_offset += sec_addr (input_section);
- if (resolved_dynly)
+
+ /* A pointer point to a ifunc symbol. */
+ if (h && h->type == STT_GNU_IFUNC)
+ {
+ if (h->dynindx == -1)
+ {
+ 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);
+ }
+ else
+ {
+ outrel.r_info = ELFNN_R_INFO (h->dynindx, R_LARCH_NN);
+ outrel.r_addend = 0;
+ }
+
+ if (SYMBOL_REFERENCES_LOCAL (info, h))
+ {
+
+ if (htab->elf.splt != NULL)
+ sreloc = htab->elf.srelgot;
+ else
+ sreloc = htab->elf.irelplt;
+ }
+ else
+ {
+
+ 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);
+ if (h->dynindx == -1)
+ {
+ if (h->root.type == bfd_link_hash_undefined)
+ (*info->callbacks->undefined_symbol)
+ (info, name, input_bfd, input_section,
+ rel->r_offset, TRUE);
+
+ outrel.r_info = ELFNN_R_INFO (0, r_type);
+ }
+ else
+ outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
+
outrel.r_addend = rel->r_addend;
}
else
@@ -2184,7 +2356,10 @@ loongarch_elf_relocate_section (bfd *output_bfd,
outrel.r_addend = relocation + rel->r_addend;
}
- if (unresolved_reloc)
+ /* No alloc space of func allocate_dynrelocs. */
+ if (unresolved_reloc
+ && !(h && (h->is_weakalias
+ || !loongarch_elf_hash_entry(h)->dyn_relocs)))
loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
}
@@ -2351,67 +2526,96 @@ loongarch_elf_relocate_section (bfd *output_bfd,
LARCH_ASSERT (rel->r_addend == 0, bfd_reloc_notsupported,
"Shouldn't be with r_addend.");
- /* 约定在GOT表中写入连接时地址。动态连接器通过_GLOBAL_OFFSET_TABLE_的
- 连接时地址和运行时地址拿到模块的加载地址,拿到连接时地址的办法就是
- 拿到那个got entry。一些体系结构通过.dynamic的段基址拿到模块加载
- 地址,我没有这么做,因为这个段在static-pie下不存在。 */
if (h != NULL)
{
- off = h->got.offset;
+ off = h->got.offset & (~1);
- LARCH_ASSERT (off != MINUS_ONE, bfd_reloc_notsupported,
- "Internal: GOT entry doesn't represent.");
+ LARCH_ASSERT (!(h->got.offset == MINUS_ONE
+ && h->type != STT_GNU_IFUNC),
+ bfd_reloc_notsupported,
+ "Internal: GOT entry doesn't represent.");
- if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn, is_pic, h)
- || (is_pic && SYMBOL_REFERENCES_LOCAL (info, h)))
+ /* Hidden symbol not has .got entry, only .got.plt entry
+ so gprel is (plt - got). */
+ if (h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
{
- /* This is actually a static link, or it is a
- -Bsymbolic link and the symbol is defined
- locally, or the symbol was forced to be local
- because of a version file. We must initialize
- this entry in the global offset table. Since the
- offset must always be a multiple of the word size,
- we use the least significant bit to record whether
- we have initialized it already.
-
- When doing a dynamic link, we create a .rela.got
- relocation entry to initialize the value. This
- is done in the finish_dynamic_symbol routine. */
-
- /* 在这里先不用管STT_GNU_IFUNC。elf_finish_dynamic_symbol
- 会单独处理。 */
-
- LARCH_ASSERT (!resolved_dynly, bfd_reloc_dangerous,
- "Internal: here shouldn't dynamic.");
- LARCH_ASSERT (defined_local || resolved_to_const,
- bfd_reloc_undefined, "Internal: ");
-
- if ((off & 1) != 0)
- off &= ~1;
+ BFD_ASSERT(h->plt.offset != (bfd_vma) -1);
+
+ 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
{
- bfd_put_NN (output_bfd, relocation, got->contents + off);
- h->got.offset |= 1;
+ /* Section iplt not has plt header. */
+ off = sec_addr (htab->elf.igotplt) + off
+ - sec_addr (htab->elf.sgot);
}
}
+
+ if ((h->got.offset & 1) == 0)
+ {
+ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn,
+ bfd_link_pic (info), h)
+ && ((bfd_link_pic (info)
+ && SYMBOL_REFERENCES_LOCAL (info, h))))
+ {
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally, or the symbol was forced to be local
+ because of a version file. We must initialize
+ this entry in the global offset table. Since the
+ offset must always be a multiple of the word size,
+ we use the least significant bit to record whether
+ we have initialized it already.
+
+ When doing a dynamic link, we create a rela.got
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+
+ LARCH_ASSERT (!resolved_dynly || (defined_local || resolved_to_const),
+ bfd_reloc_notsupported,
+ "Internal: here shouldn't dynamic.");
+
+ asection *s;
+ Elf_Internal_Rela outrel;
+ /* We need to generate a R_LARCH_RELATIVE reloc
+ for the dynamic linker. */
+ s = htab->elf.srelgot;
+ LARCH_ASSERT (s, bfd_reloc_notsupported,
+ "Internal: '.rel.got' not represent.");
+
+ 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;
+ }
}
else
{
LARCH_ASSERT (local_got_offsets, bfd_reloc_notsupported,
"Internal: local got offsets not reporesent.");
- off = local_got_offsets[r_symndx];
+ LARCH_ASSERT (local_got_offsets[r_symndx] != MINUS_ONE,
+ bfd_reloc_notsupported,
+ "Internal: GOT entry doesn't represent.");
- LARCH_ASSERT (off != MINUS_ONE, bfd_reloc_notsupported,
- "Internal: GOT entry doesn't represent.");
+ off = local_got_offsets[r_symndx] & (~1);
/* The offset must always be a multiple of the word size.
So, we can use the least significant bit to record
whether we have already processed this entry. */
- if ((off & 1) != 0)
- off &= ~1;
- else
+
+ if ((local_got_offsets[r_symndx] & 1) == 0)
{
if (is_pic)
{
@@ -2425,7 +2629,7 @@ loongarch_elf_relocate_section (bfd *output_bfd,
outrel.r_offset = sec_addr (got) + off;
outrel.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
- outrel.r_addend = relocation; /* link-time addr */
+ outrel.r_addend = relocation; /* Link-time addr. */
loongarch_elf_append_rela (output_bfd, s, &outrel);
}
@@ -2670,11 +2874,6 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
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
@@ -2684,6 +2883,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;
}
@@ -2695,6 +2895,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;
}
@@ -2764,39 +2965,49 @@ 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 (/* 加入这个条件的原因是,对于静态链接,IRELATIVE重定位类型在
- __libc_start_main中调用apply_irel,通过链接脚本提供的
- __rela_iplt_start和__rela_iplt_end遍历.rela.iplt中的动态重定位
- 表项,来调用各个resolver并将返回结果写入.igot.plt中。
- 问题是照顾不到.rela.iplt之外的IRELATIVE重定位,因此我们在静态
- 连接的情况下绝对不将IRELATIVE写入.igot.plt之外。这样做在运行时
- 可能会有一些性能影响,毕竟ifunc函数都走plt,需要load两次
- got entry。没什么好的解决方法,未来可以搞.iplt2用于延迟调用
- resolver。 */
- 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->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
+ else if(bfd_link_pic (info))
{
- 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;
+ 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
+ {
+ 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))
{
@@ -2809,7 +3020,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
}
else
{
- BFD_ASSERT ((h->got.offset & 1) == 0);
+ //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;
@@ -2929,10 +3140,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)
{
@@ -2963,8 +3172,6 @@ loongarch_elf_finish_dynamic_sections (bfd *output_bfd,
linker. */
bfd_put_NN (output_bfd, MINUS_ONE, htab->elf.sgotplt->contents);
- /* 第二项非0时动态连接器认为它是plt header的地址,从而影响到所有
- R_LARCH_JUMP_SLOT。这似乎是为了prelink预留的。 */
bfd_put_NN (output_bfd, (bfd_vma) 0,
htab->elf.sgotplt->contents + GOT_ENTRY_SIZE);
}
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index 9ab015a3..fbcc7c1f 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -1156,9 +1156,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
case BFD_RELOC_32:
if (fixP->fx_subsy)
{
- case BFD_RELOC_24:
- case BFD_RELOC_16:
- case BFD_RELOC_8:
fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
fixP->fx_next->fx_addsy = fixP->fx_subsy;
fixP->fx_next->fx_subsy = NULL;
@@ -1175,18 +1172,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
fixP->fx_r_type = BFD_RELOC_LARCH_ADD32;
fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB32;
break;
- case BFD_RELOC_24:
- fixP->fx_r_type = BFD_RELOC_LARCH_ADD24;
- fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB24;
- break;
- case BFD_RELOC_16:
- fixP->fx_r_type = BFD_RELOC_LARCH_ADD16;
- fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB16;
- break;
- case BFD_RELOC_8:
- fixP->fx_r_type = BFD_RELOC_LARCH_ADD8;
- fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB8;
- break;
default:
break;
}
@@ -1200,6 +1185,40 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
md_number_to_chars (buf, *valP, fixP->fx_size);
}
break;
+ /* case BFD_RELOC_24: */
+ case BFD_RELOC_16:
+ case BFD_RELOC_8:
+ fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
+ fixP->fx_next->fx_addsy = fixP->fx_subsy;
+ fixP->fx_next->fx_subsy = NULL;
+ fixP->fx_next->fx_offset = 0;
+ fixP->fx_subsy = NULL;
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_16:
+ fixP->fx_r_type = BFD_RELOC_LARCH_ADD16;
+ fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB16;
+ break;
+ case BFD_RELOC_8:
+ fixP->fx_r_type = BFD_RELOC_LARCH_ADD8;
+ fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB8;
+ break;
+ default:
+ break;
+ }
+
+ md_number_to_chars (buf, 0, fixP->fx_size);
+
+ if (fixP->fx_next->fx_addsy == NULL)
+ fixP->fx_next->fx_done = 1;
+
+ if (fixP->fx_addsy == NULL)
+ {
+ fixP->fx_done = 1;
+ md_number_to_chars (buf, *valP, fixP->fx_size);
+ }
+ break;
default:
break;
--
2.27.0
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。