LoongArch: Fix the issue of excessive relocation generated by GD and IE

Currently, whether GD and IE generate dynamic relocation is
determined by SYMBOL_REFERENCES_LOCAL and bfd_link_executable.
This results in dynamic relocations still being generated in some
situations where dynamic relocations are not necessary (such as
the undefined weak symbol in static links).

We use RLARCH_TLS_GD_IE_NEED_DYN_RELOC macros to determine whether
GD/IE needs dynamic relocation. If GD/IE requires dynamic relocation,
set need_reloc to true and indx to be a dynamic index.

At the same time, some test cases were modified to use regular
expression matching instead of complete disassembly matching.
This commit is contained in:
Lulu Cai 2024-03-21 16:33:21 +08:00 committed by liuzhensong
parent 7918b183ec
commit b67a17aa7c
3 changed files with 142 additions and 135 deletions

View file

@ -159,6 +159,27 @@ struct loongarch_elf_link_hash_table
|| (R_TYPE) == R_LARCH_TLS_LE64_LO20 \ || (R_TYPE) == R_LARCH_TLS_LE64_LO20 \
|| (R_TYPE) == R_LARCH_TLS_LE64_HI12) || (R_TYPE) == R_LARCH_TLS_LE64_HI12)
/* If TLS GD/IE need dynamic relocations, INDX will be the dynamic indx,
and set NEED_RELOC to true used in allocate_dynrelocs and
loongarch_elf_relocate_section for TLS GD/IE. */
#define LARCH_TLS_GD_IE_NEED_DYN_RELOC(INFO, DYN, H, INDX, NEED_RELOC) \
do \
{ \
if ((H) != NULL \
&& (H)->dynindx != -1 \
&& WILL_CALL_FINISH_DYNAMIC_SYMBOL ((DYN), \
bfd_link_pic (INFO), (H))) \
(INDX) = (H)->dynindx; \
if (((H) == NULL \
|| ELF_ST_VISIBILITY ((H)->other) == STV_DEFAULT \
|| (H)->root.type != bfd_link_hash_undefweak) \
&& (!bfd_link_executable (INFO) \
|| (INDX) != 0)) \
(NEED_RELOC) = true; \
} \
while (0)
/* Generate a PLT header. */ /* Generate a PLT header. */
static bool static bool
@ -1276,40 +1297,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
h->got.offset = s->size; h->got.offset = s->size;
if (tls_type & (GOT_TLS_GD | GOT_TLS_IE | GOT_TLS_GDESC)) if (tls_type & (GOT_TLS_GD | GOT_TLS_IE | GOT_TLS_GDESC))
{ {
int indx = 0;
bool need_reloc = false;
LARCH_TLS_GD_IE_NEED_DYN_RELOC (info, dyn, h, indx,
need_reloc);
/* TLS_GD needs two dynamic relocs and two GOT slots. */ /* TLS_GD needs two dynamic relocs and two GOT slots. */
if (tls_type & GOT_TLS_GD) if (tls_type & GOT_TLS_GD)
{ {
s->size += 2 * GOT_ENTRY_SIZE; s->size += 2 * GOT_ENTRY_SIZE;
if (bfd_link_executable (info)) if (need_reloc)
{ htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
/* Link exe and not defined local. */
if (!SYMBOL_REFERENCES_LOCAL (info, h))
htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
}
else
{
if (SYMBOL_REFERENCES_LOCAL (info, h))
htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
else
htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
}
} }
/* TLS_IE needs one dynamic reloc and one GOT slot. */ /* TLS_IE needs one dynamic reloc and one GOT slot. */
if (tls_type & GOT_TLS_IE) if (tls_type & GOT_TLS_IE)
{ {
s->size += GOT_ENTRY_SIZE; s->size += GOT_ENTRY_SIZE;
if (need_reloc)
if (bfd_link_executable (info)) htab->elf.srelgot->size += 2 * sizeof (ElfNN_External_Rela);
{
/* Link exe and not defined local. */
if (!SYMBOL_REFERENCES_LOCAL (info, h))
htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
}
else
{
htab->elf.srelgot->size += sizeof (ElfNN_External_Rela);
}
} }
/* TLS_DESC needs one dynamic reloc and two GOT slot. */ /* TLS_DESC needs one dynamic reloc and two GOT slot. */
@ -2550,13 +2555,18 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info,
}) })
/* Compute the tp/dtp offset of a tls symbol.
It is dtp offset in dynamic tls model (gd/ld) and tp
offset in static tls model (ie/le). Both offsets are
calculated the same way on LoongArch, so the same
function is used. */
static bfd_vma static bfd_vma
tls_dtpoff_base (struct bfd_link_info *info) tlsoff (struct bfd_link_info *info, bfd_vma addr)
{ {
/* 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 (elf_hash_table (info)->tls_sec == NULL)
return 0; return 0;
return elf_hash_table (info)->tls_sec->vma; return addr - elf_hash_table (info)->tls_sec->vma;
} }
@ -2890,7 +2900,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
is_undefweak, name, "TLS section not be created"); is_undefweak, name, "TLS section not be created");
} }
else else
relocation -= elf_hash_table (info)->tls_sec->vma; relocation = tlsoff (info, relocation);
} }
else else
{ {
@ -3416,7 +3426,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_LARCH_TLS_LE_HI20_R: case R_LARCH_TLS_LE_HI20_R:
relocation += rel->r_addend; relocation += rel->r_addend;
relocation -= elf_hash_table (info)->tls_sec->vma; relocation = tlsoff (info, relocation);
RELOCATE_TLS_TP32_HI20 (relocation); RELOCATE_TLS_TP32_HI20 (relocation);
break; break;
@ -3599,7 +3609,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
BFD_ASSERT (resolved_local && elf_hash_table (info)->tls_sec); BFD_ASSERT (resolved_local && elf_hash_table (info)->tls_sec);
relocation += rel->r_addend; relocation += rel->r_addend;
relocation -= elf_hash_table (info)->tls_sec->vma; relocation = tlsoff (info, relocation);
break; break;
/* TLS IE LD/GD process separately is troublesome. /* TLS IE LD/GD process separately is troublesome.
@ -3654,71 +3664,72 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
/* If a tls variable is accessed in multiple ways, GD uses /* If a tls variable is accessed in multiple ways, GD uses
the first two slots of GOT, desc follows with two slots, the first two slots of GOT, desc follows with two slots,
and IE uses one slot at the end. */ and IE uses one slot at the end. */
desc_off = 0; off = 0;
if (GOT_TLS_GD_BOTH_P (tls_type)) if (tls_type & GOT_TLS_GD)
desc_off = 2 * GOT_ENTRY_SIZE; off += 2 * GOT_ENTRY_SIZE;
desc_off = off;
ie_off = 0; if (tls_type & GOT_TLS_GDESC)
if (GOT_TLS_GD_BOTH_P (tls_type) && (tls_type & GOT_TLS_IE)) off += 2 * GOT_ENTRY_SIZE;
ie_off = 4 * GOT_ENTRY_SIZE; ie_off = off;
else if (GOT_TLS_GD_ANY_P (tls_type) && (tls_type & GOT_TLS_IE))
ie_off = 2 * GOT_ENTRY_SIZE;
if ((got_off & 1) == 0) if ((got_off & 1) == 0)
{ {
Elf_Internal_Rela rela; Elf_Internal_Rela rela;
asection *relgot = htab->elf.srelgot; asection *relgot = htab->elf.srelgot;
bfd_vma tls_block_off = 0;
if (SYMBOL_REFERENCES_LOCAL (info, h)) int indx = 0;
{ bool need_reloc = false;
BFD_ASSERT (elf_hash_table (info)->tls_sec); LARCH_TLS_GD_IE_NEED_DYN_RELOC (info, is_dyn, h, indx,
tls_block_off = relocation need_reloc);
- elf_hash_table (info)->tls_sec->vma;
}
if (tls_type & GOT_TLS_GD) if (tls_type & GOT_TLS_GD)
{ {
rela.r_offset = sec_addr (got) + got_off; if (need_reloc)
rela.r_addend = 0;
if (SYMBOL_REFERENCES_LOCAL (info, h))
{ {
/* Local sym, used in exec, set module id 1. */ /* Dynamic resolved Module ID. */
if (bfd_link_executable (info)) rela.r_offset = sec_addr (got) + got_off;
bfd_put_NN (output_bfd, 1, got->contents + got_off); rela.r_addend = 0;
rela.r_info = ELFNN_R_INFO (indx,R_LARCH_TLS_DTPMODNN);
bfd_put_NN (output_bfd, 0, got->contents + got_off);
loongarch_elf_append_rela (output_bfd, relgot, &rela);
if (indx == 0)
{
/* Local symbol, tp offset has been known. */
BFD_ASSERT (! unresolved_reloc);
bfd_put_NN (output_bfd,
tlsoff (info, relocation),
(got->contents + got_off + GOT_ENTRY_SIZE));
}
else else
{ {
rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_DTPMODNN); /* Dynamic resolved block offset. */
bfd_put_NN (output_bfd, 0,
got->contents + got_off + GOT_ENTRY_SIZE);
rela.r_info = ELFNN_R_INFO (indx,
R_LARCH_TLS_DTPRELNN);
rela.r_offset += GOT_ENTRY_SIZE;
loongarch_elf_append_rela (output_bfd, relgot, &rela); loongarch_elf_append_rela (output_bfd, relgot, &rela);
} }
bfd_put_NN (output_bfd, tls_block_off,
got->contents + got_off + GOT_ENTRY_SIZE);
} }
/* Dynamic resolved. */
else else
{ {
/* Dynamic relocate module id. */ /* In a static link or an executable link with the symbol
rela.r_info = ELFNN_R_INFO (h->dynindx, binding locally. Mark it as belonging to module 1. */
R_LARCH_TLS_DTPMODNN); bfd_put_NN (output_bfd, 1, got->contents + got_off);
loongarch_elf_append_rela (output_bfd, relgot, &rela); bfd_put_NN (output_bfd, tlsoff (info, relocation),
got->contents + got_off + GOT_ENTRY_SIZE);
/* Dynamic relocate offset of block. */
rela.r_offset += GOT_ENTRY_SIZE;
rela.r_info = ELFNN_R_INFO (h->dynindx,
R_LARCH_TLS_DTPRELNN);
loongarch_elf_append_rela (output_bfd, relgot, &rela);
} }
} }
if (tls_type & GOT_TLS_GDESC) if (tls_type & GOT_TLS_GDESC)
{ {
/* Unless it is a static link, DESC always emits a /* Unless it is a static link, DESC always emits a
dynamic relocation. */ dynamic relocation. */
int indx = h && h->dynindx != -1 ? h->dynindx : 0; indx = h && h->dynindx != -1 ? h->dynindx : 0;
rela.r_offset = sec_addr (got) + got_off + desc_off; rela.r_offset = sec_addr (got) + got_off + desc_off;
rela.r_addend = 0; rela.r_addend = 0;
if (indx == 0) if (indx == 0)
rela.r_addend = relocation - tls_dtpoff_base (info); rela.r_addend = tlsoff (info, relocation);
rela.r_info = ELFNN_R_INFO (indx, R_LARCH_TLS_DESCNN); rela.r_info = ELFNN_R_INFO (indx, R_LARCH_TLS_DESCNN);
loongarch_elf_append_rela (output_bfd, relgot, &rela); loongarch_elf_append_rela (output_bfd, relgot, &rela);
@ -3727,28 +3738,24 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
} }
if (tls_type & GOT_TLS_IE) if (tls_type & GOT_TLS_IE)
{ {
rela.r_offset = sec_addr (got) + got_off + ie_off; if (need_reloc)
if (SYMBOL_REFERENCES_LOCAL (info, h))
{ {
/* Local sym, used in exec, set module id 1. */ bfd_put_NN (output_bfd, 0,
if (!bfd_link_executable (info)) got->contents + got_off + ie_off);
{ rela.r_offset = sec_addr (got) + got_off + ie_off;
rela.r_info = ELFNN_R_INFO (0, R_LARCH_TLS_TPRELNN); rela.r_addend = 0;
rela.r_addend = tls_block_off;
loongarch_elf_append_rela (output_bfd, relgot, &rela);
}
bfd_put_NN (output_bfd, tls_block_off, if (indx == 0)
got->contents + got_off + ie_off); rela.r_addend = tlsoff (info, relocation);
rela.r_info = ELFNN_R_INFO (indx, R_LARCH_TLS_TPRELNN);
loongarch_elf_append_rela (output_bfd, relgot, &rela);
} }
/* Dynamic resolved. */
else else
{ {
/* Dynamic relocate offset of block. */ /* In a static link or an executable link with the symbol
rela.r_info = ELFNN_R_INFO (h->dynindx, bindinglocally, compute offset directly. */
R_LARCH_TLS_TPRELNN); bfd_put_NN (output_bfd, tlsoff (info, relocation),
rela.r_addend = 0; got->contents + got_off + ie_off);
loongarch_elf_append_rela (output_bfd, relgot, &rela);
} }
} }
} }
@ -3787,7 +3794,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx); tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx);
/* Use both TLS_GD and TLS_DESC. */ /* Use both TLS_GD and TLS_DESC. */
if ((tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_GDESC)) if (GOT_TLS_GD_BOTH_P (tls_type))
relocation += 2 * GOT_ENTRY_SIZE; relocation += 2 * GOT_ENTRY_SIZE;
if (r_type == R_LARCH_TLS_DESC64_PC_LO20) if (r_type == R_LARCH_TLS_DESC64_PC_LO20)

