From 7918b183ec7844b7d54a2164a177898e2db59f2e Mon Sep 17 00:00:00 2001 From: mengqinggang Date: Tue, 19 Mar 2024 21:09:12 +0800 Subject: LoongArch: gas: Ignore .align if it is at the start of a section Ignore .align if it is at the start of a section and the alignment can be divided by the section alignment, the section alignment can ensure this .align has a correct alignment. --- gas/config/tc-loongarch.c | 134 ++++++++++++++++++---- gas/testsuite/gas/loongarch/relax-align-first.d | 12 ++ gas/testsuite/gas/loongarch/relax-align-first.s | 7 ++ ld/testsuite/ld-loongarch-elf/relax-align-first.d | 15 +++ ld/testsuite/ld-loongarch-elf/relax-align-first.s | 13 +++ ld/testsuite/ld-loongarch-elf/relax.exp | 1 + 6 files changed, 157 insertions(+), 25 deletions(-) create mode 100644 gas/testsuite/gas/loongarch/relax-align-first.d create mode 100644 gas/testsuite/gas/loongarch/relax-align-first.s create mode 100644 ld/testsuite/ld-loongarch-elf/relax-align-first.d create mode 100644 ld/testsuite/ld-loongarch-elf/relax-align-first.s diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c index 6b1a897..d156477 100644 --- a/gas/config/tc-loongarch.c +++ b/gas/config/tc-loongarch.c @@ -128,6 +128,11 @@ static bool call36 = 0; #define RELAX_BRANCH_ENCODE(x) \ (BFD_RELOC_LARCH_B16 == (x) ? RELAX_BRANCH_16 : RELAX_BRANCH_21) +#define ALIGN_MAX_ADDEND(n, max) ((max << 8) | n) +#define ALIGN_MAX_NOP_BYTES(addend) ((1 << (addend & 0xff)) - 4) +#define FRAG_AT_START_OF_SECTION(frag) \ + (0 == frag->fr_address && 0 == frag->fr_fix) + enum options { OPTION_IGNORE = OPTION_MD_BASE, @@ -1647,10 +1652,32 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) } } +/* Estimate the size of a frag before relaxing. */ + int -md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, - asection *segtype ATTRIBUTE_UNUSED) +md_estimate_size_before_relax (fragS *fragp, asection *sec) { + /* align pseudo instunctions. */ + if (rs_align_code == fragp->fr_subtype) + { + offsetT nop_bytes; + if (NULL == fragp->fr_symbol) + nop_bytes = fragp->fr_offset; + else + nop_bytes = ALIGN_MAX_NOP_BYTES (fragp->fr_offset); + + /* Normally, nop_bytes should be >= 4. */ + gas_assert (nop_bytes > 0); + + if (FRAG_AT_START_OF_SECTION (fragp) + && 0 == ((1 << sec->alignment_power) % (nop_bytes + 4))) + return (fragp->fr_var = 0); + else + return (fragp->fr_var = nop_bytes); + } + + /* branch instructions and other instructions. + branch instructions may become 8 bytes after relaxing. */ return (fragp->fr_var = 4); } @@ -1767,8 +1794,7 @@ bool loongarch_frag_align_code (int n, int max) { char *nops; - symbolS *s; - expressionS ex; + symbolS *s = NULL; bfd_vma insn_alignment = 4; bfd_vma bytes = (bfd_vma) 1 << n; @@ -1783,8 +1809,6 @@ loongarch_frag_align_code (int n, int max) if (!LARCH_opts.relax) return false; - nops = frag_more (worst_case_bytes); - /* If max <= 0, ignore max. If max >= worst_case_bytes, max has no effect. Similar to gas/write.c relax_segment function rs_align_code case: @@ -1792,20 +1816,20 @@ loongarch_frag_align_code (int n, int max) if (max > 0 && (bfd_vma) max < worst_case_bytes) { s = symbol_find (now_seg->name); - ex.X_add_symbol = s; - ex.X_op = O_symbol; - ex.X_add_number = (max << 8) | n; - } - else - { - ex.X_op = O_constant; - ex.X_add_number = worst_case_bytes; + worst_case_bytes = ALIGN_MAX_ADDEND (n, max); } - loongarch_make_nops (nops, worst_case_bytes); + frag_grow (worst_case_bytes); + /* Use relaxable frag for .align. + If .align at the start of section, do nothing. Section alignment can + ensure correct alignment. + If .align is not at the start of a section, reserve NOP instructions + and R_LARCH_ALIGN relocation. */ + nops = frag_var (rs_machine_dependent, worst_case_bytes, worst_case_bytes, + rs_align_code, s, worst_case_bytes, NULL); - fix_new_exp (frag_now, nops - frag_now->fr_literal, 0, - &ex, false, BFD_RELOC_LARCH_ALIGN); + /* Default write NOP for aligned bytes. */ + loongarch_make_nops (nops, worst_case_bytes); /* 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. @@ -1963,8 +1987,7 @@ loongarch_relaxed_branch_length (fragS *fragp, asection *sec, int update) } int -loongarch_relax_frag (asection *sec ATTRIBUTE_UNUSED, - fragS *fragp ATTRIBUTE_UNUSED, +loongarch_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) { if (RELAX_BRANCH (fragp->fr_subtype)) @@ -1973,6 +1996,27 @@ loongarch_relax_frag (asection *sec ATTRIBUTE_UNUSED, fragp->fr_var = loongarch_relaxed_branch_length (fragp, sec, true); return fragp->fr_var - old_var; } + else if (rs_align_code == fragp->fr_subtype) + { + offsetT nop_bytes; + if (NULL == fragp->fr_symbol) + nop_bytes = fragp->fr_offset; + else + nop_bytes = ALIGN_MAX_NOP_BYTES (fragp->fr_offset); + + /* Normally, nop_bytes should be >= 4. */ + gas_assert (nop_bytes > 0); + + offsetT old_var = fragp->fr_var; + /* If .align at the start of a section, do nothing. Section alignment + * can ensure correct alignment. */ + if (FRAG_AT_START_OF_SECTION (fragp) + && 0 == ((1 << sec->alignment_power) % (nop_bytes + 4))) + fragp->fr_var = 0; + else + fragp->fr_var = nop_bytes; + return fragp->fr_var - old_var; + } return 0; } @@ -2048,13 +2092,53 @@ loongarch_convert_frag_branch (fragS *fragp) fragp->fr_fix += fragp->fr_var; } -/* Relax a machine dependent frag. This returns the amount by which - the current size of the frag should change. */ +/* Relax .align frag. */ + +static void +loongarch_convert_frag_align (fragS *fragp, asection *sec) +{ + bfd_byte *buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix; + + offsetT nop_bytes; + if (NULL == fragp->fr_symbol) + nop_bytes = fragp->fr_offset; + else + nop_bytes = ALIGN_MAX_NOP_BYTES (fragp->fr_offset); + + /* Normally, nop_bytes should be >= 4. */ + gas_assert (nop_bytes > 0); + + if (!(FRAG_AT_START_OF_SECTION (fragp) + && 0 == ((1 << sec->alignment_power) % (nop_bytes + 4)))) + { + expressionS exp; + exp.X_op = O_symbol; + exp.X_add_symbol = fragp->fr_symbol; + exp.X_add_number = fragp->fr_offset; + + fixS *fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, + nop_bytes, &exp, false, BFD_RELOC_LARCH_ALIGN); + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + + buf += nop_bytes; + } + + gas_assert (buf == (bfd_byte *)fragp->fr_literal + + fragp->fr_fix + fragp->fr_var); + + fragp->fr_fix += fragp->fr_var; +} + +/* Relax a machine dependent frag. */ void -md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED, - fragS *fragp) +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) { - gas_assert (RELAX_BRANCH (fragp->fr_subtype)); - loongarch_convert_frag_branch (fragp); + gas_assert (RELAX_BRANCH (fragp->fr_subtype) + || rs_align_code == fragp->fr_subtype); + if (RELAX_BRANCH (fragp->fr_subtype)) + loongarch_convert_frag_branch (fragp); + else if (rs_align_code == fragp->fr_subtype) + loongarch_convert_frag_align (fragp, asec); } diff --git a/gas/testsuite/gas/loongarch/relax-align-first.d b/gas/testsuite/gas/loongarch/relax-align-first.d new file mode 100644 index 0000000..ec0698b --- /dev/null +++ b/gas/testsuite/gas/loongarch/relax-align-first.d @@ -0,0 +1,12 @@ +#as: +#objdump: -dr + +.*:[ ]+file format .* + + +Disassembly of section .text: +0* <.text>: +[ ]+0:[ ]+4c000020[ ]+ret +Disassembly of section abc: +0* : +[ ]+0:[ ]+4c000020[ ]+ret diff --git a/gas/testsuite/gas/loongarch/relax-align-first.s b/gas/testsuite/gas/loongarch/relax-align-first.s new file mode 100644 index 0000000..a4c3d68 --- /dev/null +++ b/gas/testsuite/gas/loongarch/relax-align-first.s @@ -0,0 +1,7 @@ +.text +.align 3 +ret + +.section "abc", "ax" +.align 4, ,4 +ret diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-first.d b/ld/testsuite/ld-loongarch-elf/relax-align-first.d new file mode 100644 index 0000000..9a4fad8 --- /dev/null +++ b/ld/testsuite/ld-loongarch-elf/relax-align-first.d @@ -0,0 +1,15 @@ +#ld: -e0 +#objdump: -d + +.*:[ ]+file format .* + + +Disassembly of section aaa: +0000000120000078 : +[ ]+120000078:[ ]+4c000020[ ]+ret +Disassembly of section bbb: +0000000120000080 : +[ ]+120000080:[ ]+4c000020[ ]+ret +Disassembly of section ccc: +0000000120000090 <__bss_start-0x4004>: +[ ]+120000090:[ ]+4c000020[ ]+ret diff --git a/ld/testsuite/ld-loongarch-elf/relax-align-first.s b/ld/testsuite/ld-loongarch-elf/relax-align-first.s new file mode 100644 index 0000000..0a9115b --- /dev/null +++ b/ld/testsuite/ld-loongarch-elf/relax-align-first.s @@ -0,0 +1,13 @@ +# If .align at the start of a section, do not add NOP instructions +# and do not emit R_LARCH_ALIGN relocations. +# Section alignment can ensure correct alignment. +.section "aaa", "ax" +ret + +.section "bbb", "ax" +.align 3 +ret + +.section "ccc", "ax" +.align 4, ,4 +ret diff --git a/ld/testsuite/ld-loongarch-elf/relax.exp b/ld/testsuite/ld-loongarch-elf/relax.exp index ed71fb4..2345214 100644 --- a/ld/testsuite/ld-loongarch-elf/relax.exp +++ b/ld/testsuite/ld-loongarch-elf/relax.exp @@ -20,6 +20,7 @@ # if [istarget loongarch64-*-*] { + run_dump_test "relax-align-first" if [isbuild loongarch64-*-*] { set testname "loongarch relax .exe build" -- cgit v1.1