diff options
-rw-r--r-- | bfd/elfnn-loongarch.c | 71 | ||||
-rw-r--r-- | bfd/elfxx-loongarch.c | 10 | ||||
-rw-r--r-- | gas/config/tc-loongarch.c | 20 | ||||
-rw-r--r-- | gas/config/tc-loongarch.h | 4 | ||||
-rw-r--r-- | gas/testsuite/gas/loongarch/relax_align.d | 46 | ||||
-rw-r--r-- | gas/testsuite/gas/loongarch/relax_align.s | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/anno-sym.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/anno-sym.d | 7 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/anno-sym.l | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/anno-sym.s | 13 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/relax-align.dd | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/relax-align.s | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-loongarch-elf/relax.exp | 2 |
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] \ |