用户态调用Xen超级调用与Linux内核系统调用

一、从用户态访问系统调用
通常,系统调用靠C库支持。用户程序通过包含标准头文件并和C库链接,就可以使用系统调用。但如果你仅仅写出系统调用,glibc库恐怕并不提供支持。

这里有一个好消息还有一个坏消息,好消息是Linux本身提供了一组宏定义linux/include/asm-x86_64/unistd.h文件中。坏消息是在2.6.20之后的内核版本取消了这一系列的宏,导致一开始编译源文件的时候出错,最后在2.6.18中找到了这段代码。其实这段汇编主要的作用就是将系统调用号传递给EAX寄存器,同时将从EAX寄存器取出返回值。

//test.c

#include <stdio.h>

#include <syscall.h>

#include <linux/errno.h>

#include <errno.h>



#define __NR_foo 312

#define MAX_ERRNO 127

#define __syscall "syscall"

#define __syscall_clobber "r11","rcx","memory"

#define __syscall_return(type,res)\

    do{\

        if((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)){\

            errno = -res;\

            res = -1;\

        }\

        return (type)(res);\

    }while(0)

#define _syscall0(type,name)\

    type name(void){\

        long __res;\

        __asm__ volatile(__syscall\

                : "=a" (__res)\

                : "0" (__NR_##name) : __syscall_clobber );\

        __syscall_return(type,__res);\

    }

_syscall0(long,foo)

int main(int argc,char** argv)

{

    long stack_size = 0;

    stack_size = foo();

    if(stack_size == -1)

    perror("ERROR");

    printf("The kernel stack size is %ld\n",stack_size);

    return 0;

}

Output: The kernel stack size is 8192

这里面有几点需要注意。

(1)由于我所编译的环境的内核版本是3.2.6,而之前也已经介绍过在2.6.20之后unistd.h文件中不再存在有这些宏,因此宏需要自己声明。上面的宏声明是我从2.6.18内核中拷贝过来的。

(2)除此之外还会遇到一个宏__syscall_return(type,res)用于返回系统调用执行后的返回值。

(3)在_syscallX这一系列宏当中存在一个__syscall宏,在源文件的开始定义为“syscall”,曾经试图去找它的定义,但是没有发现。需要说明的是,在我最初用“int $0x80”而不是“syscall”的时候,系统调用不成功。ERROR返回错误:Dad Address

(4)在声明_syscall0(long,foo)后面没有分号。

下面的例子是从网上发现的。可以看到通过函数syscall将系统调用号传递进去。这样调用系统调用更方便。

//test1.c

#include <stdio.h>

#include <asm/unistd_64.h>

#include <syscall.h>

#include <sys/syscall.h>

#define __NR_foo 312

int main(int argc,char** argv)

{

    long ret = 0;

    ret = syscall(__NR_foo);

    printf("Thread Stack Size is %ld\n",ret);

    return 0;

}



Output: Thread Stack Size is 8192

二、从用户态访问超级调用
以下是在网上发现的一个用户态调用 Xenhypervisor的例子。该例子中类似上面系统调用在 Xen中新添加了一个超级调用。
#include <stdio.h>

#include <errno.h>

#include <stdlib.h>

#include <sys/ioctl.h>

#include <sys/types.h>

#include <fcntl.h>

#include <string.h>

#include <xenctrl.h>

#include <xen/sys/privcmd.h>



#define __HYPERVISOR_print_string 39



int main(int argc,char** argv)

{

    int fd = 0;

    int ret = 0;

    char* message = NULL;

    if(argc != 2)

    {

        printf("Please input one parameter!\n");

        return -1;

    }

    message = (char*)malloc(sizeof(char) * strlen(argv[1] + 1));

    if (message == NULL) {

        printf("malloc failed");

        return -1;

    }

    strcpy(message,argv[1]);

    privcmd_hypercall_t hcall = {__HYPERVISOR_print_string, {message,0,0,0,0}};

    fd = open("/proc/xen/privcmd",O_RDWR);

    if(fd < 0)

    {

        perror("open");

        exit(1);

    }

    else

        printf("fd=%d\n",fd);

    ret = ioctl(fd,IOCTL_PRIVCMD_HYPERCALL,&hcall);

    perror("ioctl err");

    printf("ret = %d\n",ret);

    

    close(fd);

    return 0;

}

之后便以Xen,重新加载Xen hypervisor,在xm dmesg命令下即可查看hypercall运行结果。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值