系統調用的封裝例程


1,什麼是封裝例程?
        系統調用是內核實現的,內核向用戶態提供服務,內核向用戶態提供系統調用的接口是一個軟中斷。
也就是int 0x80.如果用戶直接調用系統調用會很麻煩。下面就舉個直接調用系統調用的例子。用匯編實現的。
  1. # hello.s ----> intel彙編的註釋用的; 而ATT用的#
  2. # display a string "Hello, world."

  3. .section .rodata
  4. msg:
  5. .ascii "Hello, world.\n"

  6. .section .text
  7. .globl _start
  8. _start:

  9. movl $2, %eax #調用fork系統調用
  10. int $0x80


  11. movl $4, %eax # system call 系統調用號(sys_write)
  12. movl $1, %ebx # file descriptor 參數一:文件描述符(stdout)
  13. movl $msg, %ecx # string address 參數二:要顯示的字符串
  14. movl $14, %edx # string length 參數三:字符串長度
  15. int $0x80 # 調用內核功能

  16. movl $1, %eax # 系統調用號(sys_exit)
  17. movl $0, %ebx # 參數一:退出代碼
  18. int $0x80 # 調用內核功能
這就需要對系統調用進行封裝,便於用戶調用,比如說fork(),getpid(),這些函數都是libc庫中的函數
都對系統調用進行了封裝。而且都是遵循POSIX標準的。
---------------------------------------------------------------------------------------------
2,什麼是POSIX?
      POSIX是一套操作系統標準,它是隨着UNIX標準化而誕生的。linux是遵循POSIX標準的操作系統,如果
linux遵循POSIX標準的話,UNIX上的應用程序就可以順利移植到linux上來了。形象點說也就是linux和UNIX
很多函數名字及其參數都定義的是一樣的。
---------------------------------------------------------------------------------------------
3,舊方式封裝(淘汰了),__syscall0()  ~ __syscall6()
     這幾個宏實際上是利用了系統調用參數的個數不能超個6個來進行分類的。爲了內核的安全考慮。從內核2.6.18開始該宏就從頭文件中刪除了,其實完全也可以自己加入到 指定的頭文件中去。該宏被syscall()取代了,syscall()是glibc中的函數。而上面的_syscall()宏是不依賴於庫的。
  1. #define __syscall_return(type, res) \
  2. do { \
  3. if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
  4. res = -1; \
  5. } \
  6. return (type) (res); \
  7. } while (0)

  8. #define _syscall0(type,name) \
  9. type name(void) \
  10. { \
  11. long __res; \
  12. __asm__ volatile ("int $0x80" \
  13. : "=a" (__res) \
  14. : "0" (__NR_##name)); \
  15. __syscall_return(type,__res); \
  16. }

  17. #define _syscall1(type,name,type1,arg1) \
  18. type name(type1 arg1) \
  19. { \
  20. long __res; \
  21. __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
  22. : "=a" (__res) \
  23. : "0" (__NR_##name),"ri" ((long)(arg1)) : "memory"); \
  24. __syscall_return(type,__res); \
  25. }

  26. #define _syscall2(type,name,type1,arg1,type2,arg2) \
  27. type name(type1 arg1,type2 arg2) \
  28. { \
  29. long __res; \
  30. __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
  31. : "=a" (__res) \
  32. : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)) \
  33. : "memory"); \
  34. __syscall_return(type,__res); \
  35. }

  36. #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
  37. type name(type1 arg1,type2 arg2,type3 arg3) \
  38. { \
  39. long __res; \
  40. __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
  41. : "=a" (__res) \
  42. : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \
  43. "d" ((long)(arg3)) : "memory"); \
  44. __syscall_return(type,__res); \
  45. }

  46. #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
  47. type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
  48. { \
  49. long __res; \
  50. __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx" \
  51. : "=a" (__res) \
  52. : "0" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \
  53. "d" ((long)(arg3)),"S" ((long)(arg4)) : "memory"); \
  54. __syscall_return(type,__res); \
  55. }

  56. #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
  57. type5,arg5) \
  58. type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
  59. { \
  60. long __res; \
  61. __asm__ volatile ("push %%ebx ; movl %2,%%ebx ; movl %1,%%eax ; " \
  62. "int $0x80 ; pop %%ebx" \
  63. : "=a" (__res) \
  64. : "i" (__NR_##name),"ri" ((long)(arg1)),"c" ((long)(arg2)), \
  65. "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)) \
  66. : "memory"); \
  67. __syscall_return(type,__res); \
  68. }

  69. #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
  70. type5,arg5,type6,arg6) \
  71. type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
  72. { \
  73. long __res; \
  74. struct { long __a1; long __a6; } __s = { (long)arg1, (long)arg6 }; \
  75. __asm__ volatile ("push %%ebp ; push %%ebx ; movl 4(%2),%%ebp ; " \
  76. "movl 0(%2),%%ebx ; movl %1,%%eax ; int $0x80 ; " \
  77. "pop %%ebx ; pop %%ebp" \
  78. : "=a" (__res) \
  79. : "i" (__NR_##name),"0" ((long)(&__s)),"c" ((long)(arg2)), \
  80. "d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)) \
  81. : "memory"); \
  82. __syscall_return(type,__res); \
  83. }
---------------------------------------------------------------------------------------------
4,新方式封裝。(現在的封裝方式)
現在對系統調用的封裝都是用的syscall函數,該函數是不定參數,很好用,可以調用所有的系統調用。

  1.   1 #include <linux/unistd.h>
  2.   2 #include <syscall.h>
  3.   3 #include <sys/types.h>
  4.   4 #include <stdio.h>
  5.   6
  6.   7
  7.   8 int main(void)
  8.   9 {
  9.  10 long pid1;
  10.  11 pid1 = syscall(SYS_getpid); //getpid
  11.  12 printf("pid = %ld\n",pid1);
  12.  13 return 0;
  13.  14 }
---------------------------------------------------------------------------------------------
5,問題:我自己添加了一個系統調用,想在用戶態下測試下,代碼如下:

  1.   1 #include <linux/unistd.h>
  2.   2 #include <syscall.h>
  3.   3 #include <sys/types.h>
  4.   4 #include <stdio.h>
  5.   5
  6.   6
  7.   7 int main(void)
  8.   8 {
  9.   9 long n = 0;
  10.  10 n = syscall(SYS_mysyscall,190);
  11.  11 return 0;
  12.  12 }
該程序會提示“SYS_mysyscall”沒有定義。
解決辦法:
1,/usr/include/bits/syscall.h文件中添加:#define SYS_mysyscall __NR_mysyscall
2,/usr/include/i386-linux-gnu/asm/unistd_32文件末尾添加:
      #define __NR_mysyscall          345
      這樣,你添加的系統調用和系統本身自帶的系統調用的用戶態使用上就一模一樣了。
---------------------------------------------------------------------------------------------
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章