• linux0.11-内核信号


    如何在ubuntu 上编译linux-0.11 :

    HIT-Linux-0.11/准备安装环境.md at master · Wangzhike/HIT-Linux-0.11 · GitHub

    linux内核中的信号

    include/signal.h

    1. #define SIGHUP 1
    2. #define SIGINT 2
    3. #define SIGQUIT 3
    4. #define SIGILL 4
    5. #define SIGTRAP 5
    6. #define SIGABRT 6
    7. #define SIGIOT 6
    8. #define SIGUNUSED 7
    9. #define SIGFPE 8
    10. #define SIGKILL 9
    11. #define SIGUSR1 10
    12. #define SIGSEGV 11
    13. #define SIGUSR2 12
    14. #define SIGPIPE 13
    15. #define SIGALRM 14
    16. #define SIGTERM 15
    17. #define SIGSTKFLT 16
    18. #define SIGCHLD 17
    19. #define SIGCONT 18
    20. #define SIGSTOP 19
    21. #define SIGTSTP 20
    22. #define SIGTTIN 21
    23. #define SIGTTOU 22

    系统如何调用接受的信号与作用

    do_signal函数是内核系统调用中断(int 0X80)中断处理子程序的预处理程序,该函数的主要作用是将信号的处理句柄插入到用户程序堆栈中,系统调用后就会执行

    为什么0x80是系统调用:在代码中有相关设置

    1. //设置系统中断
    2. set_system_gate(0x80,&system_call);

    sys_signal由函数库提供,用于恢复系统调用后的返回值和一些寄存器。编译链接时由libc函数库提供,用于 在信号处理程序结束后清理用户态堆栈,并恢复系统调用存放在eax中的返回值。

     

    信号处理的流程

    在system_call.s中,可以看到首先调用的是do_signal进行预处理,再调用sys_signal信号处理 。

    1. _system_call:
    2. cmpl $nr_system_calls-1,%eax // 比较当前的调用号和当前最大调用号 nr_system_calls = 72 0.11 仅仅有72个系统调用
    3. ja bad_sys_call
    4. push %ds
    5. push %es
    6. push %fs
    7. pushl %edx
    8. pushl %ecx # push %ebx,%ecx,%edx as parameters
    9. pushl %ebx # to the system call
    10. movl $0x10,%edx # set up ds,es to kernel space
    11. mov %dx,%ds
    12. mov %dx,%es
    13. movl $0x17,%edx # fs points to local data space
    14. mov %dx,%fs
    15. call _sys_call_table(,%eax,4) //调用系统调用函数表中对应的系统调用
    16. pushl %eax
    17. movl _current,%eax
    18. cmpl $0,state(%eax) # state
    19. jne reschedule
    20. cmpl $0,counter(%eax) # counter
    21. je reschedule
    22. ret_from_sys_call:
    23. movl _current,%eax # task[0] cannot have signals
    24. cmpl _task,%eax
    25. je 3f
    26. cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
    27. jne 3f
    28. cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
    29. jne 3f
    30. movl signal(%eax),%ebx
    31. movl blocked(%eax),%ecx
    32. notl %ecx
    33. andl %ebx,%ecx
    34. bsfl %ecx,%ecx
    35. je 3f
    36. btrl %ecx,%ebx
    37. movl %ebx,signal(%eax)
    38. incl %ecx
    39. pushl %ecx
    40. call _do_signal //执行do_signal 系统调用
    41. popl %eax
    42. 3: popl %eax
    43. popl %ebx
    44. popl %ecx
    45. popl %edx
    46. pop %fs
    47. pop %es
    48. pop %ds
    49. iret

    由于C函数是传值函数,因此给eip赋值时需要使用'*(&eip)'的形式。

    1. //系统调用中断处理程序中的信号处理程序
    2. void do_signal(long signr,long eax, long ebx, long ecx, long edx,
    3. long fs, long es, long ds,
    4. long eip, long cs, long eflags,
    5. unsigned long * esp, long ss)
    6. {
    7. unsigned long sa_handler;
    8. long old_eip=eip;
    9. /*
    10. struct sigaction sigaction[32];
    11. current->sigaction + signr - 1 指向对应signr的sigaction
    12. */
    13. struct sigaction * sa = current->sigaction + signr - 1;
    14. int longs;
    15. unsigned long * tmp_esp;
    16. sa_handler = (unsigned long) sa->sa_handler;
    17. //#define SIG_DFL ((void (*)(int))0) /* default signal handling */
    18. //#define SIG_IGN ((void (*)(int))1) /* ignore signal */
    19. if (sa_handler==1)/* ignore signal */
    20. return;
    21. if (!sa_handler) {/* default signal handling */
    22. if (signr==SIGCHLD)//signr=SIGCHLD 没有定义处理函数 则返回
    23. return;
    24. else
    25. //do_exit 处理当前进程退出过程,当前进程已经死亡
    26. do_exit(1<<(signr-1));
    27. }
    28. if (sa->sa_flags & SA_ONESHOT)//该信号句柄仅仅需要使用一次,sa->sa_handler 置空
    29. sa->sa_handler = NULL;
    30. //将信号处理函数插入到用户堆栈。本次系统调用中断(0x80)返回用户程序时会先执行该信号处理函数
    31. //然后继续执行用户程序
    32. *(&eip) = sa_handler;
    33. longs = (sa->sa_flags & SA_NOMASK)?7:8;
    34. *(&esp) -= longs;
    35. verify_area(esp,longs*4);
    36. tmp_esp=esp;
    37. put_fs_long((long) sa->sa_restorer,tmp_esp++);
    38. put_fs_long(signr,tmp_esp++);
    39. if (!(sa->sa_flags & SA_NOMASK))
    40. put_fs_long(current->blocked,tmp_esp++);
    41. put_fs_long(eax,tmp_esp++);
    42. put_fs_long(ecx,tmp_esp++);
    43. put_fs_long(edx,tmp_esp++);
    44. put_fs_long(eflags,tmp_esp++);
    45. put_fs_long(old_eip,tmp_esp++);
    46. current->blocked |= sa->sa_mask;
    47. }

    sys_signal

     signal()系统调用。类似于sigaction()。为指定的信号安装新的信号句柄(信号处理程序)。 信号句柄可以是用户指定的函数,也可以是SIG_DFL(默认句柄)或SIG_IGN(忽略)。参数signum --指定的信号;handler --指定的句柄;restorer --恢复函数指针,该函数由Libc库提供。用于在信号处理程序结束后恢复系统调用返回时几个寄存器的原有值以及系统 调用的返回值,就好像系统调用没有执行过信号处理程序而直接返回到用户程序一样。 函数返回原信号句柄。
     

    1. int sys_signal(int signum, long handler, long restorer)
    2. {
    3. 设置分配一个信号结构体
    4. struct sigaction tmp;
    5. 检索信号范围要在1-32并且不是终止信号
    6. if (signum<1 || signum>32 || signum==SIGKILL)
    7. return -1;
    8. 指定信号处理句柄
    9. tmp.sa_handler = (void (*)(int)) handler;
    10. 设置屏蔽码
    11. tmp.sa_mask = 0;
    12. 设置改信号的状态为只可执行一次就恢复到默认值
    13. tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
    14. 保存回复处理程序指针
    15. tmp.sa_restorer = (void (*)(void)) restorer;
    16. 更新当先标识指针的信号信息
    17. handler = (long) current->sigaction[signum-1].sa_handler;
    18. current->sigaction[signum-1] = tmp;
    19. return handler;
    20. }

  • 相关阅读:
    python习题004--使用python实现ATM机效果
    JDBC整合C3P0,DBCP,DRUID数据库连接池
    NGINX源码之:目录导航
    Android逆向第一步之开启root权限
    fmp4打包H264详解
    C<6.1>函数习题(函数内测整形数组大小,递归
    以clion为例记录一次基于docker环境配置开发
    查看Linux系统信息的常用命令
    JavaEE:网络编程
    关于 G1(Garbage First)垃圾收集器
  • 原文地址:https://blog.csdn.net/LIJIWEI0611/article/details/126352078