了解从进程内核堆栈获取task_struct指针

现在我正在阅读Robert love的“Linux Kernel Development 3D Edition”一书。 在那里,他写了关于包含指向task_struct结构的指针的thread_info结构,据我所知,它位于进程的内核堆栈的底部或顶部(取决于体系结构)。 直到最近我还不熟悉Linux内核API,并且我不知道current()方法的存在。 这本书摘录了与current()方法实际工作有关的内容

在x86上,通过屏蔽掉堆栈指针的13个最低有效位来计算当前值,以获得thread_info结构。这由current_thread_info()函数完成。程序集如下所示:movl $ -8192,%eax andl% esp,%eax这里假定堆栈大小为8KB。当启用4KB堆栈时,将使用4096代替8192。

我的问题是:

据我所知,如果我们有一个十进制值表示为一组位,那么在这个集合中只有一个最低有效位,不是吗?

什么是神奇的13号?

对于这个话题的读者来说,我所提出的问题可能会导致作者不能正确理解内存分配和pipe理的过程。 好吧,这可能是正确的,因为在我的脑海里,我可以代表为堆栈分配的内存作为带(或字节)的带。 所有这些字节都可以通过一个特定的内存地址来访问,这个地址表示为一些小数值 堆栈的来源是最低的内存地址,堆栈的最高位是内存地址的最高值。 但是,怎样才能得到指向位于堆栈末端的thread_info结构的指针,只需要屏蔽出位于堆栈指针的13位最低有效位(如果我理解正确的话,我们可以屏蔽掉堆栈指针ADDRESS以十进制值表示)。

将ELF共享库和自定义binfmt可执行文件加载到相同的Linux地址空间中

如何为平台驱动程序正确初始化属性组?

从程序员的angular度来看Linux内核和UNIX内核(如FreeBSD)之间的区别

Linux上的软件声音取消(破坏性干扰)工具?

nm命令输出中的奇怪符号名称

在脚本中打开编辑器时打开文件

是否有可能从一个打开的文件描述符重新创build一个文件

Linux C ++项目目录布局 – CMake

Git手册页似乎不正确

Eclipse CDTdebugging:步入cout不起作用

内核堆栈顶部包含一个特殊的结构体 – thread_info :

26 struct thread_info { 27 struct task_struct *task; /* main task structure */ 28 struct exec_domain *exec_domain; /* execution domain */ 29 __u32 flags; /* low level flags */ 30 __u32 status; /* thread synchronous flags */ 31 __u32 cpu; /* current cpu */ 32 int preempt_count; /* 0 => preemptable,33 <0 => BUG */ 34 mm_segment_t addr_limit; 35 struct restart_block restart_block; 36 void __user *sysenter_return; 37 #ifdef CONfig_X86_32 38 unsigned long prevIoUs_esp; /* ESP of the prevIoUs stack in 39 case of nested (IRQ) stacks 40 */ 41 __u8 supervisor_stack[0]; 42 #endif 43 unsigned int sig_on_uaccess_error:1; 44 unsigned int uaccess_err:1; /* uaccess Failed */ 45 };

所以,要得到task_struct你需要从ASM代码中得到一个GET_THREAD_INFO的thread_info指针:

183 /* how to get the thread information struct from ASM */ 184 #define GET_THREAD_INFO(reg) 185 movl $-THREAD_SIZE,reg; 186 andl %esp,reg

…或来自C代码的current_thread_info :

174 /* how to get the thread information struct from C */ 175 static inline struct thread_info *current_thread_info(void) 176 { 177 return (struct thread_info *) 178 (current_stack_pointer & ~(THREAD_SIZE - 1)); 179 }

请注意,对于x86_32和x86_64, THREAD_SIZE定义为(PAGE_SIZE << THREAD_SIZE_ORDER)和THREAD_SIZE_ORDER等于1,所以THREAD_SIZE结果为8192(2 ^ 13或1 << 13)。

每个进程只获得8192个字节的内核堆栈,并对齐到一个8192字节的边界,所以每当堆栈指针被一个push或者一个pop改变时,低13位是唯一改变的部分。 2 ** 13 == 8192。

但是,怎样才能得到指向位于堆栈末端的thread_info结构的指针,只需要屏蔽掉位于堆栈指针位置的13个最低有效位

请注意,底部和限制(顶部)地址(假设位于底部的具有较高地址的自下而上堆栈)必须是堆栈大小的倍数。 例如,如果堆栈大小为8192(= 2 ^ 13),则底部和限制地址的13个最低有效位必须全为0。 最不重要的13位在某种意义上是非底层地址和限制地址之间的偏移量,它们都以13 0结束。 因此,掩盖掉最不重要的13位给出了限制地址的地址,这是thread_info结构所在的位置。

我的2位:请注意,“当前”的实现是依赖于拱的。 到目前为止的答案都集中在x86; 在Linux操作系统上,各种获取thread_info和task_struct的方法被其他的arch使用。

例如,显然PPC使用一个寄存器(这是RISC,记住,有大量的GPRs)来存储当前的值 – 实际上是将其作为硬件环境的一部分! 这将是非常快的。

现代x86端口(我查阅了4.1.0内核源代码)使用per-cpu数据以快速和无锁的方式实现电流。 等等…

相关文章

### 创建一个gRPC服务项目(grpc服务端)和一个 webapi项目(...
一、SiganlR 使用的协议类型 1.websocket即时通讯协议 2.Ser...
.Net 6 WebApi 项目 在Linux系统上 打包成Docker镜像,发布为...
一、 PD简介PowerDesigner 是一个集所有现代建模技术于一身的...
一、存储过程 存储过程就像数据库中运行的方法(函数) 优点:...
一、Ueditor的下载 1、百度编辑器下载地址:http://ueditor....