异常表的实现机制
笔者取include/asm-i386/uaccess.h中的宏定义__copy_user编写了一段程序作为例子加以讲解。
/* hello.c */
#include #include
#define __copy_user(to,from,size) do { int __d0, __d1; __asm__ __volatile__ ( "0: rep; movsl\n" " movl %3,%0\n" "1: rep; movsb\n" "2:\n" ".section .fixup,\"ax\"\n" "3: lea 0(%3,%0,4),%0\n" " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 0b,3b\n" " .long 1b,2b\n" ".previous" : "=&c"(size), "=&D" (__d0), "=&S" (__d1) : "r"(size & 3), "0"(size / 4), "1"(to), "2"(from) : "memory"); } while (0)
int main(void) { const char *string = "Hello, world!"; char buf[20]; unsigned long n, m;
m = n = strlen(string); __copy_user(buf, string, n); buf[m] = '\0'; printf("%s\n", buf); exit(0); }
先看看本程序的执行结果:
$ gcc hello.c -o hello $ ./hello Hello, world!
显然,这就是一个简单的"hello world"程序,那为什么要写得这么复杂呢?程序中的一大段汇编代码在内核中才能体现出其价值,笔者将其加入到上面的程序中,是为了后面的分析而准备的。
系统在核心态运行的时候,参数是通过寄存器来传递的,由于寄存器所能够传递的信息有限,所以传递的参数大多数是指针。要使用指针所指向的更大块的数据,就需要将用户空间的数据拷贝到系统空间来。上面的__copy_user在内核中正是扮演着这样的一个拷贝数据的角色,当然,内核中这样的宏定义还很多,笔者也只是取其中的一个来讲解,读者如果感兴趣的话可以看完本文以后自行学习。
如果读者对于简单的嵌入式汇编还不是很了解的话,可以参考《Linux内核源代码情景分析》一书。下面我们将程序编译成汇编程序来加以分析:
|