linux编译内核及添加系统调用(2)

时间:2021-10-15 13:33:34

作者:admin

来源:纯净之家


 
  .long sys_add_key
  .long sys_request_key
  .long sys_keyctl
  .代表当前地址,sys_call_table代表数组首地址。这个表依次保存所有系统调用的函数指针,以方便总的系统调用处理函数(system_call)进行索引。
  调用具体的实现在kernel/sys.c中。
  asmlinkage long
  sys_getuid16(void)
  {
  return hig2lowuid(current_uid);
  }
 
 刚才我们提到,这一指令使用中断/异常向量号128(即16进制的80)将控制权转移给内核,那么中断向量是怎么形成的。它的定义在(arch/i386/kernel/traps.c)中。
  void __init trap_init(void)
  {
  ……
  set_trap_gate(0,÷_error);
  set_trap_gate(1,&debug);
  set_intr_gate(2,&nmi);
  set_system_gate(3,&int3); /* int3-5 can be called from all */
  set_system_gate(4,&overflow);
  set_system_gate(5,&bounds);
  set_trap_gate(6,&invalid_op);
  set_trap_gate(7,&device_not_available);
  set_trap_gate(8,&double_fault);
  set_trap_gate(9,&coprocessor_segment_overrun);
  set_trap_gate(10,&invalid_TSS);
  set_trap_gate(11,&segment_not_present);
  set_trap_gate(12,&stack_segment);
  set_trap_gate(13,&general_protection);
  set_intr_gate(14,&page_fault);
  set_trap_gate(15,&spurious_interrupt_bug);
  set_trap_gate(16,&coprocessor_error);
  set_trap_gate(17,&alignment_check);
  set_trap_gate(18,&machine_check);
  set_trap_gate(19,&simd_coprocessor_error);
  set_system_gate(,&system_call);
  ……
  }
  上一句就是设置system_call 的值。SYSCALL_VECTOR的值就是0X80 .
  那么概括起来,系统调用的过程大致如下:
  (1) 系统调用初始化
  在traps.c中,系统在初始化程序trap_init()中,通过调用
  set_system_gate(0x80,*system_call)
  完成中断描述表的填充。这样当每次用户执行指令int 0x80时,系统能把控制转移到entry.S中的函数中去。
  (2) 系统调用执行
  system_call会根据用户传进来系统调用号,在系统调用表 system_call中寻找到相应偏移地址的内核处理函数,进行相应的处理。当然在这个过程之前,要保存环境(SAVE_ALL)。
  (3) 系统调用的返回
  系统调用处理完毕后,通过sys_call_exit返回。返回之前,程序会检查一些变量,相应地返回。不一定是返回到用户进程。真正返回到用户空间时,要恢复环境(restore_all)。
  用户程序中系统调用的过程
  在前面提到system_call会根据用户传进来系统调用号,在系统调用表 system_call中寻找到相应偏移地址的内核处理函数,进行相应的处理。
  那么系统调用号怎么产生,在include/asm-i386/unistd.h 中可以看到系统调用号的定义。
  #define __NR_restart_syscall 0
  #define __NR_exit 1
  #define __NR_fork 2
  #define __NR_read 3
  #define __NR_write 4
  #define __NR_open 5
  #define __NR_close 6
  #define __NR_waitpid 7
  #define __NR_creat 8
  #define __NR_link 9
  ……
  #define __NR_mq_open 277
  #define __NR_mq_unlink (__NR_mq_open+1)
  #define __NR_mq_timedsend (__NR_mq_open+2)
  #define __NR_mq_timedreceive (__NR_mq_open+3)
  #define __NR_mq_notify (__NR_mq_open+4)
  #define __NR_mq_getsetattr (__NR_mq_open+5)
  #define __NR_sys_kexec_load 283
  #define __NR_waitid 284
  /* #define __NR_sys_setaltroot 285 */
  #define __NR_add_key 286
  #define __NR_request_key 287
  #define __NR_keyctl 288
  #define NR_syscalls 289
  此处的代码是从2.6.11中的代码,其中系统调用号已到了288,并且与前面system_call中的相对应。每一个系统调用号前都是相应函数名加了__NR_。
  内核跟用户程序的交互,其实有标准C库作为它们之间的桥梁。标准C库把用户希望传递的参数装载到CPU的寄存器中,然后触发0X80中断。
  当从系统调用返回的时候(sys_call_exit),标准C库又接过控制权,处理返回值。
  对于__NR_,标准C库会作相应处理。转换成相应函数。
  对于系统函数的调用,有几个通用的宏在include/asm-i386/unistd.h中定义。
  #define __syscall_return(type, res)
  do {
  if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) {
  errno = -(res);
  res = -1;
  }
  return (type) (res);
  } while (0)
  #else
  # define __syscall_return(type, res) return (type) (res)
  #endif
  #define _syscall0(type,name)
  type name(void)
  {
  long __res;
  __asm__ volatile ("int $0x80"
  : "=a" (__res)
  : "0" (__NR_##name));
  __syscall_return(type,__res);
  }
  这是无参函数调用的形式。
  #define _syscall1(type,name,type1,arg1)
  type name(type1 arg1)
  {
  long __res;
  __asm__ volatile ("int $0x80"
  : "=a" (__res)
  : "0" (__NR_##name),"b" ((long)(arg1)));
  __syscall_return(type,__res);
  }
  这是含一个参数的调用形式,
  ……
  标准C库会把我们的调用如pause()转换成相应的形式。
  pause()
  int pause(void)
  {
  long __res;
  __asm__ volatile(“int $0x80”
  :”=a”(__res)
  :””(__NR_pause));
  __syscall_return(int,__res);
  }

  进入内核调用过程。

 基础知识介绍完了,下面来进行我们的实验:
  准备
  如果你安装的系统包含内核源文件,一般在/usr

c路径下可以看到,那么可以直接跳到步骤3进行内核修改。 

linux编译内核及添加系统调用(2)


  首先下载最新的linux2.6.37内核,先修改/usr

c

nux下的Makefile文件,将内核版本修改成自己的。

把2.6.37中Makefile文件头几行为:
  VERSION = 2
  PATCHLEVEL = 6
  SUBLEVEL = 37
  EXTRAVERSION = .1
  我们可以修改成自己版本(2.6.37.rangercyh):
  VERSION = 2
  PATCHLEVEL = 6
  SUBLEVEL = 37
  EXTRAVERSION = rangercyh 

linux编译内核及添加系统调用(2)


 下载源代码
  如果系统不包含源文件,则需要在网站上下载系统源代码。
  在官方网站上下到类似 linux-2.6.37.1.tar.gz的代码后(大概有70兆左右),放在/usr

c/ 的目录下,
  然后解压,解压后会出现文件夹 linux-2.6.37.1。不过貌似最新的代码已经出到2.6.38了。 

系统下载排行榜71011xp

提取码
XGZS
关闭 前往下载