我的编译器如何找到 stat(文件状态)函数?
How does my compiler find the stat (file status) function?
我有以下 C 程序:
#include <sys/stat.h>
int main(int argc, char **argv) {
struct stat fileStat;
if(stat(argv[1],&fileStat) < 0)
return 1;
}
当我使用 Clang 将其编译为 LLVM IR 时,我可以看到 stat
声明如下:
declare i32 @stat(i8*, %struct.stat*)
通常,这种对系统函数的外部调用直接映射到C标准库函数。例如,我可以通过以下方式找到 malloc
:
nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep malloc
然而,stat
函数似乎被区别对待。当搜索 stat
时,我可以找到相关函数,例如 __xstat
但找不到 stat
函数本身。
当我使用 ltrace
跟踪对外部库的调用时,我看到以下调用:__xstat(1, ".", 0x7fff7928c6f0)
。此外,可执行文件中的代码确认调用了 __xstat
函数,而不是调用 stat
函数。
我没有观察到对 C 标准库的其他函数调用具有与 C 程序中声明的名称不同的名称。为什么标准库中没有直接等价物?我的编译器如何发现它应该产生对 __xstat
而不是 stat
的调用?
Header sys/stat.h
将 stat
定义为在 glibc 中调用 __xstat
的宏:
#define stat(fname, buf) __xstat (_STAT_VER, fname, buf)
我在 /usr/include/x86_64-linux-gnu/sys/stat.h
中发现了以下评论:
/* To allow the `struct stat' structure and the file type `mode_t'
bits to vary without changing shared library major version number,
the `stat' family of functions and `mknod' are in fact inline
wrappers around calls to `xstat', `fxstat', `lxstat', and `xmknod',
which all take a leading version-number argument designating the
data structure and bits used. <bits/stat.h> defines _STAT_VER with
the version number corresponding to `struct stat' as defined in
that file; and _MKNOD_VER with the version number corresponding to
the S_IF* macros defined therein. It is arranged that when not
inlined these function are always statically linked; that way a
dynamically-linked executable always encodes the version number
corresponding to the data structures it uses, so the `x' functions
in the shared library can adapt without needing to recompile all
callers. */
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
# endif
__REDIRECT_NTH
定义在 /usr/include/x86_64-linux-gnu/sys/cdefs.h
:
/* __asm__ ("xyz") is used throughout the headers to rename functions
at the assembly language level. This is wrapped by the __REDIRECT
macro, in order to support compilers that can do this some other
way. When compilers don't support asm-names at all, we have to do
preprocessor tricks instead (which don't have exactly the right
semantics, but it's the best we can do).
Example:
int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */
#if defined __GNUC__ && __GNUC__ >= 2
# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias))
# ifdef __cplusplus
# define __REDIRECT_NTH(name, proto, alias) \
name proto __THROW __asm__ (__ASMNAME (#alias))
# define __REDIRECT_NTHNL(name, proto, alias) \
name proto __THROWNL __asm__ (__ASMNAME (#alias))
# else
# define __REDIRECT_NTH(name, proto, alias) \
name proto __asm__ (__ASMNAME (#alias)) __THROW
# define __REDIRECT_NTHNL(name, proto, alias) \
name proto __asm__ (__ASMNAME (#alias)) __THROWNL
# endif
# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname)
# define __ASMNAME2(prefix, cname) __STRING (prefix) cname
从注释和宏定义看来,别名似乎是在内联汇编程序中指定的。
我有以下 C 程序:
#include <sys/stat.h>
int main(int argc, char **argv) {
struct stat fileStat;
if(stat(argv[1],&fileStat) < 0)
return 1;
}
当我使用 Clang 将其编译为 LLVM IR 时,我可以看到 stat
声明如下:
declare i32 @stat(i8*, %struct.stat*)
通常,这种对系统函数的外部调用直接映射到C标准库函数。例如,我可以通过以下方式找到 malloc
:
nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep malloc
然而,stat
函数似乎被区别对待。当搜索 stat
时,我可以找到相关函数,例如 __xstat
但找不到 stat
函数本身。
当我使用 ltrace
跟踪对外部库的调用时,我看到以下调用:__xstat(1, ".", 0x7fff7928c6f0)
。此外,可执行文件中的代码确认调用了 __xstat
函数,而不是调用 stat
函数。
我没有观察到对 C 标准库的其他函数调用具有与 C 程序中声明的名称不同的名称。为什么标准库中没有直接等价物?我的编译器如何发现它应该产生对 __xstat
而不是 stat
的调用?
Header sys/stat.h
将 stat
定义为在 glibc 中调用 __xstat
的宏:
#define stat(fname, buf) __xstat (_STAT_VER, fname, buf)
我在 /usr/include/x86_64-linux-gnu/sys/stat.h
中发现了以下评论:
/* To allow the `struct stat' structure and the file type `mode_t'
bits to vary without changing shared library major version number,
the `stat' family of functions and `mknod' are in fact inline
wrappers around calls to `xstat', `fxstat', `lxstat', and `xmknod',
which all take a leading version-number argument designating the
data structure and bits used. <bits/stat.h> defines _STAT_VER with
the version number corresponding to `struct stat' as defined in
that file; and _MKNOD_VER with the version number corresponding to
the S_IF* macros defined therein. It is arranged that when not
inlined these function are always statically linked; that way a
dynamically-linked executable always encodes the version number
corresponding to the data structures it uses, so the `x' functions
in the shared library can adapt without needing to recompile all
callers. */
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (stat, (const char *__restrict __file,
struct stat *__restrict __buf), stat64)
__nonnull ((1, 2));
# endif
__REDIRECT_NTH
定义在 /usr/include/x86_64-linux-gnu/sys/cdefs.h
:
/* __asm__ ("xyz") is used throughout the headers to rename functions
at the assembly language level. This is wrapped by the __REDIRECT
macro, in order to support compilers that can do this some other
way. When compilers don't support asm-names at all, we have to do
preprocessor tricks instead (which don't have exactly the right
semantics, but it's the best we can do).
Example:
int __REDIRECT(setpgrp, (__pid_t pid, __pid_t pgrp), setpgid); */
#if defined __GNUC__ && __GNUC__ >= 2
# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias))
# ifdef __cplusplus
# define __REDIRECT_NTH(name, proto, alias) \
name proto __THROW __asm__ (__ASMNAME (#alias))
# define __REDIRECT_NTHNL(name, proto, alias) \
name proto __THROWNL __asm__ (__ASMNAME (#alias))
# else
# define __REDIRECT_NTH(name, proto, alias) \
name proto __asm__ (__ASMNAME (#alias)) __THROW
# define __REDIRECT_NTHNL(name, proto, alias) \
name proto __asm__ (__ASMNAME (#alias)) __THROWNL
# endif
# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname)
# define __ASMNAME2(prefix, cname) __STRING (prefix) cname
从注释和宏定义看来,别名似乎是在内联汇编程序中指定的。