[PATCH v1 1/2] LoongArch: Add gas support for LA32 relocations
Lulu Cai
cailulu@loongson.cn
Sun Apr 27 09:22:23 GMT 2025
* Added gas support for 6 new relocations for LA32.
* Modified DWARF alignment to accommodate LA32.
* Added call32 pseudo instruction for LA32 medium code model function call.
---
bfd/bfd-in2.h | 6 +
bfd/elfxx-loongarch.c | 108 ++++++++++++++++++
bfd/libbfd.h | 6 +
bfd/reloc.c | 13 +++
gas/config/tc-loongarch.c | 22 +++-
gas/config/tc-loongarch.h | 3 +-
.../gas/loongarch/la32r_medium_call.d | 15 +++
.../gas/loongarch/la32r_medium_call.s | 5 +
gas/testsuite/gas/loongarch/la32r_relocs.d | 40 +++++++
gas/testsuite/gas/loongarch/la32r_relocs.s | 34 ++++++
include/elf/loongarch.h | 30 +++++
opcodes/loongarch-opc.c | 6 +
12 files changed, 284 insertions(+), 4 deletions(-)
create mode 100644 gas/testsuite/gas/loongarch/la32r_medium_call.d
create mode 100644 gas/testsuite/gas/loongarch/la32r_medium_call.s
create mode 100644 gas/testsuite/gas/loongarch/la32r_relocs.d
create mode 100644 gas/testsuite/gas/loongarch/la32r_relocs.s
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index ec60f23f61b..ae09ce52544 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -7435,6 +7435,12 @@ enum bfd_reloc_code_real
BFD_RELOC_LARCH_TLS_LD_PCREL20_S2,
BFD_RELOC_LARCH_TLS_GD_PCREL20_S2,
BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2,
+ BFD_RELOC_LARCH_CALL32,
+ BFD_RELOC_LARCH_PCADD_HI20,
+ BFD_RELOC_LARCH_PCADD_GOT_HI20,
+ BFD_RELOC_LARCH_PCADD_TLS_IE_HI20,
+ BFD_RELOC_LARCH_PCADD_TLS_DESC_HI20,
+ BFD_RELOC_LARCH_PCADD_LO12_I,
BFD_RELOC_UNUSED
};
typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c
index 94980229501..0eead492e76 100644
--- a/bfd/elfxx-loongarch.c
+++ b/bfd/elfxx-loongarch.c
@@ -1882,6 +1882,114 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2, /* bfd_reloc_code_real_type. */
reloc_sign_bits, /* adjust_reloc_bits. */
"desc_pcrel_20"), /* larch_reloc_type_name. */
+
+ /* For LA32 medium call. */
+ LOONGARCH_HOWTO (R_LARCH_CALL32, /* type (127). */
+ 2, /* rightshift. */
+ 8, /* size. */
+ 36, /* bitsize. */
+ true, /* pc_relative. */
+ 0, /* bitpos. */
+ complain_overflow_signed, /* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_LARCH_CALL32", /* name. */
+ false, /* partial_inplace. */
+ 0, /* src_mask. */
+ 0x03fffc0001ffffe0, /* dst_mask. */
+ false, /* pcrel_offset. */
+ BFD_RELOC_LARCH_CALL32, /* bfd_reloc_code_real_type. */
+ reloc_sign_bits, /* adjust_reloc_bits. */
+ "call32"), /* larch_reloc_type_name. */
+
+ /* For LA32 la.pcrel. */
+ LOONGARCH_HOWTO (R_LARCH_PCADD_HI20, /* type (128). */
+ 12, /* rightshift. */
+ 4, /* size. */
+ 20, /* bitsize. */
+ true, /* pc_relative. */
+ 5, /* bitpos. */
+ complain_overflow_signed, /* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_LARCH_PCADD_HI20", /* name. */
+ false, /* partial_inplace. */
+ 0, /* src_mask */
+ 0x1ffffe0, /* dst_mask */
+ false, /* pcrel_offset */
+ BFD_RELOC_LARCH_PCADD_HI20, /* bfd_reloc_code_real_type */
+ reloc_bits, /* adjust_reloc_bits */
+ "pcadd_hi20"), /* larch_reloc_type_name */
+
+ /* For LA32 la.got. */
+ LOONGARCH_HOWTO (R_LARCH_PCADD_GOT_HI20, /* type (129). */
+ 12, /* rightshift. */
+ 4, /* size. */
+ 20, /* bitsize. */
+ true, /* pc_relative. */
+ 5, /* bitpos. */
+ complain_overflow_signed, /* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_LARCH_PCADD_GOT_HI20", /* name. */
+ false, /* partial_inplace. */
+ 0, /* src_mask */
+ 0x1ffffe0, /* dst_mask */
+ false, /* pcrel_offset */
+ BFD_RELOC_LARCH_PCADD_GOT_HI20, /* bfd_reloc_code_real_type */
+ reloc_bits, /* adjust_reloc_bits */
+ "pcadd_got_hi20"), /* larch_reloc_type_name */
+
+ /* For LA32 la.tls.ie. */
+ LOONGARCH_HOWTO (R_LARCH_PCADD_TLS_IE_HI20, /* type (130). */
+ 12, /* rightshift. */
+ 4, /* size. */
+ 20, /* bitsize. */
+ true, /* pc_relative. */
+ 5, /* bitpos. */
+ complain_overflow_signed, /* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_LARCH_PCADD_TLS_IE_HI20", /* name. */
+ false, /* partial_inplace. */
+ 0, /* src_mask */
+ 0x1ffffe0, /* dst_mask */
+ false, /* pcrel_offset */
+ BFD_RELOC_LARCH_PCADD_TLS_IE_HI20, /* bfd_reloc_code_real_type */
+ reloc_bits, /* adjust_reloc_bits */
+ "pcadd_ie_hi20"), /* larch_reloc_type_name */
+
+ /* For LA32 la.tls.desc. */
+ LOONGARCH_HOWTO (R_LARCH_PCADD_TLS_DESC_HI20, /* type (131). */
+ 12, /* rightshift. */
+ 4, /* size. */
+ 20, /* bitsize. */
+ true, /* pc_relative. */
+ 5, /* bitpos. */
+ complain_overflow_signed, /* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_LARCH_PCADD_TLS_DESC_HI20", /* name. */
+ false, /* partial_inplace. */
+ 0, /* src_mask. */
+ 0x1ffffe0, /* dst_mask. */
+ false, /* pcrel_offset. */
+ BFD_RELOC_LARCH_PCADD_TLS_DESC_HI20, /* bfd_reloc_code_real_type. */
+ reloc_bits, /* adjust_reloc_bits. */
+ "pcadd_desc_hi20"), /* larch_reloc_type_name. */
+
+ /* For LA32 Low 12 bits of a 32-bit PC-relative. */
+ LOONGARCH_HOWTO (R_LARCH_PCADD_LO12_I, /* type (132). */
+ 0, /* rightshift. */
+ 4, /* size. */
+ 12, /* bitsize. */
+ true, /* pc_relative. */
+ 10, /* bitpos. */
+ complain_overflow_signed, /* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_LARCH_PCADD_LO12_I", /* name. */
+ false, /* partial_inplace. */
+ 0, /* src_mask */
+ 0x3ffc00, /* dst_mask */
+ false, /* pcrel_offset */
+ BFD_RELOC_LARCH_PCADD_LO12_I, /* bfd_reloc_code_real_type */
+ reloc_bits, /* adjust_reloc_bits */
+ "pcadd_lo12"), /* larch_reloc_type_name */
};
reloc_howto_type *
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index d367fea33d3..24c8de0bdbc 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -3620,6 +3620,12 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_LARCH_TLS_LD_PCREL20_S2",
"BFD_RELOC_LARCH_TLS_GD_PCREL20_S2",
"BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2",
+ "BFD_RELOC_LARCH_CALL32",
+ "BFD_RELOC_LARCH_PCADD_HI20",
+ "BFD_RELOC_LARCH_PCADD_GOT_HI20",
+ "BFD_RELOC_LARCH_PCADD_TLS_IE_HI20",
+ "BFD_RELOC_LARCH_PCADD_TLS_DESC_HI20",
+ "BFD_RELOC_LARCH_PCADD_LO12_I",
"@@overflow: BFD_RELOC_UNUSED@@",
};
#endif
diff --git a/bfd/reloc.c b/bfd/reloc.c
index d3ddafb7305..8040df56039 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -8257,6 +8257,19 @@ ENUMX
ENUMX
BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2
+ENUMX
+ BFD_RELOC_LARCH_CALL32
+ENUMX
+ BFD_RELOC_LARCH_PCADD_HI20
+ENUMX
+ BFD_RELOC_LARCH_PCADD_GOT_HI20
+ENUMX
+ BFD_RELOC_LARCH_PCADD_TLS_IE_HI20
+ENUMX
+ BFD_RELOC_LARCH_PCADD_TLS_DESC_HI20
+ENUMX
+ BFD_RELOC_LARCH_PCADD_LO12_I
+
ENUMDOC
LARCH relocations.
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index 78411441634..a66e3f5371f 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -118,6 +118,9 @@ static const char default_arch[] = DEFAULT_ARCH;
static bool call36 = 0;
+/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */
+int loongarch_cie_data_alignment;
+
/* The lowest 4-bit is the bytes of instructions. */
#define RELAX_BRANCH_16 0xc0000014
#define RELAX_BRANCH_21 0xc0000024
@@ -532,6 +535,8 @@ md_begin ()
align_hash = htab_create (10, align_sec_sym_hash, align_sec_sym_eq, free);
+ loongarch_cie_data_alignment = LARCH_opts.ase_lp64 ? (-8) : (-4);
+
/* FIXME: expressionS use 'offsetT' as constant,
* we want this is 64-bit type. */
assert (8 <= sizeof (offsetT));
@@ -879,7 +884,7 @@ loongarch_args_parser_can_match_arg_helper (char esc_ch1, char esc_ch2,
esc_ch1, esc_ch2, bit_field, arg);
if (ip->reloc_info[0].type >= BFD_RELOC_LARCH_B16
- && ip->reloc_info[0].type <= BFD_RELOC_LARCH_TLS_DESC_PCREL20_S2)
+ && ip->reloc_info[0].type <= BFD_RELOC_LARCH_PCADD_LO12_I)
{
/* As we compact stack-relocs, it is no need for pop operation.
But break out until here in order to check the imm field.
@@ -1184,8 +1189,10 @@ move_insn (struct loongarch_cl_insn *insn, fragS *frag, long where)
static void
append_fixed_insn (struct loongarch_cl_insn *insn)
{
- /* Ensure the jirl is emitted to the same frag as the pcaddu18i. */
- if (BFD_RELOC_LARCH_CALL36 == insn->reloc_info[0].type)
+ /* Ensure the jirl is emitted to the same frag as the
+ pcaddu18i/pcaddu12i. */
+ if (BFD_RELOC_LARCH_CALL36 == insn->reloc_info[0].type
+ || BFD_RELOC_LARCH_CALL32 == insn->reloc_info[0].type)
frag_grow (8);
char *f = frag_more (insn->insn_length);
@@ -1580,6 +1587,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
case BFD_RELOC_LARCH_TLS_LE_ADD_R:
case BFD_RELOC_LARCH_TLS_LE_HI20_R:
case BFD_RELOC_LARCH_TLS_LE_LO12_R:
+ case BFD_RELOC_LARCH_PCADD_TLS_IE_HI20:
+ case BFD_RELOC_LARCH_PCADD_TLS_DESC_HI20:
/* Add tls lo (got_lo reloc type). */
if (fixP->fx_addsy == NULL)
as_bad_where (fixP->fx_file, fixP->fx_line,
@@ -1840,6 +1849,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
break;
}
+ /* TODO: Record and evaluate the pcrel_hi relocation with
+ local symbol. */
+ case BFD_RELOC_LARCH_PCADD_HI20:
+ case BFD_RELOC_LARCH_PCADD_GOT_HI20:
+ case BFD_RELOC_LARCH_PCADD_LO12_I:
+ break;
+
default:
break;
}
diff --git a/gas/config/tc-loongarch.h b/gas/config/tc-loongarch.h
index ebed8e0c049..3fdc5c8e67f 100644
--- a/gas/config/tc-loongarch.h
+++ b/gas/config/tc-loongarch.h
@@ -117,7 +117,8 @@ extern int loongarch_force_relocation (struct fix *);
FDE Code Alignment Factor (DWARF2_LINE_MIN_INSN_LENGTH) should be 1
because DW_CFA_advance_loc need to be relocated in bytes
when linker relaxation. */
-#define DWARF2_CIE_DATA_ALIGNMENT (-8)
+extern int loongarch_cie_data_alignment;
+#define DWARF2_CIE_DATA_ALIGNMENT loongarch_cie_data_alignment
#define DWARF2_DEFAULT_RETURN_COLUMN 1 /* FDE Return Address Register. */
#define tc_cfi_frame_initial_instructions \
diff --git a/gas/testsuite/gas/loongarch/la32r_medium_call.d b/gas/testsuite/gas/loongarch/la32r_medium_call.d
new file mode 100644
index 00000000000..24992e65ca5
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/la32r_medium_call.d
@@ -0,0 +1,15 @@
+#objdump: -dr
+#skip: loongarch64-*-*
+
+.*: file format .*
+
+
+Disassembly of section .text:
+
+00000000 <.L1>:
+ 0: 1c000001 pcaddu12i \$ra, 0
+ 0: R_LARCH_CALL32 .L1
+ 4: 4c000021 jirl \$ra, \$ra, 0
+ 8: 1c000001 pcaddu12i \$ra, 0
+ 8: R_LARCH_CALL32 .L1
+ c: 4c000021 jirl \$ra, \$ra, 0
diff --git a/gas/testsuite/gas/loongarch/la32r_medium_call.s b/gas/testsuite/gas/loongarch/la32r_medium_call.s
new file mode 100644
index 00000000000..f07bf2a3f9c
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/la32r_medium_call.s
@@ -0,0 +1,5 @@
+.L1:
+ # call .L1, r1(ra) temp register, r1(ra) return register.
+ call32 .L1
+ pcaddu12i $ra, %call32(.L1)
+ jirl $ra, $ra, 0
diff --git a/gas/testsuite/gas/loongarch/la32r_relocs.d b/gas/testsuite/gas/loongarch/la32r_relocs.d
new file mode 100644
index 00000000000..487ea4410fe
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/la32r_relocs.d
@@ -0,0 +1,40 @@
+#as:
+#objdump: -dr
+
+.*: file format .*
+
+
+Disassembly of section \.text:
+
+0+0 <_start>:
+ 0: 1c00000c pcaddu12i \$t0, 0
+ 0: R_LARCH_CALL32 s
+ 4: 4c000181 jirl \$ra, \$t0, 0
+
+0+8 <\.L1>:
+ 8: 1c00000c pcaddu12i \$t0, 0
+ 8: R_LARCH_PCADD_HI20 s
+ c: 02800184 addi.w \$a0, \$t0, 0
+ c: R_LARCH_PCADD_LO12_I \.L1
+
+0+10 <\.L2>:
+ 10: 1c00000c pcaddu12i \$t0, 0
+ 10: R_LARCH_PCADD_GOT_HI20 s
+ 14: 28800184 ld.w \$a0, \$t0, 0
+ 14: R_LARCH_PCADD_LO12_I \.L2
+
+0+18 <\.L3>:
+ 18: 1c000004 pcaddu12i \$a0, 0
+ 18: R_LARCH_PCADD_TLS_IE_HI20 t
+ 1c: 28800084 ld.w \$a0, \$a0, 0
+ 1c: R_LARCH_PCADD_LO12_I \.L3
+
+0+20 <\.L4>:
+ 20: 1c000004 pcaddu12i \$a0, 0
+ 20: R_LARCH_PCADD_TLS_DESC_HI20 t
+ 24: 02800084 addi.w \$a0, \$a0, 0
+ 24: R_LARCH_PCADD_LO12_I \.L4
+ 28: 28800081 ld.w \$ra, \$a0, 0
+ 28: R_LARCH_TLS_DESC_LD \.L4
+ 2c: 4c000021 jirl \$ra, \$ra, 0
+ 2c: R_LARCH_TLS_DESC_CALL \.L4
diff --git a/gas/testsuite/gas/loongarch/la32r_relocs.s b/gas/testsuite/gas/loongarch/la32r_relocs.s
new file mode 100644
index 00000000000..5f3a9b500b3
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/la32r_relocs.s
@@ -0,0 +1,34 @@
+ .global _start
+_start:
+ .global s
+# call32
+ pcaddu12i $t0,%call32(s)
+ 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)
+
+ .section .tata,"awT",@progbits
+ .align 2
+ .global t
+t:
+ .word 0x123
diff --git a/include/elf/loongarch.h b/include/elf/loongarch.h
index ca031a18dad..1d5c63caf8d 100644
--- a/include/elf/loongarch.h
+++ b/include/elf/loongarch.h
@@ -289,6 +289,36 @@ RELOC_NUMBER (R_LARCH_TLS_LD_PCREL20_S2, 124)
RELOC_NUMBER (R_LARCH_TLS_GD_PCREL20_S2, 125)
RELOC_NUMBER (R_LARCH_TLS_DESC_PCREL20_S2, 126)
+/* LA32 medium call
+ pcaddu12i
+ %call32(sym). */
+RELOC_NUMBER (R_LARCH_CALL32, 127)
+
+/* LA32 PCREL
+ pcaddu12i
+ %pcadd_hi20(sym). */
+RELOC_NUMBER (R_LARCH_PCADD_HI20, 128)
+
+/* LA32 GOT
+ pcaddu12i
+ %pcadd_got_hi20(sym). */
+RELOC_NUMBER (R_LARCH_PCADD_GOT_HI20, 129)
+
+/* LA32 TLS IE
+ pcaddu12i
+ %pcadd_ie_hi20(sym). */
+RELOC_NUMBER (R_LARCH_PCADD_TLS_IE_HI20, 130)
+
+/* LA32 TLS DESC
+ pcaddu12i
+ %pcadd_desc_hi20(sym). */
+RELOC_NUMBER (R_LARCH_PCADD_TLS_DESC_HI20, 131)
+
+/* LA32 PCREL
+ addi.w/ld.[bhw]
+ %pcadd_lo12(sym). */
+RELOC_NUMBER (R_LARCH_PCADD_LO12_I, 132)
+
END_RELOC_NUMBERS (R_LARCH_count)
/* Processor specific flags for the ELF header e_flags field. */
diff --git a/opcodes/loongarch-opc.c b/opcodes/loongarch-opc.c
index fa53021cfae..360ebfeb61a 100644
--- a/opcodes/loongarch-opc.c
+++ b/opcodes/loongarch-opc.c
@@ -345,6 +345,11 @@ const char *const loongarch_f_cfi_name_alias[32] =
"jirl $zero,%1,0;", \
0, 0
+#define INSN_LA_CALL32 \
+ "pcaddu12i $ra,%%call32(%1);" \
+ "jirl $ra,$ra,0;", \
+ 0, 0
+
/* For TLS_DESC32 pcrel. */
#define INSN_LA_TLS_DESC32 \
"pcalau12i $r4,%%desc_pc_hi20(%2);" \
@@ -442,6 +447,7 @@ static struct loongarch_opcode loongarch_macro_opcodes[] =
{ 0, 0, "la.tls.gd", "r,r,l", INSN_LA_TLS_GD64_LARGE_PCREL, 0 },
{ 0, 0, "call36", "la", INSN_LA_CALL, 0 },
{ 0, 0, "tail36", "r,la", INSN_LA_TAIL, 0 },
+ { 0, 0, "call32", "la", INSN_LA_CALL32, 0 },
{ 0, 0, "pcaddi", "r,la", "pcaddi %1, %%pcrel_20(%2)", &LARCH_opts.ase_ilp32, 0, 0 },
{ 0, 0, "la.tls.desc", "r,l", INSN_LA_TLS_DESC32_ABS, 0 },
{ 0, 0, "la.tls.desc", "r,l", INSN_LA_TLS_DESC32, 0 },
--
2.45.2
More information about the Binutils
mailing list