Chinaunix首页 | 论坛 | 博客
  • 博客访问: 62532
  • 博文数量: 6
  • 博客积分: 176
  • 博客等级: 入伍新兵
  • 技术积分: 122
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-20 18:47
文章分类

全部博文(6)

文章存档

2012年(6)

分类: LINUX

2012-03-13 10:36:19

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

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


 

点击(此处)折叠或打开

  1. //test.c
  2. #include <stdio.h>
  3. #include <syscall.h>
  4. #include <linux/errno.h>
  5. #include <errno.h>

  6. #define __NR_foo 312
  7. #define MAX_ERRNO 127
  8. #define __syscall "syscall"
  9. #define __syscall_clobber "r11","rcx","memory"
  10. #define __syscall_return(type,res)\
  11.     do{\
  12.         if((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)){\
  13.             errno = -res;\
  14.             res = -1;\
  15.         }\
  16.         return (type)(res);\
  17.     }while(0)
  18. #define _syscall0(type,name)\
  19.     type name(void){\
  20.         long __res;\
  21.         __asm__ volatile(__syscall\
  22.                 : "=a" (__res)\
  23.                 : "0" (__NR_##name) : __syscall_clobber );\
  24.         __syscall_return(type,__res);\
  25.     }
  26. _syscall0(long,foo)
  27. int main(int argc,char** argv)
  28. {
  29.     long stack_size = 0;
  30.     stack_size = foo();
  31.     if(stack_size == -1)
  32.     perror("ERROR");
  33.     printf("The kernel stack size is %ld\n",stack_size);
  34.     return 0;
  35. }
  36. Output: The kernel stack size is 8192

这里面有几点需要注意。

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

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

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

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

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


 

点击(此处)折叠或打开

  1. //test1.c
  2. #include <stdio.h>
  3. #include <asm/unistd_64.h>
  4. #include <syscall.h>
  5. #include <sys/syscall.h>
  6. #define __NR_foo 312
  7. int main(int argc,char** argv)
  8. {
  9.     long ret = 0;
  10.     ret = syscall(__NR_foo);
  11.     printf("Thread Stack Size is %ld\n",ret);
  12.     return 0;
  13. }

  14. Output: Thread Stack Size is 8192
二、从用户态访问超级调用
    以下是在网上发现的一个用户态调用Xenhypervisor的例子。该例子中类似上面系统调用在Xen中新添加了一个超级调用。


 

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <stdlib.h>
  4. #include <sys/ioctl.h>
  5. #include <sys/types.h>
  6. #include <fcntl.h>
  7. #include <string.h>
  8. #include <xenctrl.h>
  9. #include <xen/sys/privcmd.h>

  10. #define __HYPERVISOR_print_string 39

  11. int main(int argc,char** argv)
  12. {
  13.     int fd = 0;
  14.     int ret = 0;
  15.     char* message = NULL;
  16.     if(argc != 2)
  17.     {
  18.         printf("Please input one parameter!\n");
  19.         return -1;
  20.     }
  21.     message = (char*)malloc(sizeof(char) * strlen(argv[1] + 1));
  22.     if (message == NULL) {
  23.         printf("malloc failed");
  24.         return -1;
  25.     }
  26.     strcpy(message,argv[1]);
  27.     privcmd_hypercall_t hcall = {__HYPERVISOR_print_string, {message,0,0,0,0}};
  28.     fd = open("/proc/xen/privcmd",O_RDWR);
  29.     if(fd < 0)
  30.     {
  31.         perror("open");
  32.         exit(1);
  33.     }
  34.     else
  35.         printf("fd=%d\n",fd);
  36.     ret = ioctl(fd,IOCTL_PRIVCMD_HYPERCALL,&hcall);
  37.     perror("ioctl err");
  38.     printf("ret = %d\n",ret);
  39.     
  40.     close(fd);
  41.     return 0;
  42. }

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

阅读(2739) | 评论(1) | 转发(0) |
0

上一篇:没有了

下一篇:内部命令VS外部命令

给主人留下些什么吧!~~

welch19832012-03-28 11:46:05