View file

@ -9,6 +9,6 @@ Disassembly of section .text:
[0-9a-f]+ <fn1>: [0-9a-f]+ <fn1>:
+[0-9a-f]+: 1a000084 pcalau12i \$a0, .* +[0-9a-f]+: 1a000084 pcalau12i \$a0, .*
+[0-9a-f]+: 28cca084 ld.d \$a0, \$a0, .* +[0-9a-f]+: 28cd0084 ld.d \$a0, \$a0, .*
+[0-9a-f]+: 1a000084 pcalau12i \$a0, .* +[0-9a-f]+: 1a000084 pcalau12i \$a0, .*
+[0-9a-f]+: 28cca084 ld.d \$a0, \$a0, .* +[0-9a-f]+: 28cd0084 ld.d \$a0, \$a0, .*

View file

@ -8,53 +8,53 @@
Disassembly of section .text: Disassembly of section .text:
0+448 <fun_gl1>: [0-9a-f]+ <fun_gl1>:
448: 18021584 pcaddi \$a0, 4268 +[0-9a-f]+: 18021584 pcaddi \$a0, 4268
44c: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
450: 28dc2084 ld.d \$a0, \$a0, 1800 +[0-9a-f]+: 28dd4084 ld.d \$a0, \$a0, 1872
454: 18021364 pcaddi \$a0, 4251 +[0-9a-f]+: 18021364 pcaddi \$a0, 4251
458: 180213c4 pcaddi \$a0, 4254 +[0-9a-f]+: 180213c4 pcaddi \$a0, 4254
45c: 28c00081 ld.d \$ra, \$a0, 0 +[0-9a-f]+: 28c00081 ld.d \$ra, \$a0, 0
460: 4c000021 jirl \$ra, \$ra, 0 +[0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
464: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
468: 28dae084 ld.d \$a0, \$a0, 1720 +[0-9a-f]+: 28dc0084 ld.d \$a0, \$a0, 1792
46c: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
470: 28dae084 ld.d \$a0, \$a0, 1720 +[0-9a-f]+: 28dc0084 ld.d \$a0, \$a0, 1792
474: 18021364 pcaddi \$a0, 4251 +[0-9a-f]+: 18021364 pcaddi \$a0, 4251
478: 18021344 pcaddi \$a0, 4250 +[0-9a-f]+: 180213c4 pcaddi \$a0, 4254
47c: 28c00081 ld.d \$ra, \$a0, 0 +[0-9a-f]+: 28c00081 ld.d \$ra, \$a0, 0
480: 4c000021 jirl \$ra, \$ra, 0 +[0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
484: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
488: 28dbc084 ld.d \$a0, \$a0, 1776 +[0-9a-f]+: 28dce084 ld.d \$a0, \$a0, 1848
0+48c <fun_lo>: [0-9a-f]+ <fun_lo>:
48c: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
490: 28d98084 ld.d \$a0, \$a0, 1632 +[0-9a-f]+: 28daa084 ld.d \$a0, \$a0, 1704
494: 18020de4 pcaddi \$a0, 4207 +[0-9a-f]+: 18020de4 pcaddi \$a0, 4207
498: 18020f04 pcaddi \$a0, 4216 +[0-9a-f]+: 18020f04 pcaddi \$a0, 4216
49c: 28c00081 ld.d \$ra, \$a0, 0 +[0-9a-f]+: 28c00081 ld.d \$ra, \$a0, 0
4a0: 4c000021 jirl \$ra, \$ra, 0 +[0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
4a4: 18020e24 pcaddi \$a0, 4209 +[0-9a-f]+: 18020e24 pcaddi \$a0, 4209
4a8: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
4ac: 28da2084 ld.d \$a0, \$a0, 1672 +[0-9a-f]+: 28db4084 ld.d \$a0, \$a0, 1744
4b0: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
4b4: 28da2084 ld.d \$a0, \$a0, 1672 +[0-9a-f]+: 28db4084 ld.d \$a0, \$a0, 1744
4b8: 18020ec4 pcaddi \$a0, 4214 +[0-9a-f]+: 18020f44 pcaddi \$a0, 4218
4bc: 28c00081 ld.d \$ra, \$a0, 0 +[0-9a-f]+: 28c00081 ld.d \$ra, \$a0, 0
4c0: 4c000021 jirl \$ra, \$ra, 0 +[0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
4c4: 18020e64 pcaddi \$a0, 4211 +[0-9a-f]+: 18020e64 pcaddi \$a0, 4211
4c8: 1a000084 pcalau12i \$a0, 4 +[0-9a-f]+: 1a000084 pcalau12i \$a0, 4
4cc: 28da8084 ld.d \$a0, \$a0, 1696 +[0-9a-f]+: 28dba084 ld.d \$a0, \$a0, 1768
0+4d0 <fun_external>: [0-9a-f]+ <fun_external>:
4d0: 18020ec4 pcaddi \$a0, 4214 +[0-9a-f]+: 18020ec4 pcaddi \$a0, 4214
4d4: 28c00081 ld.d \$ra, \$a0, 0 +[0-9a-f]+: 28c00081 ld.d \$ra, \$a0, 0
4d8: 4c000021 jirl \$ra, \$ra, 0 +[0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
0+4dc <fun_hidden>: [0-9a-f]+ <fun_hidden>:
4dc: 18021224 pcaddi \$a0, 4241 +[0-9a-f]+: 18021224 pcaddi \$a0, 4241
4e0: 28c00081 ld.d \$ra, \$a0, 0 +[0-9a-f]+: 28c00081 ld.d \$ra, \$a0, 0
4e4: 4c000021 jirl \$ra, \$ra, 0 +[0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
4e8: 18021144 pcaddi \$a0, 4234 +[0-9a-f]+: 18021144 pcaddi \$a0, 4234
4ec: 28c00081 ld.d \$ra, \$a0, 0 +[0-9a-f]+: 28c00081 ld.d \$ra, \$a0, 0
4f0: 4c000021 jirl \$ra, \$ra, 0 +[0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0