You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于read(2)函数实现的技术疑问:__libc_前缀及核心代码位置

Understanding the 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 read are part of the public C library API. Users could technically define their own read function 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 read API consistent for developers. The __DARWIN_ALIAS_C(read) line you saw in <unistd.h> is exactly how the public read name 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:

  1. Your code calls the public read() function declared in <unistd.h>.
  2. 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.
  3. The wrapper uses architecture-specific instructions to make this switch:
    • On x86_64, it might use the syscall instruction.
    • On ARM, it could use svc #0.
    • These instructions pass the system call number (for read, that’s SYS_read on most systems) and your arguments (file descriptor, buffer, byte count) to the kernel.
  4. 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 read system call is usually in fs/read_write.c (look for sys_read or sys_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:15:04