I try to build a small disassembler for ARM, and I would like to know how do objdump
manage to sort out the normal mode instructions (32-bits instruction wide) from the thumb mode instructions (16-bits instruction wide) without having to look at the t
flag in the CPSR.
But first, let us build a small example and make some experiments on it.
I wrote this small piece of ARM assembly (gas
syntax) as basis example:
.arm
mov fp, #0
moveq r1, r0
.thumb
mov r0, #0
mov fp, r0
Then, I cross-compiled it like this:
$> arm-none-eabi-gcc -Wall -Wextra -mlittle-endian -c -o arm_sample arm_sample.s
And, here is the output of objdump
on the ARM object file:
$> objdump -d ./arm32_mov
./arm32_mov: file format elf32-littlearm
Disassembly of section .text:
00000000 <.text>:
0: e3a0b000 mov fp, #0
4: 01a01000 moveq r1, r0
8: 2000 movs r0, #0
a: 4683 mov fp, r0
But, when I run my tool, I get:
warning: decoder says at (0x8,0):'strmi r2, [r3], r0' : Unknown mnemonic
0: 00 b0 a0 e3 mov fp, #0
4: 00 10 a0 01 moveq r1, r0
8: ...
My tool is based on libopcodes
(exactly like objdump
), so the third instruction is just interpreted as still in 32-bits mode and the two thumb mode instructions are just interpreted as one 32-bits instruction which gives strmi r2, [r3], r0
.
My question is that I don't understand how objdump
knows that there is a switch between normal mode to thumb mode. Before discovering this, I thought that this information was only available at execution time though the value of the t
flag in the CPSR status register.
I tried to look at the code of objdump
but, I didn't see any architecture dependent cases to treat the case of the ARM thumb mode. So, this is still a mystery to me...
Any suggestion is welcome !
EDIT
In fact, I worked on an object file (compiled with -c
option), so there is not so much symbols. But, here is a more detailed output obtained through objdump
:
$> objdump -x ./arm32_mov
./arm32_mov: file format elf32-littlearm
./arm32_mov
architecture: armv4t, flags 0x00000010:
HAS_SYMS
start address 0x00000000
private flags = 5000000: [Version5 EABI]
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000000c 00000000 00000000 00000034 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 00000000 00000000 00000040 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 00000000 00000000 00000000 00000040 2**0
ALLOC
3 .ARM.attributes 00000016 00000000 00000000 00000040 2**0
CONTENTS, READONLY
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .ARM.attributes 00000000 .ARM.attributes
And, here is the output of readelf
:
$> readelf -a ./arm32_mov
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 148 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 8
Section header string table index: 5
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 00000c 00 AX 0 0 4
[ 2] .data PROGBITS 00000000 000040 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 000040 000000 00 WA 0 0 1
[ 4] .ARM.attributes ARM_ATTRIBUTES 00000000 000040 000016 00 0 0 1
[ 5] .shstrtab STRTAB 00000000 000056 00003c 00 0 0 1
[ 6] .symtab SYMTAB 00000000 0001d4 000070 10 7 7 4
[ 7] .strtab STRTAB 00000000 000244 000007 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 7 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 NOTYPE LOCAL DEFAULT 1 $a
5: 00000008 0 NOTYPE LOCAL DEFAULT 1 $t
6: 00000000 0 SECTION LOCAL DEFAULT 4
No version information found in this file.
Attribute Section: aeabi
File Attributes
Tag_CPU_arch: v4T
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-1
SOLUTION (Ian Cook)
$ objdump --syms --special-syms ./arm32_mov
./arm32_mov: file format elf32-littlearm
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l .text 00000000 $a <-- ARM code
00000008 l .text 00000000 $t <-- Thumb code
00000000 l d .ARM.attributes 00000000 .ARM.attributes
Just to be sure, I interleaved arm code, thumb code and arm code again. Here is the dump:
$> objdump --syms --special-syms ./arm32_mov
./arm32_mov: file format elf32-littlearm
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l .text 00000000 $a
00000008 l .text 00000000 $t
0000000c l .text 00000000 $a
00000000 l d .ARM.attributes 00000000 .ARM.attributes
You can see that the ARM symbol is present twice at 0x0
and 0xc
and are surrounding the thumb symbol.