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?
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.