glibc的write函数是如何工作的?

4

我尝试使用-nostdlib编译一个调用write的简单程序,但是出现了错误:

/path/to/file:3: undefined reference to `write'

我曾认为write是Unix中一直存在的东西,但显然不是这样,事实证明libc有write函数。我找到了源代码:

/* Write NBYTES of BUF to FD.  Return the number written, or -1.  */
ssize_t
__libc_write (int fd, const void *buf, size_t nbytes)
{
    if (nbytes == 0)
        return 0;
    if (fd < 0)
    {
        __set_errno (EBADF);
        return -1;
    }
    if (buf == NULL)
    {
        __set_errno (EINVAL);
        return -1;
    }

    __set_errno (ENOSYS);
    return -1;
}
libc_hidden_def (__libc_write)
stub_warning (write)

weak_alias (__libc_write, __write)
libc_hidden_weak (__write)
weak_alias (__libc_write, write)

这似乎只是设置了 errno。那么 __libc_write 是如何向文件描述符写入数据的呢?


2
嗯,“stub_warning”让我想到这段源代码只是一个存根函数……你在哪里找到它的? - Serge Ballesta
1个回答

11

您对于Cunix有一些误解。

我以为write是Unix的东西

确实,write系统调用之一,它是POSIX标准的一部分。POSIX是一个兼容unix(一个非常古老的操作系统)的标准。

这意味着在任何Unix或符合POSIX标准(如Linux)的操作系统中都存在名为writesyscall。但是,如果您没有C标准库的实现(如Linux中的glibc或Android中的bionic)- 那么您将如何进行系统调用(即要求操作系统内核执行某些操作)?系统调用与体系结构相关(SPARC、Intel、ARM、PowerPC等会有不同的实现),并由C标准库实现。如果您没有一个(例如当您使用-nostdlib编译时,您明确要求不使用C标准库)- 您无法调用write,因为该函数不存在。但是,您可以使用汇编语言自己实现它。
您提供的代码是__libc_write,而不是write。在这里,glibcgcc之间发生了一些神秘的事情,涉及存根,我并不完全理解。
简单的实现示例如下:
ssize_t write(int fd, const void *buf, size_t count)
{
    return __set_errno(syscall(__NR_write, fd, buf, count));
}

在 Android 的 libc 实现中的 bionic 中(可以在此处https://searchcode.com/codesearch/view/34924443/查看源代码),你可以看到它是用汇编语言实现的。
syscall 函数在 glibc(以及其他任何地方)都是用汇编语言实现的:http://code.metager.de/source/xref/gnu/glibc/sysdeps/unix/sysv/linux/x86_64/syscall.S(适用于 x86_64)。

然而,如果你真的想知道在调用write时中发生了什么,这有点复杂。据我所理解的,它会调用_IO_new_file_write此处有实现)。_IO_new_file_write使用了在此处定义的write_not_cancel宏,该宏是INLINE_SYSCALL(write, 3, fd, buf, len),该宏是调用系统调用并设置errno的实现


据我理解,它调用了_IO_new_file_write。-- 你的理解是错误的,并且混淆了writefwrite。你回答的那部分是完全错误的。 - Employed Russian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接