RISC-V: Avoid emitting invalid instructions in mixed RVC/no-RVC code

When linking the following code

    .global _prog_start
    _prog_start:
            mv x1, x1
            mv x2, x2
    .align 2
    rvc_boundry:
    .option norvc
    .align 3
            mv x3, x3

we currently emit an invalid two-byte 0 instruction.  The actual output
code looks like

    0000000080000000 <_prog_start>:
        80000000:   8086                    mv      ra,ra
        80000002:   810a                    mv      sp,sp

    0000000080000004 <rvc_boundry>:
        80000004:   0000                    unimp
        80000006:   0001                    nop
        80000008:   00018193                mv      gp,gp

This ends up manifesting due to the two-byte compressed NOP that's
pessimisticly emitted by the ".align 2", which results in "rvc_boundry"
being 2-byte aligned.  frag_align_code() then goes and outputs a 2-byte
NOP (which is invalid in no-RVC mode) to align the code back to a 4-byte
boundry, which can't be relaxed away by the linker as it's not part of
the R_RISCV_RELAX relocation.

The fix is to just always emit the worst case possible alignment into
the output as a single R_RISCV_RELAX, which the linker will then fix up.

With this patch I get the expected code generation

    0000000080000000 <_prog_start>:
        80000000:   8086                    mv      ra,ra
        80000002:   810a                    mv      sp,sp

    0000000080000004 <rvc_boundry>:
        80000004:   00000013                nop
        80000008:   00018193                mv      gp,gp

gas/ChangeLog

2017-09-07  Palmer Dabbelt  <palmer@dabbelt.com>

        * config/tc-riscv.c (riscv_frag_align_code): Emit the entire
        alignment sequence inside R_RISCV_ALIGN.
This commit is contained in:
Palmer Dabbelt 2017-06-16 14:33:16 -07:00
parent 9eb7b0acb5
commit ed0816bd93
2 changed files with 13 additions and 17 deletions

View File

@ -1,3 +1,8 @@
2017-09-07 Palmer Dabbelt <palmer@dabbelt.com>
* config/tc-riscv.c (riscv_frag_align_code): Emit the entire
alignment sequence inside R_RISCV_ALIGN.
2017-09-05 Alexander Fedotov <alexander.fedotov@nxp.com>
Edmar Wienskoski <edmar.wienskoski@nxp.com

View File

@ -2274,30 +2274,21 @@ bfd_boolean
riscv_frag_align_code (int n)
{
bfd_vma bytes = (bfd_vma) 1 << n;
bfd_vma min_text_alignment_order = riscv_opts.rvc ? 1 : 2;
bfd_vma min_text_alignment = (bfd_vma) 1 << min_text_alignment_order;
/* First, get back to minimal alignment. */
frag_align_code (min_text_alignment_order, 0);
bfd_vma worst_case_bytes = bytes - 2;
char *nops = frag_more (worst_case_bytes);
expressionS ex;
/* When not relaxing, riscv_handle_align handles code alignment. */
if (!riscv_opts.relax)
return FALSE;
if (bytes > min_text_alignment)
{
bfd_vma worst_case_bytes = bytes - min_text_alignment;
char *nops = frag_more (worst_case_bytes);
expressionS ex;
ex.X_op = O_constant;
ex.X_add_number = worst_case_bytes;
ex.X_op = O_constant;
ex.X_add_number = worst_case_bytes;
riscv_make_nops (nops, worst_case_bytes);
riscv_make_nops (nops, worst_case_bytes);
fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
&ex, FALSE, BFD_RELOC_RISCV_ALIGN);
}
fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
&ex, FALSE, BFD_RELOC_RISCV_ALIGN);
return TRUE;
}