【问题标题】:Win64 and Linux-x86_64 Calling Convention Unused registers modified or notWin64 和 Linux-x86_64 调用约定 未使用的寄存器是否已修改
【发布时间】:2021-10-07 16:50:43
【问题描述】:

我有一些关于 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的问题相同。例如,如果我调用只有 1 个参数的某个函数,(例如 ExitProcess)... 其他参数寄存器的值会保持不变吗?或者windows也会使用其他参数寄存器,我里面的值会改变?

【问题讨论】:

  • 对于 Linux,这是 stackoverflow.com/questions/2535989/… 的副本。 syscall 覆盖 rcxr11,并将返回值保留在 rax 中。所有其他寄存器,包括您传递参数的寄存器,都保持不变。 Windows 部分确实是一个单独的问题,我认为它应该在单独的帖子中。
  • 请注意(再次在 Linux 上)syscall 与普通函数调用有不同的约定,其中只有 rbx, rbp, rsp, r12-r15 保持不变,其他所有内容都可能被覆盖。
  • @NateEldredge 但是linux部分的第二个问题呢?
  • 再次阅读我上面写的内容:“所有其他寄存器,包括您传递参数的寄存器,保持不变。”因此,在您的问题 2 中,esi 将在多个系统调用中保持值 0766o。 (不过,您的代码的读者可能不记得这一点,所以添加 cmets 来指出它是明智的。)
  • 最好在两个单独的帖子中提出两个单独的问题 -- 更适合这种问答形式。

标签: assembly x86-64 system-calls calling-convention


【解决方案1】:

在我查看过的任何 ISA 的任何调用约定中,当然不是任何标准x86 上的。

但是,原始系统调用的调用约定与函数的调用约定不同,即使对于可能的瘦包装函数也是如此。

所有标准用户空间函数调用约定都将所有 arg 传递寄存器(和堆栈槽)作为调用破坏。因此,如果您的 asm 使用 call,这就是您所期望的。

主流操作系统上的系统调用约定保留所有寄存器(返回值除外)。 (但在 x86-64 上,只有在 syscall 本身覆盖 RCX 和 R11 之后,because that happens before the kernel gets control。)如果你直接使用 syscallint 0x80 或其他什么,这就是你应该期待的。

请注意,Windows 没有在内核版本之间具有稳定的系统调用 ABI,并且不记录原始系统调用,因此在正常的 Windows 代码中,您总是在进行 DLL 函数调用,从不原始系统调用。 People have reverse-engineered the system calls for different Windows versions, though.

MacOS 也没有官方有一个稳定的/记录的系统调用 ABI,但实际上达尔文基本上有,至少对于玩具程序的正常 POSIX 打开/读/写/关闭/退出调用使用。

【讨论】:

    猜你喜欢
    • 2012-08-26
    • 2016-05-05
    • 1970-01-01
    • 2011-07-14
    • 2017-01-17
    • 1970-01-01
    • 2012-01-27
    • 2015-08-18
    • 1970-01-01
    相关资源
    最近更新 更多