---
name: "modify_ldt"
section: "2"
platform: "linux"
package: "man-pages"
version: "6.19-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/modify_ldt"
---

# modify\_ldt(2)

get or set a per-process LDT entry

## NAME

modify\_ldt - get or set a per-process LDT entry

## LIBRARY

Standard C library (*libc*, *-lc*)

## SYNOPSIS

```
#include <asm/ldt.h>         /* Definition of struct user_desc */
#include <sys/syscall.h>     /* Definition of SYS_* constants */
#include <unistd.h>
```

**int syscall(**unsigned long bytecount;             **SYS\_modify\_ldt, int** *func***, void** *ptr***\[***bytecount***\],**             **unsigned long** *bytecount***);**

*Note*: glibc provides no wrapper for **modify\_ldt**(), necessitating the use of [**syscall**(2)](/syscall/2.md).

## DESCRIPTION

**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.

When *func* is 0, **modify\_ldt**() reads the LDT into the memory pointed to by *ptr*. The number of bytes read is the smaller of *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, **modify\_ldt**() will return the number of bytes read.

When *func* is 1 or 0x11, **modify\_ldt**() modifies the LDT entry indicated by *ptr-\>entry\_number*. *ptr* points to a *user\_desc* structure and *bytecount* must equal the size of this structure.

The *user\_desc* structure is defined in *\<asm/ldt.h\>* as:

```
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;
};
```

In Linux 2.4 and earlier, this structure was named *modify\_ldt\_ldt\_s*.

The *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 **modify\_ldt**() cannot set the hardware-defined "accessed" bit described in the CPU manual.

A *user\_desc* is considered "empty" if *read\_exec\_only* and *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" *user\_desc* or, if *func* is 1, by setting both *base* and *limit* to 0.

A conforming code segment (i.e., one with *contents==3*) will be rejected if *func* is 1 or if *seg\_not\_present* is 0.

When *func* is 2, **modify\_ldt**() will read zeros. This appears to be a leftover from Linux 2.4.

## RETURN VALUE

On success, **modify\_ldt**() returns either the actual number of bytes read (for reading) or 0 (for writing). On failure, **modify\_ldt**() returns -1 and sets *errno* to indicate the error.

## ERRORS

- **EFAULT**

  *ptr* points outside the address space.

- **EINVAL**

  *ptr* is 0, or *func* is 1 and *bytecount* is not equal to the size of the structure *user\_desc*, or *func* is 1 or 0x11 and the new LDT entry has invalid values.

- **ENOSYS**

  *func* is neither 0, 1, 2, nor 0x11.

## STANDARDS

Linux.

## NOTES

**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 [**set\_thread\_area**(2)](/set_thread_area/2.md) or [**arch\_prctl**(2)](/arch_prctl/2.md) instead, except on extremely old kernels that do not support those system calls.

The normal use for **modify\_ldt**() is to run legacy 16-bit or segmented 32-bit code. Not all kernels allow 16-bit segments to be installed, however.

Even on 64-bit kernels, **modify\_ldt**() cannot be used to create a long mode (i.e., 64-bit) code segment. The undocumented field "lm" in *user\_desc* is not useful, and, despite its name, does not result in a long mode segment.

## BUGS

On 64-bit kernels before Linux 3.19, setting the "lm" bit in *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.

## SEE ALSO

[**arch\_prctl**(2)](/arch_prctl/2.md), [**set\_thread\_area**(2)](/set_thread_area/2.md), [**vm86**(2)](/vm86/2.md)
