@@ -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;
@@ -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;
}
@@ -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 *
@@ -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
@@ -8292,6 +8292,9 @@ ENUMX
ENUMX
BFD_RELOC_LARCH_64_PCREL
+ENUMX
+ BFD_RELOC_LARCH_ALIGN_MAX
+
ENUMDOC
LARCH relocations.
@@ -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.
@@ -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; \
}
@@ -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\*
@@ -1,5 +1,4 @@
.text
-L1:
la.local $a0, L1
.align 4
la.local $a0, L1
@@ -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. */
new file mode 100644
@@ -0,0 +1,4 @@
+#...
+.*pcaddi.*
+.*pcaddi.*
+#pass
new file mode 100644
@@ -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
@@ -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 \