【问题标题】:How do I reimplement (or wrap) a syscall function on Linux?如何在 Linux 上重新实现(或包装)系统调用函数?
【发布时间】:2011-04-09 10:29:33
【问题描述】:

假设我想完全接管 open() 系统调用,也许是为了包装实际的系统调用并执行一些日志记录。 One way to do this is to use LD_PRELOAD 加载接管 open() 入口点的(用户制作的)共享对象库。

然后用户创建的 open() 例程通过 dlsym() 获取指向 glibc 函数 open() 的指针并调用它。

然而,上面提出的解决方案是一个动态解决方案。假设我想静态链接我自己的 open() 包装器。我该怎么做?我猜机制是一样的,但我也猜想用户定义的open()和libc的open()之间会有符号冲突。

请分享任何其他实现相同目标的技术。

【问题讨论】:

  • 在代码中添加一个包装函数/宏怎么样?
  • @Seamus :我不喜欢使用宏。我真的没有问题。我只是要求增加 SO 知识并学习一些新技巧。

标签: c linux system-calls libc


【解决方案1】:

您可以使用ld 提供的换行功能。来自man ld

--wrap symbol 对符号使用包装函数。任何未定义的引用 symbol 将被解析为 __wrap_symbol

__real_symbol 的任何未定义引用都将解析为symbol

所以你只需要为你的包装函数使用前缀__wrap_,当你想调用真正的函数时使用__real_。一个简单的例子是:

malloc_wrapper.c:

#include <stdio.h>
void *__real_malloc (size_t);

/* This function wraps the real malloc */
void * __wrap_malloc (size_t size)
{
    void *lptr = __real_malloc(size);
    printf("Malloc: %lu bytes @%p\n", size, lptr);
    return lptr;
}

测试应用testapp.c:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    free(malloc(1024)); // malloc will resolve to __wrap_malloc
    return 0;
}

然后编译应用程序:

gcc -c malloc_wrapper.c
gcc -c testapp.c
gcc -Wl,-wrap,malloc testapp.o malloc_wrapper.o -o testapp

生成的应用程序的输出将是:

$ ./testapp
Malloc: 1024 bytes @0x20d8010

【讨论】:

  • 看来调用malloc的函数不能动态链接。例如,我编写了一个 tools.c,其中包含一个调用 malloc 的函数 perform_alloc()。然后如果我先创建一个 libtools.so 并通过-ltools 动态链接它,-Wl,-wrap,malloc 将不起作用。
  • 正如stackoverflow.com/questions/3826108/… 中的回答,在 C++ 程序中使用此代码时,需要在函数定义前加上 extern "C"
  • 函数必须调用__wrap_malloc吗?或者它可以用不同的名字命名吗?我的意思是在包装系统调用时,我们是否必须将函数命名为与实际调用相同?
  • @return0: 如man ld 所示,符号必须有前缀__wrap___real_
【解决方案2】:

链接器会按照您在命令行中列出它们的顺序来解析符号,因此如果您在标准库之前列出您的库,那么您就会有先见之明。对于 gcc,您需要指定

gcc <BLAH> -nodefaultlibs <BLAH BLAH> -lYOUR_LIB <OTHER_LIBS>

这样您的库将首先被搜索和找到。

【讨论】:

    猜你喜欢
    • 2016-05-25
    • 2015-05-05
    • 1970-01-01
    • 2015-05-24
    • 2012-09-19
    • 1970-01-01
    • 2010-10-04
    • 1970-01-01
    • 2016-12-01
    相关资源
    最近更新 更多