Linux内核栈初始化的一个小细节
来源:互联网 发布:cocos2d js 源码 编辑:程序博客网 时间:2024/04/28 05:02
今天遇到一个有趣的问题:
内核栈的栈底(高地址)8个字节是预留出来处理bug的,所以在寻找栈底的时候用到这个宏:
#define task_pt_regs(task) /
({ /
struct pt_regs *__regs__; /
__regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); /
__regs__ - 1; /
})
KSTK_TOP是实质工作的函数,定义如下:
#define KSTK_TOP(info) /
({ /
unsigned long *__ptr = (unsigned long *)(info); /
(unsigned long)(&__ptr[THREAD_SIZE_LONGS]); /
})
info就是tsk->thread_info这个地址,就是内核栈的起始地址。
THREAD_SIZE_LONGS = THREAD_SIZE / sizeof(unsigned long),也就是THREAD_SIZE包含多少个unsigned long。
因此这里,&__ptr[THREAD_SIZE_LONGS] = &(*(__ptr + THREAD_SIZE_LONG)) = __ptr + THREAD_SIZE_LONG,即,KSTK_TOP这个宏返回的是内核栈的栈底,回到task_pt_regs,再用KSTK_TOP(task_stack_page(task))-8留出8个字节。
问题出在这里:之前定义的__ptr是unsigned long *类型的指针,即__ptr每次移动1,就会跳过unsigned long(4Bytes)的内存空间,那么,KSTK_TOP(task_stack_page(task))-8不就相当于"-8*sizeof(unsigned long)"了么?
秘密就在(unsigned long)(&__ptr[THREAD_SIZE_LONGS])这条语句中。它将得到的地址转化为unsigned long型,这个转化的作用就在于,得到的&__ptr[THREAD_SIZE_LONGS]这个地址-8相当于减去8个字节,而不是8个unsigned long。
我做了一个简单的实验:
#include <stdio.h>
int
main()
{
int* int_address;
unsigned long unsigned_long_address = (unsigned long)int_address;
printf("at the beginning, int_address = 0x%u, and unsigned_long_address = 0x%u.../n", int_address, unsigned_long_address);
printf("/nthen, int_address + 1 = 0x%u/nunsigned_long_address + 1 = 0x%u/n", int_address + 1, unsigned_long_address + 1);
return 0;
}
这里声明了一个int*类型的指针int_address,它是一个指向int大小(4bytes)的地址;
还有一个无符号长整型unsigned_long_address,它的作用是将int_address这个地址转化成一个无符号长整型数。
让这两个变量分别+1,得到如下结果:
at the beginning, int_address = 0x134513723, and unsigned_long_address = 0x134513723...
then, int_address + 1 = 0x134513727
unsigned_long_address + 1 = 0x134513724
可以看到,开始两个变量的值是相同的,但是分别+1之后,由于int_address是指向一个int大小的地址,所以它每次加1就会自动跳过4个字节,地址变成0x134513727;而unsigned_long_address只不过是一个普通的长整型数,所以它得到正常的+1结果。
现在回到KSTK_TOP(task_stack_page(task))-8,由于KSTK_TOP(task_stack_page(task))这个地址转换成了unsigned long的无符号长整型数,所以,-8就相当于减去了8个字节,现在明白了将一个地址转换成为整数的巨大作用了!!!
在task_pt_regs最后执行__regs__ - 1,由于__regs__转换成了struct pt_regs *类型指针,所以-1操作相当于跳过了
sizeof pt_regs这么多字节的空间了。
- Linux内核栈初始化的一个小细节
- 转 关于二维数组初始化的一个小细节
- cin的一个小细节
- 一个有意思的小细节
- @protocol的一个小细节
- URLClassLoader 的一个小细节
- linux内核中协议栈--tcp实现的一点细节
- linux内核中协议栈--tcp实现的一点细节
- Linux内核bootsect.S的一个小BUG
- GPIO初始化小细节1
- C++ 小细节,成员初始化
- linux内核抢占的几个细节
- linux内核抢占的几个细节
- 头文件包含的一个小细节
- 多核处理中断的一个小细节
- jdbc操作的一个小细节
- c++ #ifndef注意的一个小细节
- go run的一个小细节
- 爱
- 目录
- 脚本中export不起作用的原因分析
- JAVA IO 流操作
- 摄像头(WebCam)在Linux操作系统中的驱动方法
- Linux内核栈初始化的一个小细节
- 路由协议的比较(自己整理的,忘了就看看)
- 所谓"在表达式中,数组名总是被转换为指向该数组第一个元素的指针"应该如何理解?
- C#中的底层音频控制播放
- 看完《人生》,图书馆外面又飘起了白雪····
- geotools 在eclipse中的导入
- [教程]逆向反汇编第五课
- 精妙的SQL语句
- [教程]逆向反汇编第六课