RISC-V: Avoid emitting invalid instructions in mixed RVC/no-RVC code
authorPalmer Dabbelt <palmer@dabbelt.com>
Fri, 16 Jun 2017 21:33:16 +0000 (14:33 -0700)
committerPalmer Dabbelt <palmer@dabbelt.com>
Thu, 7 Sep 2017 16:45:40 +0000 (09:45 -0700)
commited0816bd936492aa7dc00e4fbbf8ff8de1253854
tree292b683500b1059ae36ef0288a5a786e38e218f7
parent9eb7b0acb54e18e7cbca196a8bdb320844a858b3
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.
gas/ChangeLog
gas/config/tc-riscv.c