aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/elfnn-loongarch.c71
-rw-r--r--bfd/elfxx-loongarch.c10
-rw-r--r--gas/config/tc-loongarch.c20
-rw-r--r--gas/config/tc-loongarch.h4
-rw-r--r--gas/testsuite/gas/loongarch/relax_align.d46
-rw-r--r--gas/testsuite/gas/loongarch/relax_align.s4
-rw-r--r--ld/testsuite/ld-elf/anno-sym.d2
-rw-r--r--ld/testsuite/ld-loongarch-elf/anno-sym.d7
-rw-r--r--ld/testsuite/ld-loongarch-elf/anno-sym.l4
-rw-r--r--ld/testsuite/ld-loongarch-elf/anno-sym.s13
-rw-r--r--ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp1
-rw-r--r--ld/testsuite/ld-loongarch-elf/relax-align.dd5
-rw-r--r--ld/testsuite/ld-loongarch-elf/relax-align.s5
-rw-r--r--ld/testsuite/ld-loongarch-elf/relax.exp2
14 files changed, 134 insertions, 60 deletions
diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 87eb65a..faffe27 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -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)
diff --git a/bfd/elfxx-loongarch.c b/bfd/elfxx-loongarch.c
index d93b790..679b79f 100644
--- a/bfd/elfxx-loongarch.c
+++ b/bfd/elfxx-loongarch.c
@@ -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. */
diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index 367a0b6..9b912da 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -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);
diff --git a/gas/config/tc-loongarch.h b/gas/config/tc-loongarch.h
index 4afa384..194ee10 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 1810eb4..2cc6c86 100644
--- a/gas/testsuite/gas/loongarch/relax_align.d
+++ b/gas/testsuite/gas/loongarch/relax_align.d
@@ -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\*
diff --git a/gas/testsuite/gas/loongarch/relax_align.s b/gas/testsuite/gas/loongarch/relax_align.s
index 3880d78..c0177c8 100644
--- a/gas/testsuite/gas/loongarch/relax_align.s
+++ b/gas/testsuite/gas/loongarch/relax_align.s
@@ -1,5 +1,7 @@
.text
-L1:
+.L1:
la.local $a0, L1
.align 4
la.local $a0, L1
+ .align 4, , 4
+ la.local $a0, L1
diff --git a/ld/testsuite/ld-elf/anno-sym.d b/ld/testsuite/ld-elf/anno-sym.d
index 9e53c4a..f1ce21f 100644
--- a/ld/testsuite/ld-elf/anno-sym.d
+++ b/ld/testsuite/ld-elf/anno-sym.d
@@ -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
index 0000000..a58f4a6
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/anno-sym.d
@@ -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
index 0000000..ee9611a
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/anno-sym.l
@@ -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
index 0000000..92016a8
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/anno-sym.s
@@ -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
+
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 1fc70d0..b43a518 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -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-*-*"] {
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align.dd b/ld/testsuite/ld-loongarch-elf/relax-align.dd
index 5fce225..37fdab1 100644
--- a/ld/testsuite/ld-loongarch-elf/relax-align.dd
+++ b/ld/testsuite/ld-loongarch-elf/relax-align.dd
@@ -1,7 +1,8 @@
#...
.*pcaddi.*
-.*pcaddi.*
.*nop.*
+.*pcaddi.*
.*nop.*
-.*0:.*pcaddi.*
+.*pcaddi.*
+.*pcaddi.*
#pass
diff --git a/ld/testsuite/ld-loongarch-elf/relax-align.s b/ld/testsuite/ld-loongarch-elf/relax-align.s
index 9617c02..66dfea8 100644
--- a/ld/testsuite/ld-loongarch-elf/relax-align.s
+++ b/ld/testsuite/ld-loongarch-elf/relax-align.s
@@ -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
diff --git a/ld/testsuite/ld-loongarch-elf/relax.exp b/ld/testsuite/ld-loongarch-elf/relax.exp
index 24d79ed..77323d8 100644
--- a/ld/testsuite/ld-loongarch-elf/relax.exp
+++ b/ld/testsuite/ld-loongarch-elf/relax.exp
@@ -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] \