MODIFY_LDT(2) | Руководство программиста Linux | MODIFY_LDT(2) |
modify_ldt - возвращает или изменяет запись LDT у процесса
#include <sys/types.h>
int modify_ldt(int func, void *ptr, unsigned long bytecount);
Замечание: В glibc нет обёрточной функции для данного системного вызова; смотрите ЗАМЕЧАНИЯ.
Вызов modify_ldt() считывает или записывает таблицу локальных дескрипторов (LDT) процесса. LDT представляет собой массив дескрипторов сегментов, которые могут использоваться в пользовательском коде. В Linux процессам разрешено настраивать попроцессные (в действительности, пространство памяти) LDT. Дополнительную информацию о LDT, смотрите в Intel Software Developer's Manual или AMD Architecture Programming Manual.
Если func равно 0, то modify_ldt() читает LDT в память, на которую указывает ptr. Количество читаемых байт — меньшее из bytecount и реального размера LDT несмотря на то, что ядро может действовать как будто LDT заполняется дополнительными нулевыми байтами в конце. При успешном выполнении modify_ldt() возвращает количество прочитанных байт.
Если значение func равно 1 или 0x11, то modify_ldt() изменяет запись LDT, на которую указывает ptr->entry_number. Значение ptr указывает на структуру user_desc, а bytecount должно быть равно размеру этой структуры.
Структура user_desc определена в <asm/ldt.h> следующим образом:
struct user_desc { unsigned int entry_number; unsigned long base_addr; unsigned int limit; unsigned int seg_32bit:1; unsigned int contents:2; unsigned int read_exec_only:1; unsigned int limit_in_pages:1; unsigned int seg_not_present:1; unsigned int useable:1; };
В Linux версии 2.4 и более ранних эта структура называлась modify_ldt_ldt_s.
В поле contents определяется тип сегмента (данные, данные, расширяемые вниз (expand-down data), не соответствующий код (non-conforming code) или соответствующий код). Назначение других полей совпадает с их описанием в руководстве к процессору, несмотря на то, что modify_ldt() не может изменить аппаратно-определяемый бит «доступа», описанный в руководстве к ЦП.
A user_desc считается «пустым», если read_exec_only и seg_not_present равны 1, а все остальные поля равны 0. Элемент LDT можно очистить, назначив ему «пустой» user_desc или, если func равно 1, установив base и limit в 0.
Сегмент соответствующего кода (conforming code segment, т. е., с contents==3) будет отклонён, если func равно 1 или если seg_not_present равно 0.
Если func равно 2, то modify_ldt() прочитает нули. Это, кажется, пережиток из Linux 2.4.
При успешном выполнении modify_ldt() возвращается реальное количество прочитанных байт (при чтении) или 0 (при записи). При ошибке modify_ldt() возвращает -1, а errno устанавливается в соответствующее значение.
Данный вызов есть только в Linux и не должен использоваться в программах, которые должны быть переносимыми.
В glibc нет обёртки для данного системного вызова; запускайте его с помощью syscall(2).
Вызов modify_ldt() не должен использоваться для локального хранилища нити, так как это замедляет переключение контекста и поддерживается только для ограниченного количества нитей. Вместо этого в библиотеках нитей должны использоваться set_thread_area(2) или arch_prctl(2), только если не нужна поддержка старых ядер, где нет этих вызовов.
Обычно, modify_ldt() используют для запуска старого 16-битного или сегментированного 32-битного кода. Однако, не все ядра допускают установку 16-битных сегментов.
Даже в 64-битных ядрах вызов modify_ldt() нельзя использовать для создания сегмента кода в длинном режиме (т. е., 64-битного). Недокументированное поле «lm» в user_desc не помогает и, несмотря на имя, не образует сегмент в длинном режиме.
В 64-битных ядрах до Linux 3.19, установка бита «lm» в user_desc приводила к тому, что дескриптор переставал считаться пустым. Учтите, что бит «lm» не существует в 32-битных заголовках, но есть дефектные ядра, которые по-прежнему сообщают о бите даже в 32-битном процессе.
2017-09-15 | Linux |