我的编译器如何找到stat(文件状态)函数?

时间:2016-05-17 12:24:25

标签: c linker llvm glibc llvm-ir

我有以下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

2 个答案:

答案 0 :(得分:4)

标题sys/stat.hstat定义为在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

根据注释和宏定义,似乎在内联汇编程序中指定了别名。