[PATCH v1 2/2] LoongArch: Add bfd ld support for LA32 relocations
Lulu Cai
cailulu@loongson.cn
Sun Apr 27 09:22:24 GMT 2025
* Add ld.bfd support for 6 new relocations for LA32.
* TLS type transition and relaxation are not supported,
so when a TLS symbol is referenced by multiple types,
the required GOT slots are cumulative.
---
bfd/elfnn-loongarch.c | 215 +++++++++++++++++-
bfd/elfxx-loongarch.c | 10 +
.../ld-loongarch-elf/bad_pcadd_hi20_global.d | 6 +
.../ld-loongarch-elf/bad_pcadd_hi20_global.s | 12 +
.../ld-loongarch-elf/bad_pcadd_lo12.d | 4 +
.../ld-loongarch-elf/bad_pcadd_lo12.s | 4 +
.../ld-loongarch-elf/call32_undefweak.d | 6 +
.../ld-loongarch-elf/call32_undefweak.s | 15 ++
ld/testsuite/ld-loongarch-elf/la32r_relocs.s | 44 ++++
.../ld-loongarch-elf/la32r_relocs_nopie.d | 36 +++
.../ld-loongarch-elf/la32r_relocs_pie.d | 36 +++
ld/testsuite/ld-loongarch-elf/la32r_tls.s | 34 +++
ld/testsuite/ld-loongarch-elf/la32r_tls_bin.d | 17 ++
.../ld-loongarch-elf/la32r_tls_shared.d | 18 ++
ld/testsuite/ld-loongarch-elf/la32r_tlslib.s | 5 +
.../ld-loongarch-elf/ld-loongarch-elf.exp | 36 +++
16 files changed, 492 insertions(+), 6 deletions(-)
create mode 100644 ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.d
create mode 100644 ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.s
create mode 100644 ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.d
create mode 100644 ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.s
create mode 100644 ld/testsuite/ld-loongarch-elf/call32_undefweak.d
create mode 100644 ld/testsuite/ld-loongarch-elf/call32_undefweak.s
create mode 100644 ld/testsuite/ld-loongarch-elf/la32r_relocs.s
create mode 100644 ld/testsuite/ld-loongarch-elf/la32r_relocs_nopie.d
create mode 100644 ld/testsuite/ld-loongarch-elf/la32r_relocs_pie.d
create mode 100644 ld/testsuite/ld-loongarch-elf/la32r_tls.s
create mode 100644 ld/testsuite/ld-loongarch-elf/la32r_tls_bin.d
create mode 100644 ld/testsuite/ld-loongarch-elf/la32r_tls_shared.d
create mode 100644 ld/testsuite/ld-loongarch-elf/la32r_tlslib.s
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index faad512f339..4055be33de1 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -219,7 +219,8 @@ loongarch_elf_new_section_hook (bfd *abfd, asection *sec)
#define IS_CALL_RELOC(R_TYPE) \
((R_TYPE) == R_LARCH_B26 \
- ||(R_TYPE) == R_LARCH_CALL36)
+ ||(R_TYPE) == R_LARCH_CALL36 \
+ ||(R_TYPE) == R_LARCH_CALL32)
/* If TLS GD/IE need dynamic relocations, INDX will be the dynamic indx,
and set NEED_RELOC to true used in allocate_dynrelocs and
@@ -876,7 +877,8 @@ bad_static_reloc (struct bfd_link_info *info,
bool bad_extern_access =
(bfd_link_pde (info)
|| r_type == R_LARCH_PCREL20_S2
- || r_type == R_LARCH_PCALA_HI20);
+ || r_type == R_LARCH_PCALA_HI20
+ || r_type == R_LARCH_PCADD_HI20);
if (h)
name = h->root.root.string;
@@ -1044,6 +1046,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_LARCH_GOT_PC_HI20:
case R_LARCH_GOT_HI20:
case R_LARCH_SOP_PUSH_GPREL:
+ case R_LARCH_PCADD_GOT_HI20:
/* For la.global. */
if (h)
h->pointer_equality_needed = 1;
@@ -1069,6 +1072,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_LARCH_TLS_IE_PC_HI20:
case R_LARCH_TLS_IE_HI20:
case R_LARCH_SOP_PUSH_TLS_GOT:
+ case R_LARCH_PCADD_TLS_IE_HI20:
if (bfd_link_pic (info))
/* May fail for lazy-bind. */
info->flags |= DF_STATIC_TLS;
@@ -1095,6 +1099,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_LARCH_TLS_DESC_PC_HI20:
case R_LARCH_TLS_DESC_HI20:
+ case R_LARCH_PCADD_TLS_DESC_HI20:
if (!loongarch_elf_record_tls_and_got_reference (abfd, info, h,
r_symndx,
GOT_TLS_GDESC,
@@ -1124,6 +1129,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
In static PIE undefined weak symbols may be allowed
by rewriting pcaddi to addi.w if addend is in [-2048, 2048). */
case R_LARCH_PCREL20_S2:
+ case R_LARCH_PCADD_HI20:
if (bfd_link_pic (info)
&& (sec->flags & SEC_ALLOC) != 0
&& (sec->flags & SEC_READONLY) != 0
@@ -1170,6 +1176,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_LARCH_B21:
case R_LARCH_B26:
case R_LARCH_CALL36:
+ case R_LARCH_CALL32:
if (h != NULL)
{
h->needs_plt = 1;
@@ -2993,6 +3000,12 @@ perform_relocation (const Elf_Internal_Rela *rel, asection *input_section,
case R_LARCH_TLS_LD_PCREL20_S2:
case R_LARCH_TLS_GD_PCREL20_S2:
case R_LARCH_TLS_DESC_PCREL20_S2:
+ case R_LARCH_PCADD_HI20:
+ case R_LARCH_PCADD_LO12_I:
+ case R_LARCH_PCADD_GOT_HI20:
+ case R_LARCH_PCADD_TLS_IE_HI20:
+ case R_LARCH_PCADD_TLS_DESC_HI20:
+ case R_LARCH_CALL32:
r = loongarch_check_offset (rel, input_section);
if (r != bfd_reloc_ok)
break;
@@ -3249,6 +3262,153 @@ tlsoff (struct bfd_link_info *info, bfd_vma addr)
return addr - elf_hash_table (info)->tls_sec->vma;
}
+typedef struct
+{
+ /* PC value. */
+ bfd_vma address;
+ /* Relocation value with addend. */
+ bfd_vma value;
+} loongarch_pcrel_hi_reloc;
+
+typedef struct loongarch_pcrel_lo_reloc
+{
+ /* PC value of pcaddu12i. */
+ bfd_vma address;
+ /* Internal relocation. */
+ Elf_Internal_Rela *reloc;
+ /* loongarch_elf_relocate_section can only handle an input section at a time,
+ so we can only resolved pcadd_hi20 and pcadd_lo12 in the same section. If
+ these pcrel relocs are not in the same section we should report dangerous
+ relocation errors. */
+ asection *input_section;
+ struct bfd_link_info *info;
+ reloc_howto_type *howto;
+ bfd_byte *contents;
+ /* The next loongarch_pcrel_lo_reloc. */
+ struct loongarch_pcrel_lo_reloc *next;
+} loongarch_pcrel_lo_reloc;
+
+typedef struct
+{
+ /* Hash table for loongarch_pcrel_hi_reloc. */
+ htab_t hi_relocs;
+ /* Linked list for loongarch_pcrel_lo_reloc. */
+ loongarch_pcrel_lo_reloc *lo_relocs;
+} loongarch_pcrel_relocs;
+
+/* Hash function of the pcrel_hi_reloc hash table. */
+static hashval_t
+loongarch_pcrel_reloc_hash (const void *entry)
+{
+ const loongarch_pcrel_hi_reloc *e = entry;
+ return (hashval_t)(e->address >> 2);
+}
+
+/* Comparison function of the pcrel_hi_reloc hash table. */
+static int
+loongarch_pcrel_reloc_eq (const void *entry1, const void *entry2)
+{
+ const loongarch_pcrel_hi_reloc *e1 = entry1, *e2 = entry2;
+ return e1->address == e2->address;
+}
+
+static bool
+loongarch_init_pcrel_relocs (loongarch_pcrel_relocs *p)
+{
+ p->lo_relocs = NULL;
+ p->hi_relocs = htab_create (1024, loongarch_pcrel_reloc_hash,
+ loongarch_pcrel_reloc_eq, free);
+ return p->hi_relocs != NULL;
+}
+
+static void
+loongarch_free_pcrel_reloc (loongarch_pcrel_relocs *p)
+{
+ loongarch_pcrel_lo_reloc *cur = p->lo_relocs;
+
+ while (cur != NULL)
+ {
+ loongarch_pcrel_lo_reloc *next = cur->next;
+ free (cur);
+ cur = next;
+ }
+ htab_delete (p->hi_relocs);
+}
+
+static bool
+loongarch_record_pcrel_hi_reloc (loongarch_pcrel_relocs *p,
+ bfd_vma addr,
+ bfd_vma *value)
+{
+ bfd_vma offset = *value - addr;
+ bfd_vma off_lo = offset & (bfd_vma)0xfff;
+ /* If lo12 immediate > 0x7ff, because sign-extend caused by addi.w/ld.w,
+ hi20 immediate need to add 0x1.
+ See RELOCATE_CALC_PC32_HI20(relocation, pc) */
+ if (off_lo > 0x7ff)
+ offset += 0x1000;
+
+ *value = offset;
+
+ loongarch_pcrel_hi_reloc entry = {addr, offset};
+ loongarch_pcrel_hi_reloc **slot =
+ (loongarch_pcrel_hi_reloc **)htab_find_slot (p->hi_relocs, &entry, INSERT);
+
+ BFD_ASSERT (*slot == NULL);
+ *slot = (loongarch_pcrel_hi_reloc *) bfd_malloc (sizeof (loongarch_pcrel_hi_reloc));
+ if (*slot == NULL)
+ return false;
+ **slot = entry;
+ return true;
+}
+
+static bool
+loongarch_record_pcrel_lo_reloc (loongarch_pcrel_relocs *p,
+ bfd_vma addr,
+ Elf_Internal_Rela *reloc,
+ asection *input_section,
+ struct bfd_link_info *info,
+ reloc_howto_type *howto,
+ bfd_byte *contents)
+{
+ loongarch_pcrel_lo_reloc *entry;
+ entry = (loongarch_pcrel_lo_reloc *) bfd_malloc (sizeof (loongarch_pcrel_lo_reloc));
+ if (entry == NULL)
+ return false;
+ *entry = (loongarch_pcrel_lo_reloc) {addr, reloc, input_section, info,
+ howto, contents, p->lo_relocs};
+ p->lo_relocs = entry;
+ return true;
+}
+
+static bool
+loongarch_resolve_pcrel_lo_relocs (loongarch_pcrel_relocs *p)
+{
+ loongarch_pcrel_lo_reloc *r;
+ for (r = p->lo_relocs; r != NULL; r = r->next)
+ {
+ bfd *input_bfd = r->input_section->owner;
+
+ loongarch_pcrel_hi_reloc search = {r->address, 0};
+ loongarch_pcrel_hi_reloc *entry = htab_find (p->hi_relocs, &search);
+
+ char *string = NULL;
+ if (entry == NULL)
+ string = _("%pcadd_lo12 missing marching %pcadd_*_hi20");
+
+ if (string != NULL)
+ {
+ (*r->info->callbacks->reloc_dangerous)
+ (r->info, string, input_bfd, r->input_section, r->reloc->r_offset);
+ return true;
+ }
+
+ perform_relocation (r->reloc, r->input_section, r->howto, entry->value,
+ input_bfd, r->contents);
+ }
+ return true;
+}
+
static int
loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
bfd *input_bfd, asection *input_section,
@@ -3258,6 +3418,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
{
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
+ loongarch_pcrel_relocs pcrel_relocs;
bool fatal = false;
asection *sreloc = elf_section_data (input_section)->sreloc;
struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
@@ -3269,6 +3430,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
asection *plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt;
asection *got = htab->elf.sgot;
+ if (!loongarch_init_pcrel_relocs (&pcrel_relocs))
+ return false;
+
relend = relocs + input_section->reloc_count;
for (rel = relocs; rel < relend; rel++)
{
@@ -4049,6 +4213,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_LARCH_B21:
case R_LARCH_B26:
case R_LARCH_CALL36:
+ case R_LARCH_CALL32:
unresolved_reloc = false;
bool via_plt =
plt != NULL && h != NULL && h->plt.offset != (bfd_vma) - 1;
@@ -4061,8 +4226,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
if (!via_plt && IS_CALL_RELOC (r_type))
{
/* call36 fn1 => pcaddu18i $ra,0+jirl $ra,$zero,0
- tail36 $t0,fn1 => pcaddi18i $t0,0+jirl $zero,$zero,0 */
- if (R_LARCH_CALL36 == r_type)
+ tail36 $t0,fn1 => pcaddi18i $t0,0+jirl $zero,$zero,0
+ call32 fn1 => pcaddu12i $ra,0+jirl $ra,$zero,0 */
+ if (R_LARCH_CALL36 == r_type
+ || R_LARCH_CALL32 == r_type)
{
uint32_t jirl = bfd_get (32, input_bfd,
contents + rel->r_offset + 4);
@@ -4245,6 +4412,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_LARCH_GOT_PC_HI20:
case R_LARCH_GOT_HI20:
+ case R_LARCH_PCADD_GOT_HI20:
/* Calc got offset. */
{
unresolved_reloc = false;
@@ -4336,6 +4504,13 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
if (r_type == R_LARCH_GOT_PC_HI20)
RELOCATE_CALC_PC32_HI20 (relocation, pc);
+ if (r_type == R_LARCH_PCADD_GOT_HI20)
+ {
+ if (!loongarch_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ &relocation))
+ r = bfd_reloc_overflow;
+ }
+
break;
case R_LARCH_GOT_PC_LO12:
@@ -4408,16 +4583,20 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_LARCH_TLS_LD_PCREL20_S2:
case R_LARCH_TLS_GD_PCREL20_S2:
case R_LARCH_TLS_DESC_PCREL20_S2:
+ case R_LARCH_PCADD_TLS_IE_HI20:
+ case R_LARCH_PCADD_TLS_DESC_HI20:
BFD_ASSERT (rel->r_addend == 0);
unresolved_reloc = false;
if (r_type == R_LARCH_TLS_IE_PC_HI20
- || r_type == R_LARCH_TLS_IE_HI20)
+ || r_type == R_LARCH_TLS_IE_HI20
+ || r_type == R_LARCH_PCADD_TLS_IE_HI20)
is_ie = true;
if (r_type == R_LARCH_TLS_DESC_PC_HI20
|| r_type == R_LARCH_TLS_DESC_HI20
- || r_type == R_LARCH_TLS_DESC_PCREL20_S2)
+ || r_type == R_LARCH_TLS_DESC_PCREL20_S2
+ || r_type == R_LARCH_PCADD_TLS_DESC_HI20)
is_desc = true;
bfd_vma got_off = 0;
@@ -4549,6 +4728,11 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|| r_type == R_LARCH_TLS_GD_PCREL20_S2
|| r_type == R_LARCH_TLS_DESC_PCREL20_S2)
relocation -= pc;
+ else if (r_type == R_LARCH_PCADD_TLS_IE_HI20
+ || r_type == R_LARCH_PCADD_TLS_DESC_HI20)
+ if (!loongarch_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ &relocation))
+ r = bfd_reloc_overflow;
/* else {} ABS relocations. */
break;
@@ -4620,6 +4804,21 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
unresolved_reloc = false;
break;
+ case R_LARCH_PCADD_HI20:
+ relocation += rel->r_addend;
+ if (!loongarch_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ &relocation))
+ r = bfd_reloc_overflow;
+ break;
+
+ case R_LARCH_PCADD_LO12_I:
+ if (loongarch_record_pcrel_lo_reloc (&pcrel_relocs, relocation, rel,
+ input_section, info, howto,
+ contents))
+ continue;
+ r = bfd_reloc_overflow;
+ break;
+
default:
break;
}
@@ -4711,6 +4910,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
fatal = true;
}
+ bool ret = loongarch_resolve_pcrel_lo_relocs (&pcrel_relocs);
+ fatal = !ret;
+ loongarch_free_pcrel_reloc (&pcrel_relocs);
+
return !fatal;
}
diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c
index 0eead492e76..4efb480032f 100644
--- a/bfd/elfxx-loongarch.c
+++ b/bfd/elfxx-loongarch.c
@@ -2167,6 +2167,16 @@ reloc_bits_sanity (bfd *abfd, reloc_howto_type *howto, bfd_vma *fix_val,
so the high part need to add 0x8000. */
val = (((val + 0x8000) >> 16) << 5) | (((val & 0xffff) << 10) << 32);
break;
+ case R_LARCH_CALL32:
+ /* call32 = pcaddu12i+jirl, the jirl immediate field has 16 bits,
+ and the sign extension at run time does not affect the result.
+ But at link time we need to sign-extend the lower 12 bits of
+ the offset to write the 16-bit immediate field of jirl.
+ Since there is "val = val >> howto->rightshift" in front, only
+ the lower 10 bits need to be sign-extended. */
+ bfd_vma off_lo = val & 0x3ff;
+ val = ((val >> 10) << 5) | (((off_lo & 0xffff) << 10) << 32);
+ break;
default:
val <<= howto->bitpos;
break;
diff --git a/ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.d b/ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.d
new file mode 100644
index 00000000000..196817ed84b
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.d
@@ -0,0 +1,6 @@
+#name: la32r PC-relative relocation making shared
+#source: bad_pcadd_hi20_global.s
+#skip: loongarch64-*-*
+#target: [check_shared_lib_support]
+#ld: -shared --defsym global_a=0x10 --defsym global_b=0x20
+#error: .*: relocation R_LARCH_PCADD_HI20 against `global_b` can not be used when making a shared object; recompile with -fPIC and check the symbol visibility
diff --git a/ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.s b/ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.s
new file mode 100644
index 00000000000..3993bcd407e
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/bad_pcadd_hi20_global.s
@@ -0,0 +1,12 @@
+ .hidden global_a
+ .text
+ .align 2
+main:
+ # Symbols defined .hidden are bound local and
+ # the linker should differenciate them.
+.L1:
+ pcaddu12i $t0, %pcadd_hi20(global_a)
+ addi.w $t0, $t0, %pcadd_lo12(.L1)
+.L2:
+ pcaddu12i $t0, %pcadd_hi20(global_b)
+ addi.w $t0, $t0, %pcadd_lo12(.L2)
diff --git a/ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.d b/ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.d
new file mode 100644
index 00000000000..a479491013b
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.d
@@ -0,0 +1,4 @@
+#name: %pcadd_lo12 match
+#source: bad_pcadd_lo12.s
+#ld: -e0
+#error: .*dangerous relocation: %pcadd_lo12 missing marching %pcadd_\*_hi20
diff --git a/ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.s b/ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.s
new file mode 100644
index 00000000000..faa2b631aa7
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/bad_pcadd_lo12.s
@@ -0,0 +1,4 @@
+ .text
+ .align 2
+.L1:
+ addi.w $t0, $t0, %pcadd_lo12(.L1)
diff --git a/ld/testsuite/ld-loongarch-elf/call32_undefweak.d b/ld/testsuite/ld-loongarch-elf/call32_undefweak.d
new file mode 100644
index 00000000000..7d37107221f
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/call32_undefweak.d
@@ -0,0 +1,6 @@
+#...
+[0-9a-f]+ <main>:
+ [0-9a-f]+: ........ pcaddu12i $a0, .*
+ [0-9a-f]+: ........ jirl $ra, $a0, .*
+ [0-9a-f]+: 1c000004 pcaddu12i $a0, 0
+ [0-9a-f]+: 4c000001 jirl $ra, $zero, 0
diff --git a/ld/testsuite/ld-loongarch-elf/call32_undefweak.s b/ld/testsuite/ld-loongarch-elf/call32_undefweak.s
new file mode 100644
index 00000000000..067b024abb7
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/call32_undefweak.s
@@ -0,0 +1,15 @@
+ .text
+ .globl main
+ .type main, @function
+main:
+ pcaddu12i $a0,%call32(fn1)
+ jirl $ra,$a0,0
+ # Calls to undefined weak symbols that do not
+ # require a plt entry are converted to calls to 0.
+ pcaddu12i $a0,%call32(fn2)
+ jirl $ra,$a0,0
+
+ .weak fn1
+
+ .weak fn2
+ .hidden fn2
diff --git a/ld/testsuite/ld-loongarch-elf/la32r_relocs.s b/ld/testsuite/ld-loongarch-elf/la32r_relocs.s
new file mode 100644
index 00000000000..7ad975cade9
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/la32r_relocs.s
@@ -0,0 +1,44 @@
+ .text
+ .globl f1
+ .type f1, @function
+
+f1:
+ ret
+
+ .global _start
+_start:
+# call32
+ pcaddu12i $t0,%call32(f1)
+ jirl $ra,$t0,0
+
+# pcrel
+L1:
+ pcaddu12i $t0,%pcadd_hi20(s)
+ addi.w $a0,$t0,%pcadd_lo12(L1)
+
+# got
+L2:
+ pcaddu12i $t0,%pcadd_got_hi20(s)
+ ld.w $a0,$t0,%pcadd_lo12(L2)
+
+# tls ie
+L3:
+ pcaddu12i $a0,%pcadd_ie_hi20(t)
+ ld.w $a0,$a0,%pcadd_lo12(L3)
+
+# tls desc
+L4:
+ pcaddu12i $a0,%pcadd_desc_hi20(t)
+ addi.w $a0,$a0,%pcadd_lo12(L4)
+ ld.w $ra,$a0,%desc_ld(L4)
+ jirl $ra,$ra,%desc_call(L4)
+
+ .global s
+s:
+ nop
+
+ .section .tata,"awT",@progbits
+ .align 2
+ .globl t
+t:
+ .word 0x123
diff --git a/ld/testsuite/ld-loongarch-elf/la32r_relocs_nopie.d b/ld/testsuite/ld-loongarch-elf/la32r_relocs_nopie.d
new file mode 100644
index 00000000000..807f9e498ee
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/la32r_relocs_nopie.d
@@ -0,0 +1,36 @@
+#source: la32r_relocs.s
+#ld: -e0 --hash-style=both
+#objdump: -d
+
+.*: file format .*
+
+
+Disassembly of section .text:
+
+[0-9a-f]+ <f1>:
+ [0-9a-f]+: 4c000020 ret
+
+[0-9a-f]+ <_start>:
+ [0-9a-f]+: 1dffffec pcaddu12i \$t0, -1
+ [0-9a-f]+: 4c0ffd81 jirl \$ra, \$t0, 4092
+
+[0-9a-f]+ <L1>:
+ [0-9a-f]+: 1c00000c pcaddu12i \$t0, 0
+ [0-9a-f]+: 0280a184 addi.w \$a0, \$t0, 40
+
+[0-9a-f]+ <L2>:
+ [0-9a-f]+: 1c00020c pcaddu12i \$t0, 16
+ [0-9a-f]+: 2880e184 ld.w \$a0, \$t0, 56
+
+[0-9a-f]+ <L3>:
+ [0-9a-f]+: 1c000204 pcaddu12i \$a0, 16
+ [0-9a-f]+: 2880b084 ld.w \$a0, \$a0, 44
+
+[0-9a-f]+ <L4>:
+ [0-9a-f]+: 1c000204 pcaddu12i \$a0, 16
+ [0-9a-f]+: 02807084 addi.w \$a0, \$a0, 28
+ [0-9a-f]+: 28800081 ld.w \$ra, \$a0, 0
+ [0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
+
+[0-9a-f]+ <s>:
+ [0-9a-f]+: 03400000 nop
diff --git a/ld/testsuite/ld-loongarch-elf/la32r_relocs_pie.d b/ld/testsuite/ld-loongarch-elf/la32r_relocs_pie.d
new file mode 100644
index 00000000000..c7ae214b9f7
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/la32r_relocs_pie.d
@@ -0,0 +1,36 @@
+#source: la32r_relocs.s
+#ld: -e0 -pie --hash-style=both
+#objdump: -d
+
+.*: file format .*
+
+
+Disassembly of section .text:
+
+[0-9a-f]+ <f1>:
+ [0-9a-f]+: 4c000020 ret
+
+[0-9a-f]+ <_start>:
+ [0-9a-f]+: 1dffffec pcaddu12i \$t0, -1
+ [0-9a-f]+: 4c0ffd81 jirl \$ra, \$t0, 4092
+
+[0-9a-f]+ <L1>:
+ [0-9a-f]+: 1c00000c pcaddu12i \$t0, 0
+ [0-9a-f]+: 0280a184 addi.w \$a0, \$t0, 40
+
+[0-9a-f]+ <L2>:
+ [0-9a-f]+: 1c00020c pcaddu12i \$t0, 16
+ [0-9a-f]+: 28832184 ld.w \$a0, \$t0, 200
+
+[0-9a-f]+ <L3>:
+ [0-9a-f]+: 1c000204 pcaddu12i \$a0, 16
+ [0-9a-f]+: 2882f084 ld.w \$a0, \$a0, 188
+
+[0-9a-f]+ <L4>:
+ [0-9a-f]+: 1c000204 pcaddu12i \$a0, 16
+ [0-9a-f]+: 0282b084 addi.w \$a0, \$a0, 172
+ [0-9a-f]+: 28800081 ld.w \$ra, \$a0, 0
+ [0-9a-f]+: 4c000021 jirl \$ra, \$ra, 0
+
+[0-9a-f]+ <s>:
+ [0-9a-f]+: 03400000 nop
diff --git a/ld/testsuite/ld-loongarch-elf/la32r_tls.s b/ld/testsuite/ld-loongarch-elf/la32r_tls.s
new file mode 100644
index 00000000000..360f59dd180
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/la32r_tls.s
@@ -0,0 +1,34 @@
+# DESC and IE require a total of 3 GOT slots to access the same symbol.
+# DESC occupies the first two and IE occupies the last one.
+ .section .tata,"awT",@progbits
+ .align 2
+ .globl gl1
+gl1:
+ .word 0x123
+lo1:
+ .word 0x456
+
+ .text
+ .globl _start
+_start:
+# tls ie
+.L1:
+ pcaddu12i $a0,%pcadd_ie_hi20(gl1)
+ ld.w $a0,$a0,%pcadd_lo12(.L1)
+ add.w $a0,$a0,$tp
+.L2:
+ pcaddu12i $a0,%pcadd_ie_hi20(lo1)
+ ld.w $a0,$a0,%pcadd_lo12(.L2)
+ add.w $a0,$a0,$tp
+
+# tls desc
+.L3:
+ pcaddu12i $a0,%pcadd_desc_hi20(gl1)
+ addi.w $a0,$a0,%pcadd_lo12(.L3)
+ ld.w $ra,$a0,%desc_ld(.L3)
+ jirl $ra,$ra,%desc_call(.L3)
+.L4:
+ pcaddu12i $a0,%pcadd_desc_hi20(lo1)
+ addi.w $a0,$a0,%pcadd_lo12(.L4)
+ ld.w $ra,$a0,%desc_ld(.L4)
+ jirl $ra,$ra,%desc_call(.L4)
diff --git a/ld/testsuite/ld-loongarch-elf/la32r_tls_bin.d b/ld/testsuite/ld-loongarch-elf/la32r_tls_bin.d
new file mode 100644
index 00000000000..4adadd2ce0e
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/la32r_tls_bin.d
@@ -0,0 +1,17 @@
+#name: la32r tls relocs binary
+#source: la32r_tls.s
+#ld: -no-pie tmpdir/la32r-tlslib.so
+#objdump: -dRj.got
+#skip: loongarch64-*-*
+
+.*: file format .*
+
+
+Disassembly of section .got:
+
+[0-9a-f]+ <_GLOBAL_OFFSET_TABLE_>:
+ [0-9a-f]+: .* ................
+ [0-9a-f]+: R_LARCH_TLS_DESC32 \*ABS\*\+0x4
+ ...
+ [0-9a-f]+: R_LARCH_TLS_DESC32 gl1
+ [0-9a-f]+: R_LARCH_TLS_TPREL32 gl1
diff --git a/ld/testsuite/ld-loongarch-elf/la32r_tls_shared.d b/ld/testsuite/ld-loongarch-elf/la32r_tls_shared.d
new file mode 100644
index 00000000000..a694cf6d3f3
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/la32r_tls_shared.d
@@ -0,0 +1,18 @@
+#name: la32r tls relocs shared
+#source: la32r_tls.s
+#ld: -shared tmpdir/la32r-tlslib.so
+#objdump: -dRj.got
+#skip: loongarch64-*-*
+
+.*: file format .*
+
+
+Disassembly of section .got:
+
+[0-9a-f]+ <.got>:
+ [0-9a-f]+: [0-9a-f]+ .* 0x[0-9a-f]+
+ \.\.\.
+ [0-9a-f]+: R_LARCH_TLS_DESC32 \*ABS\*\+0x4
+ [0-9a-f]+: R_LARCH_TLS_TPREL32 \*ABS\*\+0x4
+ [0-9a-f]+: R_LARCH_TLS_DESC32 gl1
+ [0-9a-f]+: R_LARCH_TLS_TPREL32 gl1
diff --git a/ld/testsuite/ld-loongarch-elf/la32r_tlslib.s b/ld/testsuite/ld-loongarch-elf/la32r_tlslib.s
new file mode 100644
index 00000000000..3d0fa96b9c1
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/la32r_tlslib.s
@@ -0,0 +1,5 @@
+ .section .tata,"awT",@progbits
+ .align 2
+ .globl gl1
+gl1:
+ .word 0x123
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 0295be81562..c55dbdb9ea2 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -57,6 +57,31 @@ if [istarget "loongarch32-*-*"] {
run_dump_test "disas-jirl-32"
}
+if [istarget "loongarch32-*-*"] {
+ run_dump_test "la32r_relocs_nopie"
+ run_dump_test "bad_pcadd_lo12"
+ if [check_pie_support] {
+ run_dump_test "la32r_relocs_pie"
+ }
+ if [check_shared_lib_support] {
+ run_ld_link_tests \
+ [list \
+ [list \
+ "Build shared lib for la32r TLS runtime" \
+ "-shared" "" "" \
+ {la32r_tlslib.s} \
+ {} \
+ "la32r_tlslib.so" \
+ ] \
+ ]
+
+ run_dump_test "bad_pcadd_hi20_global"
+ run_dump_test "la32r_tls_shared"
+ run_dump_test "la32r_tls_bin"
+
+ }
+}
+
if [istarget "loongarch64-*-*"] {
if [check_shared_lib_support] {
run_ld_link_tests \
@@ -237,3 +262,14 @@ if [istarget "loongarch64-*-*"] {
}
+if [istarget "loongarch32-*-*"] {
+ run_cc_link_tests [list \
+ [list \
+ "call32 undefweak symbol" \
+ "-no-pie" "" \
+ {call_undefweak.s} \
+ {{objdump {-d} call_undefweak.d}} \
+ "call32_undefweak" \
+ ] \
+ ]
+}
--
2.45.2
More information about the Binutils
mailing list