Linux kernel data structures (Part 1) - the current macro

Note: I have used linux kernels 2.4.18 and 2.6.0 for this tutorial.

The Linux kernel uses this macro to find the current process. The current macro is defined in include/asm-i386/current.h (line 13) in both 2.6.0 and 2.4.18 kernels. This macro calls another function get_current(). The difference is that, in Linux 2.4.18 get_current()(line 6 – 11, include/asmi386/current.h) is itself used to find the address of the current process but in Linux 2.6.0 get_current() in turn calls another function current_thread_info() defined in include/asm-i386/thread_info.h (lines 81 – 86).

For 2.4.18, struct task_struct* get_current() contains:

struct task_struct *current; __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); return current;

For 2.6.0, struct thread_info* current_thread_info() contains:

struct thread_info *ti; __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~8191UL)); return ti;

Note: The use of 8191. I'll explain that in detail below.

In 2.6.0, on return from current_thread_info(), get_current() simply returns the value of the task pointer by doing the following (line 10, include/asm-i386/current.h):

return current_thread_info()->task;

For both kernels, the main functions do the following:

The value of the kernel stack pointer is somewhere within the task_union (or thread_union for 2.6.0); (will talk about them later) 8191 decimal is 0001 1111 1111 1111 binary. Inverting that gives 1110 0000 0000 0000. This effectively strips off the low-order 13 bits of the stack pointer value, aligning it at the beginning of the task_union(or thread_union for 2.6.0). This is also the beginning of the task_struct (for 2.4.18) and thread_info (for 2.6.0).

What are task_union (2.4.18) and thread_union (2.6.0)?

They are unions that share space with an array of unsigned long. Both these structures are defined in include/linux/sched.h. Definition is below.

For 2.4.18:

507: #ifndef INIT_TASK_SIZE 508: # define INIT_TASK_SIZE 2048*sizeof(long) 509: #endif 510: 511: union task_union { 512: struct task_struct task; 513: unsigned long stack[INIT_TASK_SIZE/sizeof(long)]; 514: };

For 2.6.0:

536: #ifndef INIT_THREAD_SIZE 537: # define INIT_THREAD_SIZE 2048*sizeof(long) 538: #endif 539: 540: union thread_union { 541: struct thread_info thread_info; 542: unsigned long stack[INIT_THREAD_SIZE/sizeof(long)]; 543: };

Did this tutorial help a little? How about buy me a cup of coffee?

Buy me a coffee at ko-fi.com

Please feel free to use the comments form below if you have any questions or need more explanation on anything. I do not guarantee a response.

IMPORTANT: You must thoroughy test any instructions on a production-like test environment first before trying anything on production systems. And, make sure it is tested for security, privacy, and safety. See our terms here.