errno IS NOT A REGULAR VARIABLE
- Stored in Thread Local Storage (TLS)
- A pointer to errno is returned via libc’s __errno_location() function
- On i686 the TLS block is referenced by %gs segment register; on x86-64 via %fs.
- All syscalls return between -4095 and -1 on failure.
- Even the syscall() function sets errno
More about why [-1, -4095] range.
This specific range (-4095 to -1) is a clever hack to solve the "Pointer Ambiguity" problem.
The kernel developers needed a way for a function to return either a valid memory address (a pointer) or an error code, using only a single return register (like rax).
1) The Conflict
Imagine a system call like mmap(), which asks the kernel for memory.
Success: It returns a pointer (e.g., memory address 0x7f43a...).
Failure: It needs to return an error code (e.g., -12 for "Out of Memory").
If the kernel just returned -12, the computer sees 0xFFFFFFFFFFFFFFF4 (in 64-bit unsigned hex).
The Risk: What if there is actually a valid piece of memory at address 0xFFFFFFFFFFFFFFF4? The program wouldn't know if it got a valid pointer or an error.
2) The Solution: The "Forbidden" Page
To fix this, the kernel reserves the very last page of virtual memory (the top 4KB) as a "No-Go Zone."
The Range: -4095 corresponds to the start of that last 4KB page.
-1 = 0xFFFFFFFFFFFFFFFF (The very top)
-4095 = 0xFFFFFFFFFFFFF001 (4KB down)
The Logic: No valid pointer is allowed to point to this very last page of memory. It is reserved specifically to hold error codes.
Why 4095? Because the standard memory page size is 4096 bytes (4KB). By reserving exactly one page, they minimized wasted address space while ensuring there's enough room for all standard error codes (there are usually only ~130 distinct errno values).
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.