* [PATCH] LoongArch: Add R_LARCH_ALIGN_MAX relocation
@ 2023-11-28 3:56 mengqinggang
0 siblings, 0 replies; only message in thread
From: mengqinggang @ 2023-11-28 3:56 UTC (permalink / raw)
To: binutils
Cc: xuchenghua, chenglulu, liuzhensong, xry111, i.swmail, maskray,
cailulu, luweining, wanglei, hejinyang, mengqinggang
The addend of R_LARCH_ALIGN_MAX is used to represent the first and the third
expressions of the .align pseudo instruction.
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_MAX for ".align 5, ,4" is 0x405.
The addend of R_LARCH_ALIGN_MAX for ".balign 32, ,4" is 0x405.
---
bfd/bfd-in2.h | 1 +
bfd/elfnn-loongarch.c | 75 +++++++++++++++++++
bfd/elfxx-loongarch.c | 19 +++++
bfd/libbfd.h | 1 +
bfd/reloc.c | 3 +
gas/config/tc-loongarch.c | 6 +-
gas/config/tc-loongarch.h | 4 +-
gas/testsuite/gas/loongarch/relax_align.d | 34 ++++-----
gas/testsuite/gas/loongarch/relax_align.s | 1 -
include/elf/loongarch.h | 2 +
.../ld-loongarch-elf/relax-align-max.dd | 4 +
.../ld-loongarch-elf/relax-align-max.s | 6 ++
ld/testsuite/ld-loongarch-elf/relax.exp | 14 ++++
13 files changed, 147 insertions(+), 23 deletions(-)
create mode 100644 ld/testsuite/ld-loongarch-elf/relax-align-max.dd
create mode 100644 ld/testsuite/ld-loongarch-elf/relax-align-max.s
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 040d5560cdf..e88e5966c22 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -7460,6 +7460,7 @@ enum bfd_reloc_code_real
BFD_RELOC_LARCH_ADD_ULEB128,
BFD_RELOC_LARCH_SUB_ULEB128,
BFD_RELOC_LARCH_64_PCREL,
+ BFD_RELOC_LARCH_ALIGN_MAX,
BFD_RELOC_UNUSED
};
typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 024c5d4cd96..7a9b96018ec 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3534,6 +3534,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_LARCH_RELAX:
case R_LARCH_ALIGN:
+ case R_LARCH_ALIGN_MAX:
r = bfd_reloc_continue;
unresolved_reloc = false;
break;
@@ -3891,6 +3892,63 @@ loongarch_relax_align (bfd *abfd, asection *sec,
rel->r_addend - nop_bytes, link_info);
}
+static bool
+loongarch_relax_align_max (bfd *abfd, asection *sec,
+ asection *sym_sec,
+ struct bfd_link_info *link_info,
+ Elf_Internal_Rela *rel,
+ bfd_vma symval)
+{
+ bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
+
+ bfd_vma alignment = 1, pos, max;
+
+ /* 2^n = 2<<(n-1). */
+ alignment = 2 << ((rel->r_addend & 0xff) - 1);
+ max = (rel->r_addend >> 8);
+
+ symval -= (alignment - 4);
+ bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
+ bfd_vma nop_bytes = aligned_addr - symval;
+
+ /* Once we've handled an R_LARCH_ALIGN, we can't relax anything else. */
+ sec->sec_flg0 = true;
+
+ /* Make sure there are enough NOPs to actually achieve the alignment. */
+ if ((alignment - 4) < 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);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ /* Change R_LARCH_ALIGN_MAX to R_LARCH_NONE. */
+ rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
+
+ /* If doing the alignemnt would require skipping more bytes than the
+ specified maximum, then the alignment is not done at all (delete all NOPs).
+ If the maximum is 0, the alignment can skip any bytes. */
+ if (max > 0 && nop_bytes > max)
+ return loongarch_relax_delete_bytes (abfd, sec, rel->r_offset,
+ alignment - 4, link_info);
+
+ /* If the number of NOPs is already correct, there's nothing to do. */
+ if (nop_bytes == (alignment - 4))
+ 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,
+ (alignment - 4) - nop_bytes, link_info);
+}
+
static bool
loongarch_elf_relax_section (bfd *abfd, asection *sec,
struct bfd_link_info *info,
@@ -4005,6 +4063,14 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
if (symtype != STT_SECTION)
symval += rel->r_addend;
}
+ /* For R_LARCH_ALIGN_MAX and R_LARCH_ALIGN, symval is sec_addr(sym_sec)
+ + rel->r_offset + (alingmeng - 4).
+ For R_LARCH_ALIGN, alignmeng-4 is r_addend.
+ For R_LARCH_ALIGN_MAX, alignment-4 is 2^(r_addend & 0xff)-4. */
+ else if (R_LARCH_ALIGN_MAX == ELFNN_R_TYPE (rel->r_info))
+ symval += ((2 << ((rel->r_addend & 0xff) - 1)) - 4);
+ else if (R_LARCH_ALIGN == ELFNN_R_TYPE (rel->r_info))
+ symval += rel->r_addend;
else
symval += rel->r_addend;
@@ -4016,6 +4082,12 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
if (1 == info->relax_pass)
loongarch_relax_align (abfd, sec, sym_sec, info, rel, symval);
break;
+
+ case R_LARCH_ALIGN_MAX:
+ if (1 == info->relax_pass)
+ loongarch_relax_align_max (abfd, sec, sym_sec, info, rel, symval);
+ break;
+
case R_LARCH_DELETE:
if (1 == info->relax_pass)
{
@@ -4023,11 +4095,13 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
}
break;
+
case R_LARCH_PCALA_HI20:
if (0 == info->relax_pass && (i + 4) <= sec->reloc_count)
loongarch_relax_pcala_addi (abfd, sec, sym_sec, rel, symval,
info, again);
break;
+
case R_LARCH_GOT_PC_HI20:
if (local_got && 0 == info->relax_pass
&& (i + 4) <= sec->reloc_count)
@@ -4037,6 +4111,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
info, again);
}
break;
+
default:
break;
}
diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c
index a970a257aa9..072dbc7494f 100644
--- a/bfd/elfxx-loongarch.c
+++ b/bfd/elfxx-loongarch.c
@@ -1547,6 +1547,25 @@ static loongarch_reloc_howto_type loongarch_howto_table[] =
NULL, /* adjust_reloc_bits */
NULL), /* larch_reloc_type_name */
+ /* The lowest 8 bits is the first expression of .align,
+ other bits is the third expression of .align. */
+ LOONGARCH_HOWTO (R_LARCH_ALIGN_MAX, /* type (110). */
+ 0, /* rightshift. */
+ 0, /* size. */
+ 0, /* bitsize. */
+ false, /* pc_relative. */
+ 0, /* bitpos. */
+ complain_overflow_dont, /* complain_on_overflow. */
+ bfd_elf_generic_reloc, /* special_function. */
+ "R_LARCH_ALIGN_MAX", /* name. */
+ false, /* partial_inplace. */
+ 0, /* src_mask. */
+ 0, /* dst_mask. */
+ false, /* pcrel_offset. */
+ BFD_RELOC_LARCH_ALIGN_MAX, /* bfd_reloc_code_real_type. */
+ NULL, /* adjust_reloc_bits. */
+ NULL), /* larch_reloc_type_name. */
+
};
reloc_howto_type *
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index cc432677a81..79172590b19 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -3599,6 +3599,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_LARCH_ADD_ULEB128",
"BFD_RELOC_LARCH_SUB_ULEB128",
"BFD_RELOC_LARCH_64_PCREL",
+ "BFD_RELOC_LARCH_ALIGN_MAX",
"@@overflow: BFD_RELOC_UNUSED@@",
};
#endif
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 93ebad879e0..3353cbb2c2b 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -8292,6 +8292,9 @@ ENUMX
ENUMX
BFD_RELOC_LARCH_64_PCREL
+ENUMX
+ BFD_RELOC_LARCH_ALIGN_MAX
+
ENUMDOC
LARCH relocations.
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index d1ce111c186..8c60dd555de 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -1646,7 +1646,7 @@ 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;
@@ -1666,12 +1666,12 @@ loongarch_frag_align_code (int n)
nops = frag_more (worst_case_bytes);
ex.X_op = O_constant;
- ex.X_add_number = worst_case_bytes;
+ ex.X_add_number = ((max << 8) | n);
loongarch_make_nops (nops, worst_case_bytes);
fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
- &ex, false, BFD_RELOC_LARCH_ALIGN);
+ &ex, false, BFD_RELOC_LARCH_ALIGN_MAX);
/* We need to start a new frag after the alignment which may be removed by
the linker, to prevent the assembler from computing static offsets.
diff --git a/gas/config/tc-loongarch.h b/gas/config/tc-loongarch.h
index 4afa38422d6..194ee107c0a 100644
--- a/gas/config/tc-loongarch.h
+++ b/gas/config/tc-loongarch.h
@@ -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; \
}
diff --git a/gas/testsuite/gas/loongarch/relax_align.d b/gas/testsuite/gas/loongarch/relax_align.d
index 1810eb4cae7..cc2562fc25c 100644
--- a/gas/testsuite/gas/loongarch/relax_align.d
+++ b/gas/testsuite/gas/loongarch/relax_align.d
@@ -7,20 +7,20 @@
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\*
+.* <.text>:
+[ ]+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_MAX[ ]+\*ABS\*\+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\*
diff --git a/gas/testsuite/gas/loongarch/relax_align.s b/gas/testsuite/gas/loongarch/relax_align.s
index 3880d783e79..482600e43a5 100644
--- a/gas/testsuite/gas/loongarch/relax_align.s
+++ b/gas/testsuite/gas/loongarch/relax_align.s
@@ -1,5 +1,4 @@
.text
-L1:
la.local $a0, L1
.align 4
la.local $a0, L1
diff --git a/include/elf/loongarch.h b/include/elf/loongarch.h
index e31395e13d5..cce43bb4a10 100644
--- a/include/elf/loongarch.h
+++ b/include/elf/loongarch.h
@@ -251,6 +251,8 @@ RELOC_NUMBER (R_LARCH_SUB_ULEB128, 108)
RELOC_NUMBER (R_LARCH_64_PCREL, 109)
+RELOC_NUMBER (R_LARCH_ALIGN_MAX, 110)
+
END_RELOC_NUMBERS (R_LARCH_count)
/* Processor specific flags for the ELF header e_flags field. */
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-max.dd b/ld/testsuite/ld-loongarch-elf/relax-align-max.dd
new file mode 100644
index 00000000000..0dd739ffc4a
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-align-max.dd
@@ -0,0 +1,4 @@
+#...
+.*pcaddi.*
+.*pcaddi.*
+#pass
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-max.s b/ld/testsuite/ld-loongarch-elf/relax-align-max.s
new file mode 100644
index 00000000000..2e829392fd6
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relax-align-max.s
@@ -0,0 +1,6 @@
+ .text
+.L1:
+ la.local $t0, .L1
+ # If skipping more bytes than 4, then the alignment is not done at all.
+ .align 4, , 4
+ la.local $t0, .L1
diff --git a/ld/testsuite/ld-loongarch-elf/relax.exp b/ld/testsuite/ld-loongarch-elf/relax.exp
index 24d79ed5c20..a4bfd0fe0c7 100644
--- a/ld/testsuite/ld-loongarch-elf/relax.exp
+++ b/ld/testsuite/ld-loongarch-elf/relax.exp
@@ -130,6 +130,20 @@ if [istarget loongarch64-*-*] {
] \
]
+ run_ld_link_tests \
+ [list \
+ [list \
+ "loongarch relax-align-max" \
+ "-e 0x0 -z relro" "" \
+ "--no-warn" \
+ {relax-align-max.s} \
+ [list \
+ [list objdump -d relax-align-max.dd] \
+ ] \
+ "relax-align-max" \
+ ] \
+ ]
+
set objdump_flags "-s -j .data"
run_ld_link_tests \
[list \
--
2.36.0
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-11-28 3:56 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-28 3:56 [PATCH] LoongArch: Add R_LARCH_ALIGN_MAX relocation mengqinggang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).