如何通过内联汇编使用syscall或sysenter来调用系统调用?

6 浏览
0 Comments

如何通过内联汇编使用syscall或sysenter来调用系统调用?

在x86 Linux中,我们如何直接使用sysenter/syscall来实现系统调用?有人能提供帮助吗?如果您还能为amd64平台提供代码,那就更好了。

我知道在x86中,我们可以使用以下代码间接地路由到sysenter:

__asm__(
"               movl $1, %eax  \n"
"               movl $0, %ebx \n"
"               call *%gs:0x10 \n"
);

但我们如何直接使用sysenter/syscall来发起系统调用呢?我在这里找到了一些资料http://damocles.blogbus.com/tag/sysenter/。但仍然感到困惑。

0
0 Comments

如何通过syscall或sysenter在内联汇编中调用系统调用?

问题的出现原因:

- 在GCC中,register约束的方式无法表示所有寄存器,包括用于系统调用参数的r8、r9和r10寄存器。

- 对于其他的ISA(指令集体系结构)例如ARM,没有魔术寄存器约束名称,因此register约束无法使用。

解决方法:

- 可以使用显式寄存器变量来解决这个问题。

- 显式寄存器变量可以表示所有寄存器,包括r8、r9和r10。

- 对于其他ISA,如ARM,显式寄存器变量是唯一的最佳选择。

以下是一个使用显式寄存器变量调用系统调用的示例代码:

#define _XOPEN_SOURCE 700
#include 
#include 
ssize_t my_write(int fd, const void *buf, size_t size) {
    register int64_t rax __asm__ ("rax") = 1;
    register int rdi __asm__ ("rdi") = fd;
    register const void *rsi __asm__ ("rsi") = buf;
    register size_t rdx __asm__ ("rdx") = size;
    __asm__ __volatile__ (
        "syscall"
        : "+r" (rax)
        : "r" (rdi), "r" (rsi), "r" (rdx)
        : "rcx", "r11", "memory"
    );
    return rax;
}
void my_exit(int exit_status) {
    register int64_t rax __asm__ ("rax") = 60;
    register int rdi __asm__ ("rdi") = exit_status;
    __asm__ __volatile__ (
        "syscall"
        : "+r" (rax)
        : "r" (rdi)
        : "rcx", "r11", "memory"
    );
}
void _start(void) {
    char msg[] = "hello world\n";
    my_exit(my_write(1, msg, sizeof(msg)) != sizeof(msg));
}

在这个示例代码中,通过显式寄存器变量来指定系统调用的参数,然后使用syscall指令来调用系统调用。这样可以实现在内联汇编中调用系统调用的功能。

这种方法可以在GCC中使用,并且可以表示所有寄存器,同时也适用于其他ISA,如ARM。

0
0 Comments

如何通过syscall或sysenter在内联汇编中调用系统调用?

问题的原因:

- 在GNU C基本asm("")语法中使用此问题是不安全的。你需要使用扩展的asm来告诉编译器你修改的寄存器。

- 需要使用asm volatile,因为对于具有一个或多个输出操作数的扩展asm语句,这不是隐含的。

解决方法:

- 对于i386 Linux,系统调用是使用第128个中断向量实现的,例如在汇编代码中调用int 0x80,并在此之前设置相应的参数。

- 对于amd64架构,使用新的syscall指令。系统调用的编号仍然传递给rax寄存器,但用于保存参数的寄存器现在几乎与函数调用约定一致。

下面是一个示例代码:

// i386 Linux
#include       // compile with -m32 for 32 bit call numbers
//#define __NR_write 4
ssize_t my_write(int fd, const void *buf, size_t size)
{
    ssize_t ret;
    asm volatile
    (
        "int $0x80"
        : "=a" (ret)
        : "0"(__NR_write), "b"(fd), "c"(buf), "d"(size)
        : "memory"    // the kernel dereferences pointer args
    );
    return ret;
}
// x86-64 Linux
#include       // compile without -m32 for 64 bit call numbers
// #define __NR_write 1
ssize_t my_write(int fd, const void *buf, size_t size)
{
    ssize_t ret;
    asm volatile
    (
        "syscall"
        : "=a" (ret)
        //                 EDI      RSI       RDX
        : "0"(__NR_write), "D"(fd), "S"(buf), "d"(size)
        : "rcx", "r11", "memory"
    );
    return ret;
}

这些代码分别演示了在i386和amd64架构上如何调用系统调用。在i386上,使用int 0x80指令,而在amd64上,使用syscall指令。在这些代码中,系统调用的编号传递给寄存器rax,并将参数分别存储在寄存器ebx、ecx、edx、esi、edi和ebp中。

需要注意的是,不同的操作系统(如MacOS)使用不同的系统调用编号和参数传递约定。

本文介绍了如何在内联汇编中通过syscall或sysenter调用系统调用。通过使用适当的寄存器和指令,可以在不同的架构上实现系统调用。但是需要注意不同操作系统的系统调用编号和参数传递约定的差异。

0