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 устанавливается в соответствующее значение.

ОШИБКИ

EFAULT
    Значение ptr указывает за пределы адресного пространства.

EINVAL
    Значение ptr равно 0, или func равно 1, а bytecount не равно размеру структуры user_desc, или func равно 1 или 0x11, а новый элемент LDT содержит неправильные значения.

ENOSYS
    Значение func не равно 0, 1, 2 или 0x11.

СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов есть только в 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-битном процессе.

СМОТРИТЕ ТАКЖЕ
arch_prctl(2), set_thread_area(2), vm86(2)