[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