Вопрос по linux-kernel, linux – Понимание получения указателя task_struct из стека ядра процесса

4

Прямо сейчас я читаю книгу "Linux Kernel Development 3d Edition". Роберт Лав. Там он пишет о структуре thread_info, которая содержит указатель на структуру task_struct и, как я понял, расположена внизу или вверху стека ядра процесса (зависит от архитектуры). До недавнего времени я не был знаком с API ядра Linux и не знал о существовании метода current (). В книге есть выдержка, связанная с тем, как на самом деле работает метод current ():

On x86, current is calculated by masking out the 13 least-significant bits of the stack pointer to obtain the thread_info structure.This is done by the current_thread_info() function.The assembly is shown here: movl $-8192, %eax andl %esp, %eax This assumes that the stack size is 8KB.When 4KB stacks are enabled, 4096 is used in lieu of 8192.

Мои вопросы:

As far as I know if we have a decimal value represented as a set of bits, then there is only one least-significant bit in the set, isn't it? What is the magical number 13?

Для тех, кто будет читать эту тему, вопросы, которые я озвучил, могут привести к выводу, что автор не правильно понимает процесс выделения памяти и администрирования. Хорошо, это может быть правильно из-за того факта, что я могу представить память, выделенную для стека, как ленту, полную битов (или байтов). Все эти байты доступны по определенному адресу памяти, представленному в виде некоторого десятичного значения. Начало стека - самый низкий адрес памяти, а плавник стека - самое высокое значение адреса памяти. Но КАК, КАК мы можем получить указатель на структуру thread_info, расположенную, скажем, в конце стека, только путем маскировки 13 наименее значимых битов указателя стека, расположенных в ARBITRARY (если я правильно понял, мы маскируем биты указатель стека АДРЕС представлен в виде десятичного значения).

подсказка: от 2 до степени 13 = 8192 (т.е. размер стека), а десятичное значение -8192 - это шестнадцатеричное 0xFFFFE000 (как представлено в 32 битах на платформе с 2 дополнениями). nos
Вы говорите «десятичное значение» несколько раз - вам, вероятно, лучше подумать о двоичных значениях, особенно чтобы попытаться понять, как работает маскирование. mpe

Ваш Ответ

4   ответа
0

Мои 2 бита: обратите внимание, что реализация 'current' apos; зависит от арки. Пока ответы сосредоточены на x86; различные средства доступа к thread_info и, таким образом, task_struct используются другими архивами в ОС Linux.

Например, очевидно, что PPC использует регистр (это RISC, помните, с большим количеством GPR) для хранения значения текущего эффекта, делая его частью аппаратного контекста! Это будет очень быстро.

Современный порт x86 (я искал исходники ядра 4.1.0) использует данные для каждого процессора для быстрой и беспроблемной реализации тока. И так далее...

0

But HOW, HOW can we get the the pointer to the thread_info struct located at the, say, end of the stack only by masking out 13 least-significant bits of ARBITRARY located stack pointer

Обратите внимание, что как нижний, так и предельный (верхний) адрес (при условии, что нижний стек с более высоким адресом расположен внизу) ДОЛЖЕН БЫТЬ кратным размеру стека. Например, если размер стека равен 8192 (= 2 ^ 13), все 13 младших разрядов должны быть равны 0 как для нижнего, так и для предельного адреса. Младший 13-разрядный бит НЕ является АРБИТРАЖНЫМ в том смысле, что он дает смещение между нижним адресом и предельным адресом, которые оба заканчиваются на 13 0 '. Таким образом, маскирование младших значащих 13 битов дает вам адрес предельного адреса, в котором находится структура thread_info.

3

Стек ядра содержит специальную структуру вверху -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 вам нужно получитьthread_info указатель сGET_THREAD_INFO из ASM-кода:

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

... или сcurrent_thread_info из C-кода:

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 }

Обратите внимание, чтоTHREAD_SIZE определяется как(PAGE_SIZE << THREAD_SIZE_ORDER) а такжеTHREAD_SIZE_ORDER равно 1 для x86_32 и x86_64, такTHREAD_SIZE результаты до 8192 (2 ^ 13 или 1 & lt; & lt; 13).

4

Каждый процесс получает только 8192 байта стека ядра, выровненного по границе 8192 байта, поэтому всякий раз, когда указатель стека изменяется нажатием или попом, младшие 13 бит являются единственной частью, которая изменяется. 2 ** 13 == 8192.

Похожие вопросы