我正在编写一个机器代码程序来将字符串打印到 64 位 Linux 的终端。这是我的代码:
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 [email protected]...@.....
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..
以下是我对 x86-64 汇编指令的机器代码翻译:
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
这是我为了学习而翻译的汇编程序:
; 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
可执行文件被命名print
并在执行时:
$ ./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
我想我在 offset 处遇到了分段错误0x00000087
。问题是什么以及如何解决?
你把机器码写错了。第一条指令已经被破坏了。
b900 0000 0000 0000 01
不是mov rax, 1
它mov ecx, 0
。请注意,实际的程序转储有一个48
前缀,使其成为mov rcx, 0x100000000000000
. 即使这样,它也是错误的寄存器,并且该值不会针对小端进行调整。这也适用于其余说明。使用反汇编程序查看您实际编码的内容:前两个是错误的,第三个就错了。