From ea14dbe723a67501b377bf6d4f390ca4b6a58938 Mon Sep 17 00:00:00 2001
From: mengqinggang <mengqinggang@loongson.cn>
Date: Wed, 29 May 2024 14:50:39 +0800
Subject: [PATCH 089/123] LoongArch: Make align symbol be in same section with
 alignment directive

R_LARCH_ALIGN (psABI v2.30) requires a symbol index. The symbol is only
created at the first time to handle alignment directive. This means that
all other sections may use this symbol. If the section of this symbol is
discarded, there may be problems. Search it in its own section.

Remove elf_backend_data.is_rela_normal() function added at commit daeda14191c.

Co-authored-by: Jinyang He <hejinyang@loongson.cn>
Reported-by: WANG Xuerui <git@xen0n.name>
Link: https://lore.kernel.org/loongarch/2abbb633-a10e-71cc-a5e1-4d9e39074066@loongson.cn/T/#t
---
 bfd/elf-bfd.h                              |  4 --
 bfd/elflink.c                              |  5 +-
 bfd/elfnn-loongarch.c                      | 16 ------
 bfd/elfxx-target.h                         |  5 --
 gas/config/tc-loongarch.c                  | 63 +++++++++++++++++++++-
 gas/config/tc-loongarch.h                  |  3 ++
 gas/testsuite/gas/loongarch/relax-align2.d | 24 +++++++++
 gas/testsuite/gas/loongarch/relax-align2.s | 11 ++++
 gas/testsuite/gas/loongarch/relax_align.d  |  6 +--
 9 files changed, 104 insertions(+), 33 deletions(-)
 create mode 100644 gas/testsuite/gas/loongarch/relax-align2.d
 create mode 100644 gas/testsuite/gas/loongarch/relax-align2.s

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 074120a5..ec856764 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1703,10 +1703,6 @@ struct elf_backend_data
      backend relocate_section routine for relocatable linking.  */
   unsigned rela_normal : 1;
 
-  /* Whether a relocation is rela_normal. Compared with rela_normal,
-     is_rela_normal can set part of relocations to rela_normal.  */
-  bool (*is_rela_normal) (Elf_Internal_Rela *);
-
   /* Set if DT_REL/DT_RELA/DT_RELSZ/DT_RELASZ should not include PLT
      relocations.  */
   unsigned dtrel_excludes_plt : 1;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index cbf87d70..7217c2f0 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -11647,10 +11647,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd)
 		    {
 		      rel_hash = PTR_ADD (esdo->rela.hashes, esdo->rela.count);
 		      rela_hash_list = rel_hash;
-		      if (bed->is_rela_normal != NULL)
-			rela_normal = bed->is_rela_normal (irela);
-		      else
-			rela_normal = bed->rela_normal;
+		      rela_normal = bed->rela_normal;
 		    }
 
 		  irela->r_offset = _bfd_elf_section_offset (output_bfd,
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index eb572a77..9eaad7f4 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -5527,21 +5527,6 @@ elf_loongarch64_hash_symbol (struct elf_link_hash_entry *h)
   return _bfd_elf_hash_symbol (h);
 }
 
-/* If a relocation is rela_normal and the symbol associated with the
-   relocation is STT_SECTION type, the addend of the relocation would add
-   sec->output_offset when partial linking (ld -r).
-   See elf_backend_data.rela_normal and elf_link_input_bfd().
-   The addend of R_LARCH_ALIGN is used to represent the first and third
-   expression of .align, it should be a constant when linking.  */
-
-static bool
-loongarch_elf_is_rela_normal (Elf_Internal_Rela *rel)
-{
-  if (R_LARCH_ALIGN == ELFNN_R_TYPE (rel->r_info))
-    return false;
-  return true;
-}
-
 #define TARGET_LITTLE_SYM loongarch_elfNN_vec
 #define TARGET_LITTLE_NAME "elfNN-loongarch"
 #define ELF_ARCH bfd_arch_loongarch
@@ -5577,7 +5562,6 @@ loongarch_elf_is_rela_normal (Elf_Internal_Rela *rel)
 #define elf_backend_grok_psinfo loongarch_elf_grok_psinfo
 #define elf_backend_hash_symbol elf_loongarch64_hash_symbol
 #define bfd_elfNN_bfd_relax_section loongarch_elf_relax_section
