]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
LoongArch: Add support for the third expression of .align for R_LARCH_ALIGN
authormengqinggang <mengqinggang@loongson.cn>
Fri, 8 Dec 2023 07:15:50 +0000 (15:15 +0800)
committerliuzhensong <liuzhensong@loongson.cn>
Fri, 22 Dec 2023 06:20:18 +0000 (14:20 +0800)
If the symbol index is not zero, the addend is used to represent
the first and the third expressions of the .align.

The lowest 8 bits are used to represent the first expression.
Other bits are used to represent the third expression.

The addend of R_LARCH_ALIGN for ".align 5, ,4" is 0x405.
The addend of R_LARCH_ALIGN for ".balign 32, ,4" is 0x405.

14 files changed:
bfd/elfnn-loongarch.c
bfd/elfxx-loongarch.c
gas/config/tc-loongarch.c
gas/config/tc-loongarch.h
gas/testsuite/gas/loongarch/relax_align.d
gas/testsuite/gas/loongarch/relax_align.s
ld/testsuite/ld-elf/anno-sym.d
ld/testsuite/ld-loongarch-elf/anno-sym.d [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/anno-sym.l [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/anno-sym.s [new file with mode: 0644]
ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
ld/testsuite/ld-loongarch-elf/relax-align.dd
ld/testsuite/ld-loongarch-elf/relax-align.s
ld/testsuite/ld-loongarch-elf/relax.exp

index 87eb65ab9f795f14fe6b8fe8a5c746adfb8f6ad0..faffe27294a5d0969dcb6c692036c5cc6f4c62d8 100644 (file)
@@ -3858,44 +3858,53 @@ loongarch_relax_align (bfd *abfd, asection *sec,
                        Elf_Internal_Rela *rel,
                        bfd_vma symval)
 {
-  bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
-  bfd_vma alignment = 1, pos;
-  while (alignment <= rel->r_addend)
-    alignment *= 2;
+  bfd_vma  addend, max = 0, alignment = 1;
 
-  symval -= rel->r_addend;
-  bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
-  bfd_vma nop_bytes = aligned_addr - symval;
+  int index = ELFNN_R_SYM (rel->r_info);
+  if (index > 0)
+    {
+      alignment = 1 << (rel->r_addend & 0xff);
+      max = rel->r_addend >> 8;
+    }
+  else
+    alignment = rel->r_addend + 4;
 
-  /* Once we've handled an R_LARCH_ALIGN, we can't relax anything else.  */
-  sec->sec_flg0 = true;
+  addend = alignment - 4; /* The bytes of NOPs added by R_LARCH_ALIGN.  */
+  symval -= addend; /* The address of first NOP added by R_LARCH_ALIGN.  */
+  bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
+  bfd_vma need_nop_bytes = aligned_addr - symval; /* */
 
   /* Make sure there are enough NOPs to actually achieve the alignment.  */
-  if (rel->r_addend < nop_bytes)
+  if (addend < need_nop_bytes)
     {
       _bfd_error_handler
        (_("%pB(%pA+%#" PRIx64 "): %" PRId64 " bytes required for alignment "
           "to %" PRId64 "-byte boundary, but only %" PRId64 " present"),
         abfd, sym_sec, (uint64_t) rel->r_offset,
-        (int64_t) nop_bytes, (int64_t) alignment, (int64_t) rel->r_addend);
+        (int64_t) need_nop_bytes, (int64_t) alignment, (int64_t) addend);
       bfd_set_error (bfd_error_bad_value);
       return false;
     }
 
-  /* Delete the reloc.  */
+  /* Once we've handled an R_LARCH_ALIGN in a section,
+     we can't relax anything else in this section.  */
+  sec->sec_flg0 = true;
   rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
 
+  /* If skipping more bytes than the specified maximum,
+     then the alignment is not done at all and delete all NOPs.  */
+  if (max > 0 && need_nop_bytes > max)
+    return loongarch_relax_delete_bytes (abfd, sec, rel->r_offset,
+                                         addend, link_info);
+
   /* If the number of NOPs is already correct, there's nothing to do.  */
-  if (nop_bytes == rel->r_addend)
+  if (need_nop_bytes == addend)
     return true;
 
-  /* Write as many LOONGARCH NOPs as we need.  */
-  for (pos = 0; pos < (nop_bytes & -4); pos += 4)
-    bfd_putl32 (LARCH_NOP, contents + rel->r_offset + pos);
-
   /* Delete the excess NOPs.  */
-  return loongarch_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes,
-                                  rel->r_addend - nop_bytes, link_info);
+  return loongarch_relax_delete_bytes (abfd, sec,
+                                       rel->r_offset + need_nop_bytes,
+                                       addend - need_nop_bytes, link_info);
 }
 
 static bool
