[PATCH 1/3] LoongArch: Emit relocations for .long 0x2eef - symbol

mengqinggang mengqinggang@loongson.cn
Thu Aug 13 17:07:34 GMT 2026


Emit relocations for expressions like .long 0x2eef - symbol.
Since fx_addsy is set to NULL in fixup_segment, we cannot generate
relocations in md_apply_fix.
Set fx_addsy to abs_section_sym in md_apply_fix.
---
 gas/config/tc-loongarch.c                   | 139 ++++++++++++--------
 gas/testsuite/gas/loongarch/bfd_reloc_8.s   |  16 ---
 gas/testsuite/gas/loongarch/loongarch.exp   |   2 +-
 gas/testsuite/gas/loongarch/reloc-abs.d     |  23 ++++
 gas/testsuite/gas/loongarch/reloc-abs.s     |  12 ++
 gas/testsuite/gas/loongarch/reloc-add-sub.d |  22 ++++
 gas/testsuite/gas/loongarch/reloc-add-sub.s |  16 +++
 7 files changed, 155 insertions(+), 75 deletions(-)
 delete mode 100644 gas/testsuite/gas/loongarch/bfd_reloc_8.s
 create mode 100644 gas/testsuite/gas/loongarch/reloc-abs.d
 create mode 100644 gas/testsuite/gas/loongarch/reloc-abs.s
 create mode 100644 gas/testsuite/gas/loongarch/reloc-add-sub.d
 create mode 100644 gas/testsuite/gas/loongarch/reloc-add-sub.s

diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index bd7d8dabb7a..218c7004b8d 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -1758,39 +1758,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
       fix_reloc_insn (fixP, (bfd_vma)stack_top, buf);
       break;
 
-    /* LARCH only has R_LARCH_64/32, not has R_LARCH_24/16/8.
-       For BFD_RELOC_64/32, if fx_addsy and fx_subsy not null, wer need
-       generate BFD_RELOC_LARCH_ADD64/32 and BFD_RELOC_LARCH_SUB64/32 here.
-       Then will parse howto table bfd_reloc_code_real_type to generate
-       R_LARCH_ADD64/32 and R_LARCH_SUB64/32 reloc at tc_gen_reloc function.
-       If only fx_addsy not null, skip here directly, then generate
-       R_LARCH_64/32.
-
-       For BFD_RELOC_24/16/8, if fx_addsy and fx_subsy not null, wer need
-       generate BFD_RELOC_LARCH_ADD24/16/8 and BFD_RELOC_LARCH_SUB24/16/8 here.
-       Then will parse howto table bfd_reloc_code_real_type to generate
-       R_LARCH_ADD24/16/8 and R_LARCH_SUB24/16/8 reloc at tc_gen_reloc
-       function. If only fx_addsy not null, we generate
-       BFD_RELOC_LARCH_ADD24/16/8 only, then generate R_LARCH_24/16/8.
-       To avoid R_LARCH_ADDxx add extra value, we write 0 first
-       (use md_number_to_chars (buf, 0, fixP->fx_size)).  */
     case BFD_RELOC_64:
     case BFD_RELOC_32:
-      if (fixP->fx_pcrel)
-	{
-	  switch (fixP->fx_r_type)
-	    {
-	    case BFD_RELOC_64:
-	      fixP->fx_r_type = BFD_RELOC_64_PCREL;
-	      break;
-	    case BFD_RELOC_32:
-	      fixP->fx_r_type = BFD_RELOC_32_PCREL;
-	      break;
-	    default:
-	      break;
-	    }
-	}
-
       /* If symbol in .eh_frame the address may be adjusted, and contents of
 	 .eh_frame will be adjusted, so use pc-relative relocation for FDE
 	 initial location.
@@ -1807,33 +1776,65 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 	  fixP->fx_subsy = NULL;
 	  break;
 	}
-
-      if (fixP->fx_addsy && fixP->fx_subsy)
+      else if (fixP->fx_pcrel && LARCH_opts.thin_add_sub)
 	{
-	  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_64:
-	      fixP->fx_r_type = BFD_RELOC_LARCH_ADD64;
-	      fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB64;
+	      fixP->fx_r_type = BFD_RELOC_64_PCREL;
 	      break;
 	    case BFD_RELOC_32:
-	      fixP->fx_r_type = BFD_RELOC_LARCH_ADD32;
-	      fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB32;
+	      fixP->fx_r_type = BFD_RELOC_32_PCREL;
 	      break;
 	    default:
 	      break;
 	    }
+	}
+      else
+	{
+	  /* For .long 0x2eef - 1b, fx_addsy is set to NULL in fixup_segment.
+	     If fx_addsy and fx_subsy both is NULL, no need to emit relocations.
+	     If fx_sybsy is not NULL, fake up a local symbol in the absolute
+	     section, just as fixup_segment dose for fx_pcrel relocations.  */
+	  if (fixP->fx_addsy == NULL
+	      && fixP->fx_subsy != NULL)
+	    fixP->fx_addsy = abs_section_sym;
+
+	  /* For .4byte/.8byte symbol, fx_addsy is not NULL, fx_subsy is NULL.
+	     Not need to enter this if branch, just emit R_LARCH_32/64 directly.
+	     BFD_RELOC_32/64 -> R_LARCH_32/64.  */
+	  if (fixP->fx_addsy && fixP->fx_subsy)
+	    {
+	      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;
 
-	  md_number_to_chars (buf, 0, fixP->fx_size);
+	      switch (fixP->fx_r_type)
+		{
+		case BFD_RELOC_64:
+		  fixP->fx_r_type = BFD_RELOC_LARCH_ADD64;
+		  fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB64;
+		  break;
+		case BFD_RELOC_32:
+		  fixP->fx_r_type = BFD_RELOC_LARCH_ADD32;
+		  fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB32;
+		  break;
+		default:
+		  break;
+		}
+
+	      /* Because we use ADD/SUB relocations, clear the position
+		 to avoid the linker adding an extra value.  */
+	      md_number_to_chars (buf, 0, fixP->fx_size);
+	    }
 	}
 
