我有以下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)
。此外,可执行文件中的代码确认调用stat
函数而不是调用__xstat
函数。
我没有观察到对C标准库的其他函数调用,这些函数调用的名称与C程序中声明的名称不同。为什么标准库中没有直接的等价物,我的编译器如何发现它应该调用__xstat
而不调用stat
?
答案 0 :(得分:4)
标题sys/stat.h
将stat
定义为在glibc中调用__xstat
的宏:
#define stat(fname, buf) __xstat (_STAT_VER, fname, buf)
答案 1 :(得分:1)
我在/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
根据注释和宏定义,似乎在内联汇编程序中指定了别名。