@@ -3904,8 +3913,8 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
                               bool *again)
 {
   struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
-  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
   struct bfd_elf_section_data *data = elf_section_data (sec);
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
   Elf_Internal_Rela *relocs;
   *again = false;
 
@@ -3938,7 +3947,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
                                                   0, NULL, NULL, NULL)))
     return true;
 
-      data->relocs = relocs;
+  data->relocs = relocs;
 
   for (unsigned int i = 0; i < sec->reloc_count; i++)
     {
@@ -3946,6 +3955,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
       asection *sym_sec;
       bfd_vma symval;
       unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
+      unsigned long r_type = ELFNN_R_TYPE (rel->r_info);
       bool local_got = false;
       char symtype;
       struct elf_link_hash_entry *h = NULL;
@@ -3957,7 +3967,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
          if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
            continue;
 
-         if (sym->st_shndx == SHN_UNDEF)
+         if (sym->st_shndx == SHN_UNDEF || R_LARCH_ALIGN == r_type)
            {
              sym_sec = sec;
              symval = rel->r_offset;
@@ -3983,9 +3993,9 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
            continue;
 
          if ((h->root.type == bfd_link_hash_defined
-                   || h->root.type == bfd_link_hash_defweak)
-                  && h->root.u.def.section != NULL
-                  && h->root.u.def.section->output_section != NULL)
+                 || h->root.type == bfd_link_hash_defweak)
+               && h->root.u.def.section != NULL
+               && h->root.u.def.section->output_section != NULL)
            {
              symval = h->root.u.def.value;
              sym_sec = h->root.u.def.section;
@@ -4011,12 +4021,21 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
           if (symtype != STT_SECTION)
             symval += rel->r_addend;
        }
+      /* For R_LARCH_ALIGN, symval is sec_addr (sym_sec) + rel->r_offset
+        + (alingmeng - 4).
+        If r_symndx is 0, alignmeng-4 is r_addend.
+        If r_symndx > 0, alignment-4 is 2^(r_addend & 0xff)-4.  */
+      else if (R_LARCH_ALIGN == r_type)
+       if (r_symndx > 0)
+         symval += ((1 << (rel->r_addend & 0xff)) - 4);
+       else
+         symval += rel->r_addend;
       else
        symval += rel->r_addend;
 
       symval += sec_addr (sym_sec);
 
-      switch (ELFNN_R_TYPE (rel->r_info))
+      switch (r_type)
        {
        case R_LARCH_ALIGN:
          if (1 == info->relax_pass)
index d93b79043ce22ae4760e1fedb5ff7fd59acd05a0..679b79f34a4dd90d5dbc325dbec9fbeab0a7b461 100644 (file)
@@ -1395,9 +1395,13 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
         NULL,                                  /* adjust_reloc_bits.  */
         NULL),                                 /* larch_reloc_type_name.  */
 
