glibc的写作是如何工作的?

MD *_* XF 2 c unix glibc

我试图编译一个简单的程序,所谓的write-nostdlib,但我得到了错误:

/path/to/file:3: undefined reference to `write'
Run Code Online (Sandbox Code Playgroud)

我认为这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)
Run Code Online (Sandbox Code Playgroud)

所有这些似乎都在做errno.如何__libc_write写入文件描述符?

Mar*_*gal 7

你对C和有一些误解unix.

我以为write是Unix的东西

当然,write是一个系统调用其是的一部分POSIX标准.POSIX是一个与unix(一个非常古老的操作系统)兼容的标准.

这意味着调用的系统调用write存在于任何符合Unix或POSIX的操作系统(如Linux)中.但是,如果您没有C标准库的实现(如Linux中的glibc或Android中的bionic) - 您将如何进行系统调用(即要求操作系统内核执行某些操作)?Syscalls依赖于体系结构(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));
}
Run Code Online (Sandbox Code Playgroud)

(在bionicAndroid的libc实现中,你可以在这里看到源代码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)

但是,如果你必须真正知道glibc你打电话时发生了什么write- 这有点复杂.据我了解,它调用_IO_new_file_write(在这里实现)._IO_new_file_write使用write_not_cancel定义的宏这里一个宏 INLINE_SYSCALL (write, 3, fd, buf, len),这是执行调用系统调用和设置错误号.

  • 好的,你能正确解释一下吗? (3认同)