-#define elf_backend_is_rela_normal loongarch_elf_is_rela_normal
 
 #define elf_backend_dtrel_excludes_plt 1
 
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 385e40b7..f8553006 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -703,10 +703,6 @@
 #define elf_backend_rela_normal 0
 #endif
 
-#ifndef elf_backend_is_rela_normal
-#define elf_backend_is_rela_normal NULL
-#endif
-
 #ifndef elf_backend_dtrel_excludes_plt
 #define elf_backend_dtrel_excludes_plt 0
 #endif
@@ -952,7 +948,6 @@ static const struct elf_backend_data elfNN_bed =
   elf_backend_default_use_rela_p,
   elf_backend_rela_plts_and_copies_p,
   elf_backend_rela_normal,
-  elf_backend_is_rela_normal,
   elf_backend_dtrel_excludes_plt,
   elf_backend_sign_extend_vma,
   elf_backend_want_got_plt,
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index f030fd07..f039d027 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -419,6 +419,55 @@ loongarch_target_format ()
   return LARCH_opts.ase_lp64 ? "elf64-loongarch" : "elf32-loongarch";
 }
 
+typedef struct
+{
+  unsigned int sec_id;
+  symbolS *s;
+} align_sec_sym;
+
+static htab_t align_hash;
+
+static hashval_t
+align_sec_sym_hash (const void *entry)
+{
+  const align_sec_sym *e = entry;
+  return (hashval_t) (e->sec_id);
+}
+
+static int
+align_sec_sym_eq (const void *entry1, const void *entry2)
+{
+  const align_sec_sym *e1 = entry1, *e2 = entry2;
+  return e1->sec_id == e2->sec_id;
+}
+
+/* Make align symbol be in same section with alignment directive.
+   If the symbol is only created at the first time to handle alignment
+   directive.  This means that all other sections may use this symbol.
+   If the section of this symbol is discarded, there may be problems.  */
+
+static symbolS *get_align_symbol (segT sec)
+{
+  align_sec_sym search = { sec->id, NULL };
+  align_sec_sym *pentry = htab_find (align_hash, &search);
+  if (pentry)
+    return pentry->s;
+
+  /* If we not find the symbol in this section.  Create and insert it.  */
+  symbolS *s = (symbolS *)local_symbol_make (".Lla-relax-align", sec,
+					     &zero_address_frag, 0);
+  align_sec_sym entry = { sec->id, s };
+  align_sec_sym **slot = (align_sec_sym **) htab_find_slot (align_hash,
+							    &entry, INSERT);
+  if (slot == NULL)
+    return NULL;
+  *slot = (align_sec_sym *) xmalloc (sizeof (align_sec_sym));
+  if (*slot == NULL)
+    return NULL;
+  **slot = entry;
+  return entry.s;
+}
+
 void
 md_begin ()
 {
@@ -440,11 +489,21 @@ md_begin ()
 		    it->name, it->format, it->macro);
       }
 
+  align_hash = htab_create (10, align_sec_sym_hash, align_sec_sym_eq, free);
+
   /* FIXME: expressionS use 'offsetT' as constant,
    * we want this is 64-bit type.  */
   assert (8 <= sizeof (offsetT));
 }
 
+/* Called just before the assembler exits.  */
+
+void
+loongarch_md_end (void)
+{
+  htab_delete (align_hash);
+}
+
 unsigned long
 loongarch_mach (void)
 {
@@ -1826,7 +1885,9 @@ loongarch_frag_align_code (int n, int max)
      if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype).  */
   if (align_max)
     {
-      s = symbol_find (now_seg->name);
+      s = get_align_symbol (now_seg);
+      if (!s)
+	as_fatal (_("internal error: cannot get align symbol"));
       addend = ALIGN_MAX_ADDEND (n, max);
     }
 
diff --git a/gas/config/tc-loongarch.h b/gas/config/tc-loongarch.h
index 6963867e..05c0af45 100644
--- a/gas/config/tc-loongarch.h
+++ b/gas/config/tc-loongarch.h
@@ -32,6 +32,9 @@ extern unsigned long loongarch_mach (void);
 #define WORKING_DOT_WORD 1
 #define REPEAT_CONS_EXPRESSIONS
 
+#define md_end loongarch_md_end
+extern void loongarch_md_end (void);
+
 /* Early than md_begin.  */
 #define md_after_parse_args loongarch_after_parse_args
 extern void loongarch_after_parse_args (void);
