Search code examples
assemblyarmcompiler-warningsthumb

Compile-time register checks for Thumb-2 code


In Thumb-2 code, it is not possible to use registers 8-15 in most instructions, while this is possible in ARM code. Hence, the following assembly gives a runtime Illegal Instruction error:

        .syntax unified
        .fpu    vfp
        .thumb
        .text
        .globl  main
main:
        str r12,[sp,#-4]    @ r12 is too high, source register is 3 bits wide

However, I do not get a warning at compile time, even though I use -Wall:

pi@rasppi:~/ctests$ arm-linux-gnueabihf-as -Wall -o high.o high.s 
ARM GAS  high.s                         page 1


   1                                    .syntax unified
   2                                    .fpu    vfp
   3                                    .thumb
   4                                    .text
   5                                    .globl  main
   6                            main:
   7 0000 4DF804CC                      str r12,[sp,#-4]
pi@rasppi:~/ctests$ arm-linux-gnueabihf-gcc -Wall -o high high.o 
pi@rasppi:~/ctests$ ./high 
Illegal instruction
pi@rasppi:~/ctests$ file high
high: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=c9d90a7d6386bf97a18f9da87a7b2ce422402659, not stripped

Is there any tool that can be used to check for illegal instructions at compile time?


Solution

  • One problem is that you have Thumb code at the symbol main, but haven't annotated that as a Thumb symbol. Thus the linker doesn't set the lsb of the symbol address, so at runtime the call gets there in ARM state and subsequently chokes on a Thumb encoding. To solve that, you need to add the .thumb_func annotation:

    ...
    .globl main
    .thumb_func
    main:
    ...
    

    With that in place, it's highly likely to still crash with either an undefined instruction or a segfault when you run off the end of that code into whatever code/data/unmapped page follows. You need to actually return from main.

    Your initial assumption is incorrect, because if it were a problem with register usage as you suspect, it wouldn't even assemble. The "tool that can be used to check for illegal instructions at compile time" is the assembler.