| .\" Copyright (c) 1995 Michael Chastain (mec@duracef.shout.net), 22 July 1995. |
| .\" Copyright (c) 2015 Andrew Lutomirski |
| .\" |
| .\" %%%LICENSE_START(GPLv2+_DOC_FULL) |
| .\" This is free documentation; you can redistribute it and/or |
| .\" modify it under the terms of the GNU General Public License as |
| .\" published by the Free Software Foundation; either version 2 of |
| .\" the License, or (at your option) any later version. |
| .\" |
| .\" The GNU General Public License's references to "object code" |
| .\" and "executables" are to be interpreted as the output of any |
| .\" document formatting or typesetting system, including |
| .\" intermediate and printed output. |
| .\" |
| .\" This manual is distributed in the hope that it will be useful, |
| .\" but WITHOUT ANY WARRANTY; without even the implied warranty of |
| .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| .\" GNU General Public License for more details. |
| .\" |
| .\" You should have received a copy of the GNU General Public |
| .\" License along with this manual; if not, see |
| .\" <http://www.gnu.org/licenses/>. |
| .\" %%%LICENSE_END |
| .\" |
| .TH MODIFY_LDT 2 2021-03-22 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| modify_ldt \- get or set a per-process LDT entry |
| .SH SYNOPSIS |
| .nf |
| .BI "int modify_ldt(int " func ", void *" ptr ", unsigned long " bytecount ); |
| .fi |
| .PP |
| .IR Note : |
| There is no glibc wrapper for this system call; see NOTES. |
| .SH DESCRIPTION |
| .BR modify_ldt () |
| reads or writes the local descriptor table (LDT) for a process. |
| The LDT |
| is an array of segment descriptors that can be referenced by user code. |
| Linux allows processes to configure a per-process (actually per-mm) LDT. |
| For more information about the LDT, see the Intel Software Developer's |
| Manual or the AMD Architecture Programming Manual. |
| .PP |
| When |
| .I func |
| is 0, |
| .BR modify_ldt () |
| reads the LDT into the memory pointed to by |
| .IR ptr . |
| The number of bytes read is the smaller of |
| .I bytecount |
| and the actual size of the LDT, although the kernel may act as though |
| the LDT is padded with additional trailing zero bytes. |
| On success, |
| .BR modify_ldt () |
| will return the number of bytes read. |
| .PP |
| When |
| .I func |
| is 1 or 0x11, |
| .BR modify_ldt () |
| modifies the LDT entry indicated by |
| .IR ptr\->entry_number . |
| .I ptr |
| points to a |
| .I user_desc |
| structure |
| and |
| .I bytecount |
| must equal the size of this structure. |
| .PP |
| The |
| .I user_desc |
| structure is defined in \fI<asm/ldt.h>\fP as: |
| .PP |
| .in +4n |
| .EX |
| struct user_desc { |
| unsigned int entry_number; |
| unsigned int 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; |
| }; |
| .EE |
| .in |
| .PP |
| In Linux 2.4 and earlier, this structure was named |
| .IR modify_ldt_ldt_s . |
| .PP |
| The |
| .I contents |
| field is the segment type (data, expand-down data, non-conforming code, or |
| conforming code). |
| The other fields match their descriptions in the CPU manual, although |
| .BR modify_ldt () |
| cannot set the hardware-defined "accessed" bit described in the CPU manual. |
| .PP |
| A |
| .I user_desc |
| is considered "empty" if |
| .I read_exec_only |
| and |
| .I seg_not_present |
| are set to 1 and all of the other fields are 0. |
| An LDT entry can be cleared by setting it to an "empty" |
| .I user_desc |
| or, if |
| .I func |
| is 1, by setting both |
| .I base |
| and |
| .I limit |
| to 0. |
| .PP |
| A conforming code segment (i.e., one with |
| .IR contents==3 ) |
| will be rejected if |
| .I |
| func |
| is 1 or if |
| .I seg_not_present |
| is 0. |
| .PP |
| When |
| .I func |
| is 2, |
| .BR modify_ldt () |
| will read zeros. |
| This appears to be a leftover from Linux 2.4. |
| .SH RETURN VALUE |
| On success, |
| .BR modify_ldt () |
| returns either the actual number of bytes read (for reading) |
| or 0 (for writing). |
| On failure, |
| .BR modify_ldt () |
| returns \-1 and sets |
| .I errno |
| to indicate the error. |
| .SH ERRORS |
| .TP |
| .B EFAULT |
| .I ptr |
| points outside the address space. |
| .TP |
| .B EINVAL |
| .I ptr |
| is 0, |
| or |
| .I func |
| is 1 and |
| .I bytecount |
| is not equal to the size of the structure |
| .IR user_desc , |
| or |
| .I func |
| is 1 or 0x11 and the new LDT entry has invalid values. |
| .TP |
| .B ENOSYS |
| .I func |
| is neither 0, 1, 2, nor 0x11. |
| .SH CONFORMING TO |
| This call is Linux-specific and should not be used in programs intended |
| to be portable. |
| .SH NOTES |
| Glibc does not provide a wrapper for this system call; call it using |
| .BR syscall (2). |
| .PP |
| .BR modify_ldt () |
| should not be used for thread-local storage, as it slows down context |
| switches and only supports a limited number of threads. |
| Threading libraries should use |
| .BR set_thread_area (2) |
| or |
| .BR arch_prctl (2) |
| instead, except on extremely old kernels that do not support those system |
| calls. |
| .PP |
| The normal use for |
| .BR modify_ldt () |
| is to run legacy 16-bit or segmented 32-bit code. |
| Not all kernels allow 16-bit segments to be installed, however. |
| .PP |
| Even on 64-bit kernels, |
| .BR modify_ldt () |
| cannot be used to create a long mode (i.e., 64-bit) code segment. |
| The undocumented field "lm" in |
| .IR user_desc |
| is not useful, and, despite its name, |
| does not result in a long mode segment. |
| .SH BUGS |
| On 64-bit kernels before Linux 3.19, |
| .\" commit e30ab185c490e9a9381385529e0fd32f0a399495 |
| setting the "lm" bit in |
| .IR user_desc |
| prevents the descriptor from being considered empty. |
| Keep in mind that the |
| "lm" bit does not exist in the 32-bit headers, but these buggy kernels |
| will still notice the bit even when set in a 32-bit process. |
| .SH SEE ALSO |
| .BR arch_prctl (2), |
| .BR set_thread_area (2), |
| .BR vm86 (2) |