-      if (fixP->fx_addsy == NULL)
+      /* If all symbols are resolved, write the value without emitting
+	 relocatiosn.  */
+      if (fixP->fx_addsy == NULL
+	  && fixP->fx_subsy == NULL)
 	{
 	  fixP->fx_done = 1;
 	  md_number_to_chars (buf, *valP, fixP->fx_size);
@@ -1843,39 +1844,61 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
     case BFD_RELOC_24:
     case BFD_RELOC_16:
     case BFD_RELOC_8:
+      /* Similar with BFD_RELOC_64/32.  */
+      if (fixP->fx_addsy == NULL
+	  && fixP->fx_subsy != NULL)
+	fixP->fx_addsy = abs_section_sym;
+
+      /* For .byte/.2byte/.3byte(if supported) symbol, fx_addsy is not NULL,
+	 fx_subsy is NULL.  There are no corresponding R_LARCH_8/16/24, need
+	 to enter this if branch to emit R_LARCH_ADD8/16/24.
+	 BFD_RELOC_8/16/24 -> BFD_RELOC_LARCH_ADD8/16/24 -> R_LARCH_ADD8/16/24.  */
       if (fixP->fx_addsy)
 	{
-	  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_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;
 	    }
 
-	  md_number_to_chars (buf, 0, fixP->fx_size);
+	  if (fixP->fx_subsy != NULL)
+	    {
+	      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;
 
-	  if (fixP->fx_next->fx_addsy == NULL)
-	    fixP->fx_next->fx_done = 1;
+	      switch (fixP->fx_r_type)
+		{
+		case BFD_RELOC_LARCH_ADD24:
+		  fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB24;
+		  break;
+		case BFD_RELOC_LARCH_ADD16:
+		  fixP->fx_next->fx_r_type = BFD_RELOC_LARCH_SUB16;
+		  break;
+		case 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_addsy == NULL)
+      if (fixP->fx_addsy == NULL
+	  && fixP->fx_subsy == NULL)
 	{
 	  fixP->fx_done = 1;
 	  md_number_to_chars (buf, *valP, fixP->fx_size);
diff --git a/gas/testsuite/gas/loongarch/bfd_reloc_8.s b/gas/testsuite/gas/loongarch/bfd_reloc_8.s
deleted file mode 100644
index 27388a5826f..00000000000
--- a/gas/testsuite/gas/loongarch/bfd_reloc_8.s
+++ /dev/null
@@ -1,16 +0,0 @@
-# from linux kernel entry.s
-# test line 10 ".byte \type", BFD_RELOC_8 -> BFD_RELOC_RLARCH_ADD8 -> R_LARCH_ADD8
-
-.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
-.Lunwind_hint_ip_\@:
- .pushsection .discard.unwind_hints
-  .long .Lunwind_hint_ip_\@ - .
-  .short \sp_offset
-  .byte \sp_reg
-  .byte \type
-  .byte \end
-  .balign 4
- .popsection
-.endm
-
-UNWIND_HINT type=ORC_TYPE_CALL sp_reg=2
diff --git a/gas/testsuite/gas/loongarch/loongarch.exp b/gas/testsuite/gas/loongarch/loongarch.exp
index f1dfb53d855..e5b9262a483 100644
--- a/gas/testsuite/gas/loongarch/loongarch.exp
+++ b/gas/testsuite/gas/loongarch/loongarch.exp
@@ -20,7 +20,7 @@
 
 if [istarget loongarch*-*-*] {
     run_dump_tests [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
-    gas_test_old bfd_reloc_8.s "" "bfd_reloc_8"
+
     if [file exist "tls_le_insn_format_check.s "] {
       set format [run_host_cmd "as" "tls_le_insn_format_check.s"]
       if { [ regexp ".*no match insn.*" $format] } {
diff --git a/gas/testsuite/gas/loongarch/reloc-abs.d b/gas/testsuite/gas/loongarch/reloc-abs.d
new file mode 100644
index 00000000000..f1a4fb3d1ab
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/reloc-abs.d
@@ -0,0 +1,23 @@
+#source: reloc-abs.s
+#as: -mrelax
+#objdump: -dr
+
+#...
+.*R_LARCH_ADD16	\*ABS\*\+0x2eef
+.*R_LARCH_SUB16	.L1\^B1
+.*R_LARCH_ADD32	\*ABS\*\+0x2eef
+.*R_LARCH_SUB32	.L1\^B1
+.*R_LARCH_ADD64	\*ABS\*\+0x12345678
+.*R_LARCH_SUB64	.L1\^B1
+.*R_LARCH_ADD16	\*ABS\*\+0x2eef
+.*R_LARCH_SUB16	.L1\^B1
+.*R_LARCH_ADD32	\*ABS\*\+0x2eef
+.*R_LARCH_SUB32	.L1\^B1
+.*R_LARCH_ADD8	\*ABS\*\+0x2e
+.*R_LARCH_SUB8	.L1\^B1
+.*R_LARCH_ADD16	\*ABS\*\+0x2eef
+.*R_LARCH_SUB16	.L1\^B1
+.*R_LARCH_ADD32	\*ABS\*\+0x2eef
+.*R_LARCH_SUB32	.L1\^B1
+.*R_LARCH_ADD64	\*ABS\*\+0x12345678
+.*R_LARCH_SUB64	.L1\^B1
diff --git a/gas/testsuite/gas/loongarch/reloc-abs.s b/gas/testsuite/gas/loongarch/reloc-abs.s
new file mode 100644
index 00000000000..526b71f0283
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/reloc-abs.s
@@ -0,0 +1,12 @@
+  .text
+1:
+  nop
+  .half 0x2eef - 1b
+  .word 0x2eef - 1b
+  .dword 0x12345678 - 1b
+  .short 0x2eef - 1b
+  .long 0x2eef - 1b
+  .byte 0x2e - 1b
+  .2byte 0x2eef - 1b
+  .4byte 0x2eef - 1b
+  .8byte 0x12345678 - 1b
diff --git a/gas/testsuite/gas/loongarch/reloc-add-sub.d b/gas/testsuite/gas/loongarch/reloc-add-sub.d
new file mode 100644
index 00000000000..8c599fc1711
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/reloc-add-sub.d
@@ -0,0 +1,22 @@
+#source: reloc-add-sub.s
+#as: -mrelax
+#objdump: -dr
+
+#...
+			4: R_LARCH_ADD32	\*ABS\*\+0xa
+			4: R_LARCH_SUB32	x
+			8: R_LARCH_32	x-0xa
+			c: R_LARCH_ADD32	x
+			c: R_LARCH_SUB32	y
+			10: R_LARCH_32	x
+  14:	00000005 	.word		0x00000005
+			15: R_LARCH_ADD8	\*ABS\*\+0xa
+			15: R_LARCH_SUB8	x
+			16: R_LARCH_ADD8	x-0xa
+			17: R_LARCH_ADD8	x
+			17: R_LARCH_SUB8	y
+  18:	00000000 	.word		0x00000000
+			18: R_LARCH_ADD8	x
+			19: R_LARCH_ADD8	x
+			1a: R_LARCH_ADD8	x
+			1b: R_LARCH_ADD8	x
diff --git a/gas/testsuite/gas/loongarch/reloc-add-sub.s b/gas/testsuite/gas/loongarch/reloc-add-sub.s
new file mode 100644
index 00000000000..9d18bbe3093
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/reloc-add-sub.s
@@ -0,0 +1,16 @@
+  .text
+x:
+  .long 10 - 5	# no relocation
+  .long 10 - x	# R_LARCH_ADD32/SUB32
+  .long x - 10	# R_LARCH_32
+  .long x - y	# R_LARCH_ADD32/SUB32
+  .long x	# R_LARCH_32
+
+  .byte 10 - 5	# no relocation
+  .byte 10 - x	# R_LARCH_ADD8/SUB8
+  .byte x - 10	# R_LARCH_ADD8
+  .byte x - y   # R_LARCH_ADD8/SUB8
+  .byte x	# R_LARCH_ADD8
+  .byte x
+  .byte x
+  .byte x
-- 
2.34.1



More information about the Binutils mailing list