我正在尝试在程序集中进行一些基本的系统调用(OSX上的NASM中的x86-64),但到目前为止还没有成功。
到目前为止,我在网上看到的唯一例子是从stdin读取或写入stdout,例如:
global main
section .text
main:
call write
write:
mov rax, 0x2000004
mov rdi, 1
mov rsi, message
mov rdx, length
syscall
section .data
message: db 'Hello, world!', 0xa
length: equ $ - message
但是,当我尝试使用相同的模式进行另一个系统调用时,它不起作用(它说的是Bus error: 10
):
global main
section .text
main:
call mkdir
mkdir:
mov rax, 0x2000136 ; mkdir system command number
mov rdi, rax ; point destination to system command
mov rsi, directory ; first argument
mov rdx, 755 ; second argument
syscall
section .data
directory: db 'tmp', 0xa
调用系统命令的一般结构是什么(理想情况下在NASM中的OSX上)?
基本上你应该做的就是在这里找到你想要的系统调用:http://www.opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master。所以“写”一个看起来像这样:
4 AUE_NULL ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); }
这就是说:
所以我开始认为一般模式是这样的:
rax: system call number
rdi: maybe? point to system call ("destination index"), but why the `1` in the write example?
rsi: first argument to system call ("source index", the string in this case)
rdx: second argument to system call
rcx: third argument (if necessary, but not in the system write case)
那么就像你可以直接映射任何系统命令一样。所以mkdir
:
136 AUE_MKDIR ALL { int mkdir(user_addr_t path, int mode); }
将被翻译为:
rax: 0x20000136 ; 136 + 20000000
rdi: i dunno, maybe `rax`?
rsi: directory (first argument)
rdx: 755 (mode, second argument)
但是,这不起作用。
我做错了什么?如何执行此操作的一般模式是什么,以便我可以在syscalls.master中的任何其他系统命令上进行测试?你能描述不同的寄存器在这里扮演的角色吗?这有助于澄清我的想法。
答案 0 :(得分:3)
我相信OSX遵循标准的SYSV ABI调用约定,至少你的例子肯定是这样的。参数按顺序进入寄存器RDI
,RSI
,RDX
,R10
,R8
和R9
。系统电话号码进入RAX
。
让我们看一下write
:int fd, user_addr_t cbuf, user_size_t nbyte
大会:
mov rdi, 1 ; fd = 1 = stdout
mov rsi, message ; cbuf
mov rdx, length ; nbyte
现在,对于mkdir
:user_addr_t path, int mode
显然,您需要将path
加入rdi
和mode
加入rsi
。
mkdir:
mov rax, 0x2000136 ; mkdir system command number
mov rdi, directory ; first argument
mov rsi, 0x1ED ; second argument, 0x1ED = 755 octal
syscall
ret
请注意,您需要ret
和mkdir
子例程的结尾,并且您还需要一个,因此main
不会进入mkdir
。此外,您应该使用lea
加载directory
参数,并使用RIP
- 相对寻址,例如lea rdi, [rel directory]
。
答案 1 :(得分:2)
你已经得到了几乎正确的结果:系统调用号需要0x88(dec 136)。 syscall.master中的系统调用是十进制的。你最终调用了getsid(这是系统调用310)。
对于参数,不要使用syscalls.master,因为这会给你一个有点倾斜的内核视角(当涉及到参数名称时)。您应该使用/usr/include/unistd.h作为原型,并使用usr / inclunde / sys / syscall.h作为数字。只有在系统调用未导出到这些文件的情况下,syscalls.master才会派上用场,而且那些主文件是NO_SYSCALL_STUB的情况。
对于ABI,它与System V AMD64 ABI相同。 http://people.freebsd.org/~obrien/amd64-elf-abi.pdf
你可以看到系统调用就像libsystem那样:
otool -tV /usr/lib/system/libsystem_kernel.dylib | more
# seek to /^_mkdir:
_mkdir:
0000000000012dfc movl $0x2000088, %eax
0000000000012e01 movq %rcx, %r10
0000000000012e04 syscall
0000000000012e06 jae 0x12e0d
0000000000012e08 jmpq cerror_nocancel
0000000000012e0d ret
0000000000012e0e nop
0000000000012e0f nop
所有系统调用基本上都具有以下结构:
系统调用被执行
<<内核部分发生,其中执行通过陷阱进入内核模式, 并且eax的值用于i)到达系统调用表和ii)分支以纠正 系统调用>>
答案 2 :(得分:0)
Bus error: 10
错误似乎是由错误的系统调用号码引起的,并且没有退出系统调用。
; nasm -f macho64 mkdir.asm && ld -o mkdir mkdir.o && ./mkdir
%define SYSCALL_MKDIR 0x2000088
%define SYSCALL_EXIT 0x2000001
global start
section .text
start:
call mkdir
call exit
ret
mkdir:
mov rax, SYSCALL_MKDIR
mov rdi, directory
mov rsi, 0x1ED
syscall
exit:
mov rax, SYSCALL_EXIT
mov rdi, 0
syscall
section .data
directory: db 'tmp', 0
原始代码更改摘要:
main
符号重命名为start
0x2000136
更改为0x2000088
0xa
字符更改为0
(无效,但文件名不正确)我还必须安装nasm
的版本2.10.09:
brew install https://raw.githubusercontent.com/Homebrew/homebrew/c1616860c8697ffed8887cae8088ab39141f0308/Library/Formula/nasm.rb
brew switch nasm 2.10.09
这是由于:
nacho64
/usr/bin/nasm
支持
fatal: No section for index 2 offset 0 found