【问题标题】:Accessing a system call directly from user program直接从用户程序访问系统调用
【发布时间】:2012-10-24 13:04:23
【问题描述】:

在 Ubuntu 上 - 内核 2.6.32.2

如何在不借助任何库的情况下直接从用户代码调用已有的系统调用? 我在书籍和互联网上阅读以解决此问题,然后编写以下代码但仍然出现错误。请帮忙

想知道当前进程的进程id

#include <stdio.h>
#include<linux/unistd.h> // for __NR_getpid
_syscall0(int, getpid)

int main() {
 printf("Current Process ID : %d\n",getpid());
 return 0;
}

编译时出错:

root@Omkant:~/os# gcc -Wall getpid.c -o getpid
getpid.c:5:16: error: expected declaration specifiers or ‘...’ before ‘getpid’
getpid.c:5:1: warning: data definition has no type or storage class
getpid.c:5:1: warning: type defaults to ‘int’ in declaration of ‘_syscall0’
getpid.c: In function ‘main’:
getpid.c:8:2: warning: implicit declaration of function ‘getpid’

代码有什么问题?请帮忙...

【问题讨论】:

  • "但仍然出现错误" -- 编译时间?运行?为什么要隐藏这些重要信息?
  • 对不起....现在是编译时间...
  • 请使用实际的错误消息(完整,逐字)编辑您的帖子。 “一个错误”对任何人都没有帮助。
  • 如果您想了解如何编写它们并从头开始使用,请尝试此操作。stackoverflow.com/questions/12469836/…
  • @askmish : 谢谢..但我知道如何编写我们自己的系统调用和调用过程..但我想在没有库函数帮助的情况下调用现有的系统调用

标签: c posix system-calls


【解决方案1】:

_syscall(2) 的手册页指出:

从内核 2.6.18 开始,_syscall 宏已从提供给用户空间的头文件中删除。请改用 syscall(2)。 (某些架构,尤其是 ia64,从未提供 _syscall 宏;在这些架构上,总是需要 syscall(2)。)

因此,您想要的方法不适用于更现代的内核。 (您可以清楚地看到,如果您在代码上运行预处理器。它不会解析_syscall0 宏)尝试改用syscall 函数:

这是一个用法示例,引用自syscall(2)

#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>

int
main(int argc, char *argv[])
{
    pid_t tid;
    tid = syscall(SYS_gettid);
}

当您要求在没有任何用户空间包装器的情况下直接调用 Linux 内核时,我将向您展示 80386 和 amd64 架构的示例。

首先,您必须从表中获取系统调用号,例如this one。在getpid 的情况下,amd64 的系统调用号为 39,80386 的系统调用号为 20。接下来,我们创建一个为我们调用系统的函数。在 80386 处理器上,您使用中断 128 来调用系统,在 amd64 上,我们使用特殊的syscall 指令。系统调用号进入寄存器 eax,输出也写入该寄存器。为了使程序更简单,我们用汇编编写它。您可以稍后使用 strace 来验证它是否正常工作。

这是 80386 的代码。它应该返回其 pid 的最低字节作为退出状态。

        .global _start
_start: mov $20,%eax       #system call number 20:
        int $128           #call the system
        mov %eax,%ebx      #move pid into register ebx
        mov $1,%eax        #system call number 1: exit, argument in ebx
        int $128           #exit

组装:

as -m32 -o 80386.o 80386.s
ld -m elf_i386 -o 80386 80386.o

这与 amd64 的代码相同:

        .global _start
_start: mov $39,%eax    #system call 39: getpid
        syscall         #call the system
        mov %eax,%edi   #move pid into register edi
        mov $60,%eax    #system call 60: exit
        syscall         #call the system

组装:

as -o amd64.o amd64.s
ld -o amd64 amd64.o

【讨论】:

  • 但是syscall这里还是用户空间功能吧?有没有其他方法可以直接调用内核空间函数
  • @Omkant 调用系统是一项高度依赖平台的任务,通常涉及手写汇编代码。如果你告诉我你在哪个平台上,我可以给你举个例子。
  • 我是intel ia64 ubuntu(64-bit) kernel - 2.6.32.2
  • IA64?您是指 amd64 别名 x64 还是 intel IA64 架构?如果是后者,我帮不了你。
  • 谢谢..我从你的汇编代码中得到了一些想法,我现在可以做到
【解决方案2】:

“如何在没有任何库帮助的情况下直接从用户代码调用已经存在的系统调用?我在书籍和互联网上阅读以解决这个问题,然后编写以下代码但仍然出现错误”

您的问题就像询问如何在不使用 glibc/libc 的情况下使用 printf ,我想只有一个解决方案获取 printf 的源代码,将其粘贴到您的代码中并使用它

想知道当前进程的进程id

可以通过使用 libc 中的 getpid 函数找到进程 ID,该函数负责您的系统调用。

系统调用未在库中定义,这些是为访问内核数据而编写的函数。

问候, 祖布拉吉

【讨论】:

    猜你喜欢
    • 2014-03-02
    • 2016-02-18
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多