问题描述
我试图用-nostdlib
编译一个名为write
的简单程序,但出现错误:
I tried to compile a simple program that called write
with -nostdlib
, but I got the error:
/path/to/file:3: undefined reference to `write'
我认为write
是Unix上的东西,并且一直存在,但显然不是,事实证明libc具有write
功能.我找到了源代码:
I thought write
was a Unix thing and was always there, but apparently not, turns out libc has write
function. I found the source code:
/* 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
如何写入文件描述符?
All this seems to be doing is setting errno
. How does __libc_write
write to a file descriptor?
推荐答案
您对C
和unix
有一些误解.
write
当然是系统调用,它是 POSIX 标准. POSIX
是与unix
(一个非常老的操作系统)兼容的标准.
Definitely, write
is a syscall which is a part of the POSIX standard. POSIX
is a standard that is compatible with unix
(a very old operating system).
这意味着名为write
的 syscall 存在于任何与Unix或POSIX兼容的操作系统(如Linux)中.但是,如果您没有C标准库的实现(例如Linux中的glibc或Android中的bionic)-您将如何进行系统调用(即要求OS的内核执行某项操作)? Syscall依赖于体系结构(SPARC,Intel,ARM,PowerPC等将具有不同的实现)-并由C标准库实现.如果您没有该库(例如,当您遵循-nostdlib
时,您明确要求不使用C标准库)-您无法调用write
,则该函数不存在.但是,您可以自己使用汇编来实现它.
This means that the syscall called write
exists in any unix or POSIX-compliant (like Linux) operating system. However, if you don't have a an implementation of the C standard library (like glibc in Linux or bionic in Android) - how are you going to make a syscall (i.e. ask the kernel of the OS to do something)? Syscalls are architecture dependent (SPARC, Intel, ARM, PowerPC etc will have different implementations) - and are implemented by the C standard library. If you don't have one (e.g when you complie with -nostdlib
you specifically ask not to have a C standard library) - you can't call write
, the function doesn't exist. You can, however, implement it yourself using assembly.
您提供的代码是针对__libc_write
的,与write
不同.在glibc
和gcc
之间发生了一些伏都教,这与存根有关,我不完全理解.
The code you provided is for __libc_write
, which is not the same as write
. There's some voodoo that's going on between glibc
and gcc
here, something that has to do with stubs and I don't completely understand it.
简单的实现是这样的:
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/-看到它是在汇编中实现的
(In bionic
, Android's libc implementation, you can see the sources here https://searchcode.com/codesearch/view/34924443/ - see that it is implemented in assembly)
syscall
函数在glibc
中(以及其他任何位置)以汇编形式实现: http://code.metager.de/source/xref/gnu/glibc/sysdeps/unix/sysv/linux/x86_64/syscall.S (对于x86_64)
The syscall
function is implemented in assembly in glibc
(and anywhere else): http://code.metager.de/source/xref/gnu/glibc/sysdeps/unix/sysv/linux/x86_64/syscall.S (for x86_64)
但是,如果在调用write
时必须真正了解glibc
中发生的事情,则有点复杂.据我了解,它调用_IO_new_file_write
(已实现这里). _IO_new_file_write
使用定义的write_not_cancel
宏此处, INLINE_SYSCALL (write, 3, fd, buf, len)
的宏,它是实现,用于调用syscall并设置errno.
However, if you must really know what's happening in glibc
when you call write
- it's a bit complicated. As far as I understood it, it calls _IO_new_file_write
(implemented here). _IO_new_file_write
uses the write_not_cancel
macro defined here which is a macro for INLINE_SYSCALL (write, 3, fd, buf, len)
, which is the implementation for calling a syscall and setting errno.
这篇关于glibc的写工作如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!