I'm writing a machine code program to print a string to the terminal in 64-bit Linux. Here is my code:
00000000: 7f45 4c46 0201 0103 0000 0000 0000 0000 .ELF............
00000010: 0200 3e00 0100 0000 7800 4000 0000 0000 ..>.....x.@.....
00000020: 4000 0000 0000 0000 0000 0000 0000 0000 @...............
00000030: 0000 0000 4000 3800 0100 4000 0000 0000 ....@.8...@.....
00000040: 0100 0000 0700 0000 0000 0000 0000 0000 ................
00000050: 0000 4000 0000 0000 0000 4000 0000 0000 ..@.......@.....
00000060: 8e00 0000 0000 0000 8e00 0000 0000 0000 ................
00000070: 0010 0000 0000 0000 48b9 0000 0000 0000 ........H.......
00000080: 0001 bf00 0000 0000 4000 88bb 0000 0000 ........@.......
00000090: 0000 0005 c000 0000 0000 0000 010f 05c7 ................
000000a0: c03c 0000 0048 c7c7 0000 0000 0f05 6865 .<...H........he
000000b0: 6c6c 6f00 0a llo..
Here are my machine code translations for the x86-64 assembly instructions:
mov rax, 1
b900 0000 0000 0000 01
mov rsi, input
bf00 0000 0000 4000 88
mov rdx, 5
bb00 0000 0000 0000 05
mov rdi, 1
c000 0000 0000 0000 01
syscall
0f05
Here is the assembly program I'm translating for learning:
; print.asm - written in fasm assembly language
format ELF64 executable 3 ; value 3 marks the executable for Linux system
; print
mov rax, 1 ; syscall #1 (write)
mov rsi, input ; arg1 = msg
mov rdx, 5 ; arg2 = msg length
mov rdi, 1 ; arg3 = 1 (stdout)
syscall
; exit
mov rax, 60 ; syscall #60 (exit)
mov rdi, 0 ; arg 1 = 0 (OK)
syscall ; call exit
; data
input db "hello", 0
The executable is named print
and on executing it:
$ ./print
Segmentation fault (core dumped)
$ gdb ./print
(gdb) r
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400087 in ?? ()
(gdb) quit
$ readelf -l print
Elf file type is EXEC (Executable file)
Entry point 0x400078
There is 1 program header, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000008e 0x000000000000008e RWE 0x1000
$ file print
print: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, no section header
I think I'm getting the segmentation fault at offset 0x00000087
. What is the problem and how to figure it out?
You have done the machine code wrong. The very first instruction is already broken. b900 0000 0000 0000 01
is not mov rax, 1
it's mov ecx, 0
. Note that the actual program dump has a 48
prefix which makes it mov rcx, 0x100000000000000
. Even then it's the wrong register and the value is not adjusted for little endian. That applies for the rest of the instructions as well. Use a disassembler to see what you actually encoded:
(gdb) x/3i 0x400078
=> 0x400078: movabs rcx,0x100000000000000
0x400082: mov edi,0x0
0x400087: add BYTE PTR [rax+0x0],al
The first two are just wrong, the third one will fault.