Finding the Machine Code in an ELF Executable.
Notes
- I have written a program for these purposes foo.s
.global main .text main: add x1, xzr, xzr add x3, x4, w2, SXTW add x2, x4, #52 ret -
readelf filename-
readelf -h fooshows header information-
bennett@Archimedes:~/armAssembly $ readelf -h foo ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Position-Independent Executable file) Machine: AArch64 Version: 0x1 Entry point address: 0x640 Start of program headers: 64 (bytes into file) Start of section headers: 68976 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 10 Size of section headers: 64 (bytes) Number of section headers: 35 Section header string table index: 34
-
- We can see the entry point is 0x640, where the text segment begins.
- But the text offset is the beginning of ALL Of the code
- We don't want any preamble the compiler installs.
-
- Fortunately
objdumpwill let us look at executable code.-
objdump -d foo -
0000000000000768
: 768: 8b1f03e1 add x1, xzr, xzr 76c: 8b22c083 add x3, x4, w2, sxtw 770: 9100d082 add x2, x4, #0x34 774: d65f03c0 ret
-
-
od- -Ax will dump the addresses in hex, decimal by default
- -x will dump the code in hex
-
od -Ax -x foo -
0 1 2 3 4 5 6 7 8 9 a b c d e f 000760 245f d503 ffdb 17ff 03e1 8b1f c083 8b22 000770 d082 9100 03c0 d65f 233f d503 7bfd a9bf 000780 03fd 9100 7bfd a8c1 23bf d503 03c0 d65f - I selected the right range and added the top line.
- So the instruction at 768 is: 03e1 8b1f16
- But ARM is little endian, so the number is really
- 8b1f03e116
-
add x1, xzr, xzr- Remember x1: is 1 (00001)
- xzr is 31 (1111)
- I found an ARM Architecture Reference Manual here: https://support.arm.com/documentation/ddi0487/mc/-Part-C-The-AArch64-Instruction-Set/-Chapter-C4-A64-Instruction-Set-Encoding/-C4-1-A64-instruction-set-encoding?lang=en#a64_encoding_index_top (use the download button on the left).
-
SF is 1 - 64 bit, 0 - 32 bit 30-23 are 0001011000 rm is 11111 option is probably 000 imm3 is 000 rn is 11111 rd is 00001 1 0001011000 11111 000 000 11111 00001 (from above) 10001011000111110000001111100001 (remove the spaces) 1000 1011 0001 1111 0000 0011 1110 0001 (Groups of 4) 8 B 1 F 0 3 E 1 (Hex Digits) 8B3F03E18 - By the way, there is a ADD (extended Register)
-
add x3, x4, w2, SXTW -
- For
add xRd, xRs1, *Rs2, SXTW - This sign extends the *Rs2 value to be 64 bits.
- There is a fourth argument that describes how to extend
- Note, this is the same, or nearly the same op-code
- Bit 21 is different.
-
sf = 1 30-21 = 0001011001 rm = 00010 Option = SXTW - 110 imm3 = 000 rn = 00100 rd = 00011 1 0001011001 00010 110 000 00100 00011 10001011001000101100000010000011 1000 1011 0010 0010 1100 0000 1000 0011 8 B 2 2 C 0 8 3
-
- And an Add Immediate
-
add x2, x4, #52 -
- This is a different format
-
9100d082 91000082 1001 0001 0000 0000 1101 0000 1000 0010 1 00 100010 0 000000110100 00100 00010 sf = 1, 64 bit op,S = 00 OPCode = 100010 (addi) sh = 0 imm12 = 000000110100 = 32 + 16 + 4 = 52 Rn = 4 Rd = 2
-
-
- In the end, we will not study ARMv8 Instruction formats
- We will study LEGv8 instruction formats
- But given a manual, and time ...
- DEITY grant blessings on the person who created the assembler, and the compiler!
- I expect that you understand what is happening here, and appreciate that this is THE REAL THING.