OSX stat()和libffi

时间:2018-01-22 11:50:46

标签: macos dylib libffi

我试图使用libffi访问macos(10.11)上的stat()。这是SWI-Prolog基于FFI的新外部接口的一部分。此接口解析<sys/stat.h>标头以获取函数原型和struct stat类型。但是,我得到了虚假的价值观。如果我编译下面的代码并从生成的mystat链接.dylib

,它可以正常工作
#include <sys/stat.h>

int
mystat(const char *name, struct stat *buf)
{ return stat(name, buf);
}

我怀疑我从stat得到错误的dlsym()函数。在/usr/lib/libc.dylib/usr/lib/libSystem.B.dylib上进行了尝试。这给出了相同的结果。如果我从上面的dylib上运行nm我得到了 U _stat$INODE64dlsym stat$INODE64无效534_> nm /usr/lib/libc.dylib | grep stat 0000000000001ac5 T R8289209$_pthread_attr_setdetachstate 0000000000001af7 T R8289209$_stat U _pthread_attr_setdetachstate U _stat 。看看libc.dylib,我们得到了

{{1}}

两者如何相关?任何人都有任何线索可能会发生什么?

1 个答案:

答案 0 :(得分:0)

您要查找的符号在/usr/lib/system/libsystem_kernel.dylib中定义:

$  ~ nm -g /usr/lib/system/libsystem_kernel.dylib | grep '_stat\$INODE64'
0000000000002ed0 T _stat$INODE64

可以使用dlsym找到它

#include <sys/stat.h>

#include <dlfcn.h>
#include <stdio.h>
#include <string.h>

int
(*real_stat)(const char *path, struct stat *buf);

int main() {
  const char *path = "/usr/lib/system/libsystem_kernel.dylib";
  int err;
  struct stat st;

  void *lib = dlopen(path, RTLD_LOCAL);
  real_stat = dlsym(lib, "stat$INODE64");

  if((err = real_stat(path, &st)))
    fprintf(stderr, "Can't stat %s: %s\n", path, strerror(err));

  printf("%s inode: %lld\n", path, st.st_ino);

  dlclose(lib);
  return 0;
}

real_stat返回的索引节点编号与stat(1)返回的索引节点编号匹配:

$  ~ cc stat.c
$  ~ ./a.out
/usr/lib/system/libsystem_kernel.dylib inode: 4335860614

$  ~ stat -r /usr/lib/system/libsystem_kernel.dylib
16777220 4335860614 0100755 1 0 0 0 545424 1564436981 1564436981 1565194657 1564436981 4096 448 524320 /usr/lib/system/libsystem_kernel.dylib

在某些情况下,stat可能会被这样错误地声明:

struct stat;
int stat(const char *restrict path, struct stat *restrict buf);

int mystat(const char *path, struct stat *buf) {
  return stat(path, buf);
}

该库确实引用了旧版stat

$  ~ cc -dynamiclib wrong-stat.c -o libwrongstat.dylib
$  ~ nm libwrongstat.dylib
0000000000000f70 T _mystat
                 U _stat
                 U dyld_stub_binder

<sys/stat.h>使用带有后缀stat的特殊assembler names for functions声明$INODE64,以避免与现有stat发生冲突(有关详细信息,请参见stat(2))。如果声明stat以后缀引用新的汇编程序名称,则该库可以固定:

struct stat;
int stat(const char *path, struct stat *buf) __asm("_stat$INODE64");

int mystat(const char *path, struct stat *buf) {
  return stat(path, buf);
}
$  ~ cc -dynamiclib correct-stat.c -o libcorrectstat.dylib
$  ~ nm libcorrectstat.dylib
0000000000000f70 T _mystat
                 U _stat$INODE64
                 U dyld_stub_binder

但老实说,我会使用<sys/stat.h>来提取正确的符号声明。