- 论坛徽章:
- 2
|
回复 1# embeddedlwp
其实我并不是专门研究kernel的。只是偶尔会碰上一些讨论恰好与kernel有关,比如这帖。 所以分析中带有许多猜测……
1. module_init/module_exit 应该是宏
C语言是不允许top level中调用函数的
2. module_init与module_exit展开后的代码编译后得到的应该分别是 init_module/cleanup_module
源代码里 __asm__ __volatile__("movl %%cr3, %0":"=r"(pgd_pa)) 是出现在 test_init 里
反汇编得到的
mov %cr3,%eax
mov %eax,0x4(%esp)
在 init_module 里
3. cleanup_module
我不明白空函数 test_exit 经过 module_exit 展开后为什么会产生一个函数调用。
但抛开 test_exit/module_exit与 cleanup_mode 之间的关联,仅仅分析 cleanup_module还是很容易的。
这就是最普通的函数,调用了另一个函数。
push %ebp
mov %esp,%ebp ; 这两句是prologue,会在栈上保存一个完整的调用链。
call 4 ; 这是一个函数调用,操作数fc ff ff ff只是一个桩,重定位节中会记录链接时此4字节应该被修正为什么 —— 即被调用函数
; 只从反汇编是看不出被调用函数的。
; 若想了解究竟调用了哪个函数, 如ls所说,要看 rel 节
pop %ebp ; 与上面的prologue对应,将调用链的末尾出栈
ret ; 返回
4. init_module
4.1 先把 prologue/epilogue 去掉
push %ebp
mov %esp,%ebp
...
leave
ret
余下的代码与 test_init 的对应关系就很清楚了
4.2 sub $0x8,%esp
这8字节将作为 printk 的参数
4.3 __asm__ __volatile__("movl %%cr3, %0":"=r"(pgd_pa));
mov %cr3,%eax
没有为pgd_pa变量分配内存,而是使用eax。
初值 int*pgd_pa=NULL; 被优化,没有先赋值为0,而是直接获取 cr3 的值。
4.4 printk("cr3 is %p\n", pgd_pa);
mov %eax,0x4(%esp) ; 传递pgd_pa的值
movl $0x0,(%esp) ; 传递 "cr3 is %p\n" 的地址
call 15 ; 调用 printk
后面两条指令中的操作数都是桩。
重定位节中会有相应的数据,使得链接器可以在链接时将操作数修正为 "cr3 is %p\n" 的地址 与 printk 的偏移。
4.5 return 0;
xor %eax,%eax |
|