From 7266731f9edef92e459084c323e67a7b918ee7a8 Mon Sep 17 00:00:00 2001 From: David Peixotto Date: Mon, 25 Nov 2013 19:11:13 +0000 Subject: [PATCH] ARM integrated assembler generates incorrect nop opcode This patch fixes a bug in the assembler that was causing bad code to be emitted. When switching modes in an assembly file (e.g. arm to thumb mode) we would always emit the opcode from the original mode. Consider this small example: $ cat align.s .code 16 foo: add r0, r0 .align 3 add r0, r0 $ llvm-mc -triple armv7-none-linux align.s -filetype=obj -o t.o $ llvm-objdump -triple thumbv7 -d t.o Disassembly of section .text: foo: 0: 00 44 add r0, r0 2: 00 f0 20 e3 blx #4195904 6: 00 00 movs r0, r0 8: 00 44 add r0, r0 This shows that we have actually emitted an arm nop (e320f000) instead of a thumb nop. Unfortunately, this encodes to a thumb branch which causes bad things to happen when compiling assembly code with align directives. The fix is to notify the ARMAsmBackend when we switch mode. The MCMachOStreamer was already doing this correctly. This patch makes the same change for the MCElfStreamer. There is still a bug in the way nops are emitted for alignment because the MCAlignment fragment does not store the correct mode. The ARMAsmBackend will emit nops for the last mode it knew about. In the example above, we still generate an arm nop if we add a `.code 32` to the end of the file. PR18019 llvm-svn: 195677 --- llvm/lib/MC/MCELFStreamer.cpp | 4 ++++ llvm/test/MC/ARM/align_arm_2_thumb.s | 15 +++++++++++++++ llvm/test/MC/ARM/align_thumb_2_arm.s | 15 +++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 llvm/test/MC/ARM/align_arm_2_thumb.s create mode 100644 llvm/test/MC/ARM/align_thumb_2_arm.s diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp index 3be71ce9b61e..e806cb9f1c94 100644 --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELF.h" @@ -96,6 +97,9 @@ void MCELFStreamer::EmitDebugLabel(MCSymbol *Symbol) { } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + // Let the target do whatever target specific stuff it needs to do. + getAssembler().getBackend().handleAssemblerFlag(Flag); + // Do any generic stuff we need to do. switch (Flag) { case MCAF_SyntaxUnified: return; // no-op here. case MCAF_Code16: return; // Change parsing mode; no-op here. diff --git a/llvm/test/MC/ARM/align_arm_2_thumb.s b/llvm/test/MC/ARM/align_arm_2_thumb.s new file mode 100644 index 000000000000..120e96480b5c --- /dev/null +++ b/llvm/test/MC/ARM/align_arm_2_thumb.s @@ -0,0 +1,15 @@ +@ RUN: llvm-mc -triple armv7-none-linux -filetype=obj -o %t.o %s +@ RUN: llvm-objdump -triple thumbv7-none-linux -d %t.o | FileCheck --check-prefix=ARM_2_THUMB %s + +@ RUN: llvm-mc -triple armv7-apple-darwin -filetype=obj -o %t_darwin.o %s +@ RUN: llvm-objdump -triple thumbv7-apple-darwin -d %t_darwin.o | FileCheck --check-prefix=ARM_2_THUMB %s + +.syntax unified +.code 16 +@ ARM_2_THUMB-LABEL: foo +foo: + add r0, r0 +.align 3 +@ ARM_2_THUMB: 2: 00 bf nop + add r0, r0 + diff --git a/llvm/test/MC/ARM/align_thumb_2_arm.s b/llvm/test/MC/ARM/align_thumb_2_arm.s new file mode 100644 index 000000000000..328bfabce65c --- /dev/null +++ b/llvm/test/MC/ARM/align_thumb_2_arm.s @@ -0,0 +1,15 @@ +@ RUN: llvm-mc -triple thumbv7-none-linux -filetype=obj -o %t.o %s +@ RUN: llvm-objdump -triple armv7-none-linux -d %t.o | FileCheck --check-prefix=THUMB_2_ARM %s + +@ RUN: llvm-mc -triple thumbv7-apple-darwin -filetype=obj -o %t_darwin.o %s +@ RUN: llvm-objdump -triple armv7-apple-darwin -d %t_darwin.o | FileCheck --check-prefix=THUMB_2_ARM %s + +.syntax unified +.code 32 +@ THUMB_2_ARM-LABEL: foo +foo: + add r0, r0 +.align 3 +@ THUMB_2_ARM: 4: 00 f0 20 e3 nop + add r0, r0 + -- GitLab