一、从用户态访问系统调用
通常,系统调用靠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
二、从用户态访问超级调用
以下是在网上发现的一个用户态调用Xen中hypervisor的例子。该例子中类似上面系统调用在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运行结果。
阅读(2784) | 评论(1) | 转发(0) |