2016-05-17 9 views
2

У меня следующая программа C:Как мой компилятор находит функцию stat (статус файла)?

#include <sys/stat.h> 

int main(int argc, char **argv) { 
    struct stat fileStat; 
    if(stat(argv[1],&fileStat) < 0)  
     return 1; 
} 

Когда я скомпилировать его с LLVM ИК использования Clang, можно увидеть, что stat объявляются следующим образом:

declare i32 @stat(i8*, %struct.stat*) 

Обычно такого внешний вызов системная функция непосредственно сопоставляется с стандартной библиотечной функцией C. Например, я могу найти malloc следующим:

nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep malloc 

Однако функция stat кажется, трактуется по-разному. Когда grepping для stat, я могу найти связанные функции, такие как __xstat, но не функцию stat.

Когда я отслеживаю звонок во внешнюю библиотеку с помощью ltrace Я вижу следующий звонок: __xstat(1, ".", 0x7fff7928c6f0). Также код в исполняемом файле подтверждает, что вместо вызова функции stat вызывается функция __xstat.

Я не наблюдал других вызовов функций в стандартной библиотеке C, которые имеют другие имена, чем те, которые были объявлены в программе C. Почему в стандартной библиотеке нет прямого эквивалента, и как мой компилятор узнает, что он должен вызвать вызов __xstat, а не stat?

+1

Это может помочь вам много http://stackoverflow.com/questions/8237294/intercepting-stat –

ответ

4

Заголовок sys/stat.h определяет stat как макрос, который вызывает __xstat в Glibc:

#define stat(fname, buf) __xstat (_STAT_VER, fname, buf) 
+1

Но если 'stat' - это макрос, то макрос уже должен быть разрешен Clang и вызовом в бит-коде LLVM файл должен перейти в '__xstat' или нет? – box

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 

Из комментариев и макроопределений кажется, что псевдоним указан в встроенном ассемблере.