I'm writing an ARMv7E-M Thumb2 binary analysis tool, and decoding the instruction stream manually.
arm-gcc, invoked with the -mcpu=cortex-m4 and -mfloat-abi=hard flags, emitted the following instruction while compiling my C code:
40280: eeb8 7a47 vcvt.f32.u32 s14, s14
I can't find this specific encoding in the ARMv7-M Architecture Reference Manual, though.
The closest I can find is A7.7.226 VCVT, pictured below, but bit 1 of word 0 is set to 1 in the specification, but 0 in eeb8.
Which instruction and encoding is the compiler selecting for eeb8 7a47? Where can I find the documentation for this specific encoding?
Uhh, well, a different version of the ARMv7-M ARM has an encoding that matches what the compiler is emitting. I'm not sure yet what the difference is, but I'm posting the matching version here and marking it as an answer.
Related
I have a maybe trivial question, but what is a difference between Thumb (-mthumb) and Arm (-marm) state and why most of the tutorials recommend to use Thumb state?
I am curious what exactly does it mean? What it is related to?
Best!
I would suggest to read those two articles, one from Arm, Instruction Set Architecture (-marm means that GCC will generate arm32/A32 code, -mthumb means that it will generate thumb/T32 one), and this research paper, Profile Guided Selection of ARM and ThumbInstructions.
Basically, the two instruction sets differ in the set of instructions available as well as their encoding. You should therefore get a smaller and faster executable by using thumb/T32 than by using arm/A32.
This is the reason why most of the tutorials recommend to use the thumb/T32 instruction set.
I am trying to learn function call grammar in arm architecture and i compiled same code for user mode app and loadable kernel module. in attached picture you can see disassembly result for same function in two different mode. i am curious about reason of this difference.
You have compiled the code with wildly different options. The first is ARM (32bit only) and the 2nd is Thumb2 (mixed 16/32bit); see hex opcodes at the side. Thumb2 used the first 8 registers in a compact way (16bit encodings) so the call interface is different. Ie, fp is r7 versus r12. This is why you are seeing different call sequences for the same code.
Also, the first has profiling enabled (why __gnu_mcount_nc is inserted).
It really has nothing to do with 'kernel' versus 'user' code. It is possible to compile user code with similar option as the kernel uses. There are many gcc command line options which affect the 'call interface' (search AAPCS for more information and the gcc ARM options help).
Related: ARM Link and frame pointer
I'm most interested in extracting the architecture version, i.e. v5, v5T, etc. I've been referencing Elf for the ARM Architecture Section 4.3.6 Build Attributes which has been helpful in getting me up to this point. I can find the start of the .ARM.attributes section and can parse the first key parts of the information: Format-version, Section-length, and vendor-name + null byte, no problem. I get a little lost after that. Below is a snapshot I ran using hexdump -vC on an elf compiled with arm-linux-gnueabi-gcc -march=armv5t -O myprog.c -o myprog for a ARMv5T architecture. The start of the section is 77f0b.
We can see:
Format-version: A
Section-length: 0x29
Vendor-name: "aeabi"
Obviously, 5T is available in ASCII form at 77f1C, but I'm not sure how to interpret the tag I need to parse to get that value.
Note: Yes, I understand there are tools that I can use to do this, but I need to extract the information in the application I am writing. It already parses the necessary information to make it this far.
Bonus question: Does PowerPC have similar tags? I couldn't find any supporting documentation.
These tags are documented in the Addenda to, and Errata in, the ABI for the ARM Architecture. For example, under The target-related-attributes (section 3.3.5.2), we learn that Tag_CPU_arch has value 6, which immediately follows Tag_CPU_name (5, preceding the 5T) in your dump. Its argument is 3, which again corresponds to ARM v5T, according to the table in the document. The next tag is Tag_ARM_ISA_use (8) with an argument of 1, meaning The user intended that this entity could use ARM instructions (whatever this means), and so on.
Note that the integers are encoded in uleb128 format. This encoding is described in the DWARF standard (in section 7.6 of DWARF 3). Basically, it's base-128, little endian, and you need to keep reading while the MSB is set.
I have rootfs and klibc file systems. I am creating make rules and some developers have an older compiler without inter-networking.note1 I am trying to verify that all the files get built with arm only when a certain version of the compiler is detected. I have re-built the tree's several times. I was using readelf -A and looking for Tag_THUMB_ISA_use: Thumb-1, but this seem to be in arm only code (but was built with the interworking compiler) as well as thumb code. I can manually run objdump -S and examine the assembler to determine what instruction set is in use.
However, it would be much easier if I had a script/tool predicate so that find, etc can be used to search through the shadow file systems to look for binaries that may have been missed. I thought that some of this information would be in the ELF header and accessible via objdump or readelf, but I haven't found anything reliable.
Specifically I am looking for,
Compiled 'C' that wouldn't run without a CONFIG_ARM_THUMB Linux system.
make rules that use 'C' compiler flags that choke a non-thumb compilers.
note1: Interworking allow easy switching between thumb and arm modes, and the compiler will automatically generate code to support calling from either mode.
The readelf -A output doesn't describe the elf contents. It just describes the capabilities of the processor and or system that is expected or fed to the compiler. As I have an ARM926 CPU which is an ARMV5TEJ processor, gcc/ld will always set Tag_THUMB_ISA_use: Thumb-1 as it just means that ARMV5TEJ is recognized as being Thumb-1 capable. It says nothing about the code itself.
Examining the Linux arch/arm/kernel/elf.c routine elf_check_arch() shows a check for x->e_entry & 1. This leads to the following script,
readelf -h $1 | grep -q Entry.*[13579bdf]$
Ie, just look at the initial ELF entry value and see if the low bit is set. This is a fast check that fits the spirit of what I am looking for. unixsmurf has a good point that the code inside any ELF can mix and match ARM and Thumb. This maybe ok, if the program dynamically ids the CPU and selects an appropriate routine. Ie, just the presence of a Thumb instruction doesn't mean that code will execute.
Just looking at the entry value does determine which gcc compiler flags were used, at least for gcc versions 4.6 to 4.7.
Since thumb and arm sequences can be freely interchanged within an object file, even within the same section, plain ELF header inspection is not going to help you whether a file includes Thumb instructions or not.
A slightly roundabout and still not 100% foolproof way would be to use readelf -r and check if the output contains "R_ARM_THM", indicating a relocation for thumb.
I am compiling on a 64 bit architecture with the intel C compiler. The same code built fine on a different 64 bit intel architecture.
Now when I try to build the binaries, I get a message "Skipping incompatible ../../libtime.a" or some such thing, that is indicating the libtime.a that I archived (from some object files I compiled) is not compatible. I googled and it seemed like this was usually the result of a 32->64 bit changeover or something like that, but the intel C compiler doesnt seem to support a -64 or some other memory option at compile time. How do I troubleshoot and fix this error?
You cannot mix 64-bit and 32-bit compiled code. Config instructions for Linux are here.
You need to determine the target processor of both the library and the new code you are building. This can be done in a few ways but the easiest is:
$ objdump -f ../../libtime.a otherfile.o
For libtime this will probably print out bunches of things, but they should all have the same target processor. Make sure that otherfile.o (which you should substitute one of your object files for) also has the same architecture.
gcc has the -m32 and -m64 flags for switching from the default target to a similar processor with the different register and memory width (commonly x86 and x86_64), which the Intel C compiler may also have.
If this has not been helpful then you should include the commands (with all flags) used to compile everything and also information about the systems that each command was being run on.