From ed0816bd936492aa7dc00e4fbbf8ff8de1253854 Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Fri, 16 Jun 2017 14:33:16 -0700 Subject: [PATCH] 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 : 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 : 80000004: 00000013 nop 80000008: 00018193 mv gp,gp gas/ChangeLog 2017-09-07 Palmer Dabbelt * config/tc-riscv.c (riscv_frag_align_code): Emit the entire alignment sequence inside R_RISCV_ALIGN. --- gas/ChangeLog | 5 +++++ gas/config/tc-riscv.c | 25 ++++++++----------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index b52259f8d1..5dc06f5e5c 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2017-09-07 Palmer Dabbelt + + * config/tc-riscv.c (riscv_frag_align_code): Emit the entire + alignment sequence inside R_RISCV_ALIGN. + 2017-09-05 Alexander Fedotov Edmar Wienskoski 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; } -- 2.34.1