diff --git a/gas/testsuite/gas/loongarch/relax-align2.d b/gas/testsuite/gas/loongarch/relax-align2.d
new file mode 100644
index 00000000..cbef84f8
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/relax-align2.d
@@ -0,0 +1,24 @@
+#as: --no-warn
+#readelf: -rsW
+#skip: loongarch32-*-*
+
+Relocation section '\.rela\.text' at offset .* contains 2 entries:
+.*
+0+04[ 	]+0000000000000066[ 	]+R_LARCH_ALIGN[ 	]+c
+0+14[ 	]+0000000500000066[ 	]+R_LARCH_ALIGN[ 	]+0+[ 	]+\.Lla-relax-align \+ 404
+
+Relocation section '\.rela\.text2' at offset .* contains 2 entries:
+.*
+0+04[ 	]+0000000000000066[ 	]+R_LARCH_ALIGN[ 	]+c
+0+14[ 	]+0000000600000066[ 	]+R_LARCH_ALIGN[ 	]+0+[ 	]+\.Lla-relax-align \+ 404
+
+Symbol table '\.symtab' contains .* entries:
+#...
+[ 	]+.*:[ 	]+0+[ 	]+0[ 	]+SECTION[ 	]+LOCAL[ 	]+DEFAULT[ 	]+1[ 	]+\.text
+#...
+[ 	]+.*:[ 	]+0+[ 	]+0[ 	]+SECTION[ 	]+LOCAL[ 	]+DEFAULT[ 	]+5[ 	]+\.text2
+#...
+[ 	]+.*:[ 	]+0+[ 	]+0[ 	]+NOTYPE[ 	]+LOCAL[ 	]+DEFAULT[ 	]+1[ 	]+\.Lla-relax-align
+#...
+[ 	]+.*:[ 	]+0+[ 	]+0[ 	]+NOTYPE[ 	]+LOCAL[ 	]+DEFAULT[ 	]+5[ 	]+\.Lla-relax-align
+#pass
diff --git a/gas/testsuite/gas/loongarch/relax-align2.s b/gas/testsuite/gas/loongarch/relax-align2.s
new file mode 100644
index 00000000..6cd6bd87
--- /dev/null
+++ b/gas/testsuite/gas/loongarch/relax-align2.s
@@ -0,0 +1,11 @@
+.section ".text", "ax"
+nop
+.align 4
+nop
+.align 4, , 4
+
+.section ".text2", "ax"
+nop
+.align 4
+nop
+.align 4, , 4
diff --git a/gas/testsuite/gas/loongarch/relax_align.d b/gas/testsuite/gas/loongarch/relax_align.d
index acd215a4..fc1fd032 100644
--- a/gas/testsuite/gas/loongarch/relax_align.d
+++ b/gas/testsuite/gas/loongarch/relax_align.d
@@ -7,7 +7,7 @@
 
 Disassembly of section .text:
 
-[ 	]*0000000000000000 <.text>:
+[ 	]*0000000000000000 <.Lla-relax-align>:
 [ 	]+0:[ 	]+4c000020[ 	]+ret
 [ 	]+4:[ 	]+03400000[ 	]+nop
 [ 	]+4: R_LARCH_ALIGN[ 	]+\*ABS\*\+0xc
@@ -20,12 +20,12 @@ Disassembly of section .text:
 [ 	]+1c:[ 	]+03400000[ 	]+nop
 [ 	]+20:[ 	]+4c000020[ 	]+ret
 [ 	]+24:[ 	]+03400000[ 	]+nop
-[ 	]+24: R_LARCH_ALIGN[ 	]+.text\+0x104
+[ 	]+24: R_LARCH_ALIGN[ 	]+.Lla-relax-align\+0x104
 [ 	]+28:[ 	]+03400000[ 	]+nop
 [ 	]+2c:[ 	]+03400000[ 	]+nop
 [ 	]+30:[ 	]+4c000020[ 	]+ret
 [ 	]+34:[ 	]+03400000[ 	]+nop
-[ 	]+34: R_LARCH_ALIGN[ 	]+.text\+0xb04
+[ 	]+34: R_LARCH_ALIGN[ 	]+.Lla-relax-align\+0xb04
 [ 	]+38:[ 	]+03400000[ 	]+nop
 [ 	]+3c:[ 	]+03400000[ 	]+nop
 [ 	]+40:[ 	]+4c000020[ 	]+ret
-- 
2.33.0

