关于linux-x86_64和win64中的调用约定,我有一些重要的问题。我找了太多的地方,但我还没有找到我问题的答案!!我认为我的问题没有重复,所以请先阅读一下。
在linux-x86_64中,我们使用系统调用…
linux-x86_64系统调用约定为:
RDI -> first parameter
RSI -> second parameter
RDX -> third parameter
R10 -> fourth parameter
R8 -> fifth parameter
R9 -> sixth parameter
R11 -> ... (for all syscalls)
RCX -> ... (for all syscalls)
RAX -> return
现在,我的问题关于linux-x86_64:
问题1:如果一个系统调用(例如,'sys_write
')接受3个参数(RDI,RSI,RDX
),那么其他参数寄存器怎么办?是的,这个系统调用只有3个参数,但它是否也会使用其他参数寄存器(用于其他用途,如进程内部和…)?我的意思是,如果我调用sys_write
并且我在R10
寄存器中有一些东西,R10
值在系统调用后会保持100%不变吗?这个系统调用没有第四个参数,所以我认为R10或R8或R9内的所有内容都将保持不变…正确吗?我说的对吗?
问题2:例如,sys_mkdir
…如果我必须调用sys_mkdir
3次(一个接一个),这样正确吗?
mov eax, 83
mov rdi, .filename
mov esi, 0766o
syscall
mov eax, 83
mov rdi, .filename2
syscall ; no (mov esi, 0766o) anymore because ESI is equal to 0766o from last syscall
mov eax, 83
mov rdi, .filename3
syscall ; no (mov esi, 0766o) anymore because ESI is equal to 0766o from last syscall
在这里,我只是没有更新ESI
了…因为我认为syscall
保持参数寄存器不变。我说的对吗?
现在是Win64, Win64调用约定是:
RCX -> first parameter
RDX -> second parameter
R8 -> third parameter
R9 -> fourth parameter
... (Stack)
问题1:这里,我关于win64调用约定的问题与第一个关于linux-x86_64的问题相同。如果,例如,我调用一些函数只有一个参数,(例如ExitProcess
)…其他参数寄存器的值是否保持不变?或者windows也会使用其他参数寄存器,我在它们里面的值会改变吗?
寄存器作为保留调用或中断调用的状态从不取决于调用方实际传递的和/或被调用方期望的参数的数量,在我看过的任何ISA的任何调用约定中,当然也不是x86上的任何标准约定。
但是,原始系统调用的调用约定与函数的调用约定是不同的,即使对于可能是薄包装的函数也是如此。
所有标准的用户空间函数调用约定都将所有的arg传递寄存器(和堆栈槽)作为调用处理。因此,如果您的asm使用call
,这就是您需要期待的。
主流操作系统的系统调用约定保留所有寄存器(除了返回值)。(但是在x86-64上,只有在syscall
本身覆盖RCX和R11之后,因为这发生在内核获得控制之前。)如果你直接使用syscall
或int 0x80
或其他,这是你应该期待的。
请注意,Windows没有在内核版本中有一个稳定的系统调用ABI,并且没有记录原始系统调用,因此在正常的Windows代码中,您总是进行DLL函数调用,而不是原始系统调用。不过,人们已经对系统调用进行了逆向工程,要求使用不同的Windows版本。
MacOS也没有正式的有一个稳定的/文档化的系统调用ABI,但在实践中达尔文基本上有,至少对于普通的POSIX打开/读/写/关闭/退出调用,玩具程序使用。
- 通过linux x86-64函数调用保留哪些寄存器
- UNIX的调用约定是什么?i386和x86-64上的Linux系统调用(和用户空间函数)
- https://packagecloud.io/blog/the-definitive-guide-to-linux-system-calls/
- x86-64 System V ABI文档在哪里?
- Windows系统调用