[LLVMbugs] [Bug 18019] New: ARM integrated assembler generates incorrect nop opcode when switching from arm to thumb mode

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Thu Nov 21 17:24:25 PST 2013


http://llvm.org/bugs/show_bug.cgi?id=18019

            Bug ID: 18019
           Summary: ARM integrated assembler generates incorrect nop
                    opcode when switching from arm to thumb mode
           Product: tools
           Version: trunk
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: normal
          Priority: P
         Component: llc
          Assignee: unassignedbugs at nondot.org
          Reporter: dpeixott at codeaurora.org
                CC: llvmbugs at cs.uiuc.edu
    Classification: Unclassified

I am seeing a problem with the way nops are emitted in the integrated assembler
for ARM. When switching from arm to thumb mode in an assembly file we still
emit the arm nop opcode.  Look at this small example:

$ cat align.s
.syntax unified
.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
t.o:    file format ELF32-arm

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 ARMAsmBackend class is responsible for emitting these nops. It keeps track
of whether it should emit arm or thumb nop. The first problem is that
MCElfStreamer does not pass on the `.code 16` directive to the ARMAsmBackend
class (using handleAssemblerFlag). In the example above we start assembling in
arm mode (because of the -triple) and so the ARMAsmBackend always thinks we are
in arm mode and it emits the wrong opcode.

We actually can assemble this example correctly for darwin because the
MCMachOStreamer does pass on the directives. It looks like we need to modify
the MCElfStreamer to pass the assembler directives down to the ARMAsmBackend to
match the behavior of the MCMachOStreamer.

Unfortunately, this change will not solve the full problem, even though the
integrated assembler works correctly for MachO in this example:

$ llvm-mc -triple armv7-apple-darwin align.s -filetype=obj -o t.o &&
llvm-objdump -triple thumbv7 -d t.o
t.o:    file format Mach-O arm

Disassembly of section __TEXT,__text:
foo:
       0:       00 44                                           add     r0,
r0
       2:       00 bf                                           nop
       4:       00 bf                                           nop
       6:       00 bf                                           nop
       8:       00 44                                           add     r0,
r0


The problem is that the nops are written after the assembly is complete when it
writes the MCAlignFragment to the output. The ARMAsmBackend writes nops using
the last mode it knew about. So it can write bad nop data if the nops are in a
location that is a mode that does not match the bit stored in the backend. We
can see the problem by simply adding a `.code 32` directive to the end of the
example:

$ echo ".code 32" >> align.s
$ llvm-mc -triple armv7-apple-darwin align.s -filetype=obj -o t.o &&
llvm-objdump -triple thumbv7 -d t.o
t.o:    file format Mach-O arm

Disassembly of section __TEXT,__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


It seems that the MCAlignFragment needs to know if it is aligning in thumb mode
or in arm mode. How should we solve this problem? Should we store the current
mode in the fragment when assembling the file and use that mode when writing
nop data?

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20131122/8ead6c96/attachment.html>


More information about the llvm-bugs mailing list