-  /* Indicates an alignment statement.  The addend field encodes how many
-     bytes of NOPs follow the statement.  The desired alignment is the
-     addend rounded up to the next power of two.  */
+  /* Indicates an alignment statement. f the symbol index is 0,
+     the addend indicates the number of bytes occupied by nop instructions
+     at the relocation offset. The alignment boundary is specified by the
+     addend rounded up to the next power of two.
+     If the symbol index is not 0, the addend indicates the first and third
+     expressions of .align. The lowest 8 bits are used to represent the first
+     expression, other bits are used to represent the third expression.  */
   LOONGARCH_HOWTO (R_LARCH_ALIGN,              /* type (102).  */
         0,                                     /* rightshift.  */
         0,                                     /* size.  */
index 367a0b6c5a4d92a51019a4d126f168b8abf60854..9b912daf407998064090ae251ac4a07ffc4ce4e8 100644 (file)
@@ -1652,14 +1652,16 @@ loongarch_make_nops (char *buf, bfd_vma bytes)
    the correct alignment now because of other linker relaxations.  */
 
 bool
-loongarch_frag_align_code (int n)
+loongarch_frag_align_code (int n, int max)
 {
-  bfd_vma bytes = (bfd_vma) 1 << n;
-  bfd_vma insn_alignment = 4;
-  bfd_vma worst_case_bytes = bytes - insn_alignment;
   char *nops;
+  symbolS *s;
   expressionS ex;
 
+  bfd_vma insn_alignment = 4;
+  bfd_vma bytes = (bfd_vma) 1 << n;
+  bfd_vma worst_case_bytes = bytes - insn_alignment;
+
   /* If we are moving to a smaller alignment than the instruction size, then no
      alignment is required.  */
   if (bytes <= insn_alignment)
@@ -1671,8 +1673,14 @@ loongarch_frag_align_code (int n)
 
   nops = frag_more (worst_case_bytes);
 
-  ex.X_op = O_constant;
-  ex.X_add_number = worst_case_bytes;
+  s = symbol_find (".Lla-relax-align");
+  if (s == NULL)
+    s = (symbolS *)local_symbol_make (".Lla-relax-align", now_seg,
+                                     &zero_address_frag, 0);
+
+  ex.X_add_symbol = s;
+  ex.X_op = O_symbol;
+  ex.X_add_number = (max << 8) | n;
 
   loongarch_make_nops (nops, worst_case_bytes);
 
index 4afa38422d65383b7e27a3285f03b2462b3e8152..194ee107c0a221127fad242acf115b4e55abb161 100644 (file)
@@ -49,11 +49,11 @@ extern int loongarch_relax_frag (asection *, struct frag *, long);
 #define md_undefined_symbol(name) (0)
 #define md_operand(x)
 
-extern bool loongarch_frag_align_code (int);
+extern bool loongarch_frag_align_code (int, int);
 #define md_do_align(N, FILL, LEN, MAX, LABEL)                          \
   if ((N) != 0 && !(FILL) && !need_pass_2 && subseg_text_p (now_seg))  \
     {                                                                  \
-      if (loongarch_frag_align_code (N))                               \
+      if (loongarch_frag_align_code (N, MAX))                          \
        goto LABEL;                                                     \
     }
 
index 1810eb4cae73ffbc4f313b7701abb012bd67e9c7..2cc6c86d38aad9736451be8a4a7763357f631ef3 100644 (file)
@@ -1,4 +1,4 @@
-#as:
+#as: --no-warn
 #objdump: -dr
 #skip: loongarch32-*-*
 
@@ -7,20 +7,30 @@
 
 Disassembly of section .text:
 
-00000000.* <L1>:
-[      ]+0:[   ]+1a000004[     ]+pcalau12i[    ]+\$a0,[        ]+0
-[      ]+0:[   ]+R_LARCH_PCALA_HI20[   ]+L1
-[      ]+0:[   ]+R_LARCH_RELAX[        ]+\*ABS\*
-[      ]+4:[   ]+02c00084[     ]+addi\.d[      ]+\$a0,[        ]+\$a0,[        ]+0
-[      ]+4:[   ]+R_LARCH_PCALA_LO12[   ]+L1
-[      ]+4:[   ]+R_LARCH_RELAX[        ]+\*ABS\*
-[      ]+8:[   ]+03400000[     ]+nop[  ]+
-[      ]+8:[   ]+R_LARCH_ALIGN[        ]+\*ABS\*\+0xc
-[      ]+c:[   ]+03400000[     ]+nop[  ]+
-[      ]+10:[  ]+03400000[     ]+nop[  ]+
-[      ]+14:[  ]+1a000004[     ]+pcalau12i[    ]+\$a0,[        ]+0
-[      ]+14:[  ]+R_LARCH_PCALA_HI20[   ]+L1
-[      ]+14:[  ]+R_LARCH_RELAX[        ]+\*ABS\*
-[      ]+18:[  ]+02c00084[     ]+addi\.d[      ]+\$a0,[        ]+\$a0,[        ]+0
-[      ]+18:[  ]+R_LARCH_PCALA_LO12[   ]+L1
-[      ]+18:[  ]+R_LARCH_RELAX[        ]+\*ABS\*
+[      ]*0000000000000000 <.Lla-relax-align>:
+[      ]+0:[   ]+1a000004[     ]+pcalau12i[    ]+\$a0, 0
+[      ]+0: R_LARCH_PCALA_HI20[        ]+L1
+[      ]+0: R_LARCH_RELAX[     ]+\*ABS\*
+[      ]+4:[   ]+02c00084[     ]+addi.d[       ]+\$a0, \$a0, 0
+[      ]+4: R_LARCH_PCALA_LO12[        ]+L1
+[      ]+4: R_LARCH_RELAX[     ]+\*ABS\*
+[      ]+8:[   ]+03400000[     ]+nop.*
+[      ]+8: R_LARCH_ALIGN[     ]+.Lla-relax-align\+0x4
+[      ]+c:[   ]+03400000[     ]+nop.*
+[      ]+10:[  ]+03400000[     ]+nop.*
+[      ]+14:[  ]+1a000004[     ]+pcalau12i[    ]+\$a0, 0
+[      ]+14: R_LARCH_PCALA_HI20[       ]+L1
+[      ]+14: R_LARCH_RELAX[    ]+\*ABS\*
+[      ]+18:[  ]+02c00084[     ]+addi.d[       ]+\$a0, \$a0, 0
+[      ]+18: R_LARCH_PCALA_LO12[       ]+L1
+[      ]+18: R_LARCH_RELAX[    ]+\*ABS\*
+[      ]+1c:[  ]+03400000[     ]+nop.*
+[      ]+1c: R_LARCH_ALIGN[    ]+.Lla-relax-align\+0x404
+[      ]+20:[  ]+03400000[     ]+nop.*
+[      ]+24:[  ]+03400000[     ]+nop.*
+[      ]+28:[  ]+1a000004[     ]+pcalau12i[    ]+\$a0, 0
+[      ]+28: R_LARCH_PCALA_HI20[       ]+L1
+[      ]+28: R_LARCH_RELAX[    ]+\*ABS\*
+[      ]+2c:[  ]+02c00084[     ]+addi.d[       ]+\$a0, \$a0, 0
+[      ]+2c: R_LARCH_PCALA_LO12[       ]+L1
+[      ]+2c: R_LARCH_RELAX[    ]+\*ABS\*
index 3880d783e798f6b21cea10ec2c3e8d937b79028c..c0177c88fc10521f1c4d5abff5d5c1b856aa0fa6 100644 (file)
@@ -1,5 +1,7 @@
   .text
-L1:
+.L1:
   la.local $a0, L1
   .align 4
   la.local $a0, L1
+  .align 4, , 4
+  la.local $a0, L1
index 9e53c4a9c168b73372120748af9b91052b2674a6..f1ce21f9eaa5c094395b288ec689906eb0ef99a4 100644 (file)
@@ -3,3 +3,5 @@
 #error_output: anno-sym.l
 # The mips-irix6 target fails this test because it does not find any function symbols.  Not sure why.
 #skip: *-*-irix*
+# The .align generate a local symbol .Lla-relax-align.
+#skip: loongarch*-*-*
diff --git a/ld/testsuite/ld-loongarch-elf/anno-sym.d b/ld/testsuite/ld-loongarch-elf/anno-sym.d
new file mode 100644 (file)
index 0000000..a58f4a6
--- /dev/null
@@ -0,0 +1,7 @@
+# Copied from ld-elf, add -mno-relax to prevent generate .Lla-relax-align symbol
+# Check that linking anno-sym.o produces an undefined reference message referring to '_start' and not 'annobin_hello.c'
+#as: -mno-relax
+#ld:  -e _start
+#error_output: anno-sym.l
+# The mips-irix6 target fails this test because it does not find any function symbols.  Not sure why.
+#skip: *-*-irix*
diff --git a/ld/testsuite/ld-loongarch-elf/anno-sym.l b/ld/testsuite/ld-loongarch-elf/anno-sym.l
new file mode 100644 (file)
index 0000000..ee9611a
--- /dev/null
@@ -0,0 +1,4 @@
+#...
+.*: in function `(|_)start':
+.*: undefined reference to `foo'
+#pass
diff --git a/ld/testsuite/ld-loongarch-elf/anno-sym.s b/ld/testsuite/ld-loongarch-elf/anno-sym.s
new file mode 100644 (file)
index 0000000..92016a8
--- /dev/null
@@ -0,0 +1,13 @@
+       .text
+
+       .hidden .annobin_hello.c
+       .type .annobin_hello.c, STT_NOTYPE
+       .equiv .annobin_hello.c, .
+       .size .annobin_hello.c, 0
+
+       .global _start
+_start:
+       .nop
+       .align 4
+       .dc.a foo
+
index 1fc70d0a61e6b8152d43fa3498820aa9d6c5ae2d..b43a518af836ff0db39b340cab849fe6c7d644e2 100644 (file)
@@ -32,6 +32,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "syscall"
     run_dump_test "disas-jirl"
     run_dump_test "local-ifunc-reloc"
+    run_dump_test "anno-sym"
 }
 
 if [istarget "loongarch32-*-*"] {
index 5fce2255ddacb56702c3ae8bf4e49e1c10821fd1..37fdab18fab49a73bb4606f4a34d7f963feefe6e 100644 (file)
@@ -1,7 +1,8 @@
 #...
 .*pcaddi.*
-.*pcaddi.*
 .*nop.*
+.*pcaddi.*
 .*nop.*
-.*0:.*pcaddi.*
+.*pcaddi.*
+.*pcaddi.*
 #pass
index 9617c02d8e575af1aa2492698f69b120bc02d25b..66dfea8f2c98807233a05aa868f795799dbdf26d 100644 (file)
@@ -4,6 +4,9 @@
   .text
 L1:
   la.local $a0, L1
+  .align 3
   la.local $a0, L1
-  .align 4
+  .align 3, ,4
+  la.local $a0, L1
+  .align 3, ,2
   la.local $a0, L1
index 24d79ed5c20bb2953d656d8d57278891a032dcf6..77323d8d7a3a0bbd28144178657ce8af225bd88a 100644 (file)
@@ -121,7 +121,7 @@ if [istarget loongarch64-*-*] {
          [list \
              "loongarch relax-align" \
              "-e 0x0 -z relro" "" \
-             "" \
+             "--no-warn" \
              {relax-align.s} \
              [list \
                  [list objdump -d relax-align.dd] \