@@ -3852,11 +3852,21 @@ loongarch_relax_align (bfd *abfd, asection *sec,
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 alignment = 1, pos, max = 0, addend;
- symval -= rel->r_addend;
+ int index = ELFNN_R_SYM (rel->r_info);
+ if (index > 0)
+ {
+ alignment = 1 << (rel->r_addend & 0xff);
+ max = rel->r_addend >> 8;
+ }
+ else
+ while (alignment <= rel->r_addend)
+ alignment *= 2;
+
+ addend = alignment - 4;
+
+ symval -= addend;
bfd_vma aligned_addr = ((symval - 1) & ~(alignment - 1)) + alignment;
bfd_vma nop_bytes = aligned_addr - symval;
@@ -3864,22 +3874,25 @@ loongarch_relax_align (bfd *abfd, asection *sec,
sec->sec_flg0 = true;
/* Make sure there are enough NOPs to actually achieve the alignment. */
- if (rel->r_addend < nop_bytes)
+ if (addend < 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) nop_bytes, (int64_t) alignment, (int64_t) addend);
bfd_set_error (bfd_error_bad_value);
return false;
}
- /* Delete the reloc. */
rel->r_info = ELFNN_R_INFO (0, R_LARCH_NONE);
+ if (max > 0 && 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 (nop_bytes == addend)
return true;
/* Write as many LOONGARCH NOPs as we need. */
@@ -3888,7 +3901,7 @@ loongarch_relax_align (bfd *abfd, asection *sec,
/* Delete the excess NOPs. */
return loongarch_relax_delete_bytes (abfd, sec, rel->r_offset + nop_bytes,
- rel->r_addend - nop_bytes, link_info);
+ addend - nop_bytes, link_info);
}
static bool
@@ -3939,6 +3952,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;
@@ -3950,7 +3964,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;
@@ -4005,12 +4019,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. */
+ 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)
@@ -1648,12 +1648,14 @@ 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;
/* If we are moving to a smaller alignment than the instruction size, then no
@@ -1667,8 +1669,13 @@ 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 = colon (".Lla-relax-align");
+ ex.X_add_symbol = s;
+
+ ex.X_op = O_symbol;
+ ex.X_add_number = (max << 8) | n;
loongarch_make_nops (nops, worst_case_bytes);
@@ -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; \
}
@@ -1,4 +1,4 @@
-#as:
+#as: --no-warn
#objdump: -dr
#skip: loongarch32-*-*
@@ -7,20 +7,31 @@
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\*
+.* <.Lla-relax-align-0x14>:
+[ ]+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.*
+0000000000000014 <.Lla-relax-align>:
+[ ]+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\*
@@ -1,5 +1,7 @@
.text
-L1:
+.L1:
la.local $a0, L1
.align 4
la.local $a0, L1
+ .align 4, , 4
+ la.local $a0, L1
@@ -1,7 +1,8 @@
#...
.*pcaddi.*
-.*pcaddi.*
.*nop.*
+.*pcaddi.*
.*nop.*
-.*0:.*pcaddi.*
+.*pcaddi.*
+.*pcaddi.*
#pass
@@ -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
@@ -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] \