关于read(2)函数实现的技术疑问:__libc_前缀及核心代码位置
read(2) System Call Implementation Let me break down your questions one by one—digging into glibc and kernel sources can feel a bit confusing at first, so let's unpack this step by step:
1. What's the __libc_ prefix, and why is it needed?
The __libc_ prefix marks this as an internal glibc symbol, and it serves two key purposes:
- Namespace isolation: Standard functions like
readare part of the public C library API. Users could technically define their ownreadfunction in code (not that we recommend it), so using the__libc_prefix for the internal implementation avoids naming collisions with user-defined code. - Flexibility and versioning: Glibc uses this prefix to manage platform-specific implementations or multiple versions of functions under the hood, while keeping the public
readAPI consistent for developers. The__DARWIN_ALIAS_C(read)line you saw in<unistd.h>is exactly how the publicreadname links to__libc_read—it’s an alias that maps the user-facing function to the internal implementation.
2. How is read(2) triggered when a user calls it?
When you call read() in your code, you’re not directly hitting that stub __libc_read you found right away. Here’s the typical flow:
- Your code calls the public
read()function declared in<unistd.h>. - This public symbol is aliased to glibc’s internal wrapper (like
__libc_read), but the real work starts when this wrapper triggers a system call to switch from user space to kernel space. - The wrapper uses architecture-specific instructions to make this switch:
- On x86_64, it might use the
syscallinstruction. - On ARM, it could use
svc #0. - These instructions pass the system call number (for
read, that’sSYS_readon most systems) and your arguments (file descriptor, buffer, byte count) to the kernel.
- On x86_64, it might use the
- The kernel handles the actual I/O operation, then sends the result back to the glibc wrapper, which passes it to your code.
The stub in read.c is a fallback implementation—it only runs if the system call isn’t available (a rare scenario on modern systems). Most platforms have optimized assembly or C wrappers that directly invoke the system call.
3. Where is the core implementation of read(2)? Did I look in the wrong place?
You’re absolutely right that the __libc_read in that read.c file only handles basic error checking and returns ENOSYS ("function not implemented"). That’s because the core logic of read(2) lives in the kernel, not in glibc.
Glibc’s role is just to provide a user-space bridge to the kernel’s system call. The actual work of reading data from a file descriptor—whether it’s a regular file, pipe, socket, or device—is handled by the kernel’s filesystem and device drivers.
To find the core implementation, you’ll need to look at the Linux kernel source code:
- The entry point for the
readsystem call is usually infs/read_write.c(look forsys_readorsys_readv). - From there, the kernel routes the request to the appropriate filesystem driver (e.g., ext4, tmpfs) or device driver (e.g., disk, network socket) based on what the file descriptor points to.
That read.c file in glibc is just a safety net for edge cases—it’s not the real implementation you’re looking for.
内容的提问来源于stack exchange,提问作者H.Potter

