【问题标题】:How to replace C standard library function ?如何替换 C 标准库函数?
【发布时间】:2012-02-24 19:23:49
【问题描述】:

我们如何用我们自己实现的函数替换 C 标准库函数?

例如,如何将strcpy() 替换为我自己的strcpy() 实现,并让所有调用都链接到新的实现?

【问题讨论】:

  • 为什么要这样做? 可能有什么意义?
  • 真的值得这么麻烦吗?您必须编辑 string.h 头文件,其位置取决于您使用的系统和环境。但我认为你最好编写一个单独的函数。
  • @CodyGray,我想,看看 FatalError 的answer,您可以将可执行文件中的每个调用替换为您自己的打印调试信息?或者类似的东西,我猜。可能不是很好的做法。您应该编写一个具有不同名称的新函数并更改所有调用。
  • 正如@CodyGray 所说,您不应该尝试覆盖已被证明是准确且优化至完美的标准库函数。
  • @IntermediateHacker 有问题的标准库函数怎么样? Somebugreports关于rintf()

标签: c


【解决方案1】:

我不确定让链接器执行您想要的操作有多难,但这里有一个解决方案,它不涉及更改任何链接器设置,而是使用预处理器宏,以便任何尝试调用 strcpy 的代码实际上调用了一个名为 my_strcpy 的函数:

mystuff.h:

#define strcpy my_strcpy
char * my_strcpy(char * dst, const char * src);

my_strcpy.c:

#include <mystuff.h>
char * my_strcpy(char * dst, const char * src);
{
    ...
}

my_code.c:

#include <mystuff.h>

int main()
{
   /* Any call to strcpy will look like a normal call to strcpy
      but will actually call my_strcpy. */
}

【讨论】:

    【解决方案2】:

    至少对于 GCC 和 glibc,标准 C 函数的符号是​​ weak,因此您可以覆盖它们。例如,

    strcpy.c:

    #include <string.h>
    #include <stdio.h>
    
    char * strcpy(char *dst, const char *src)
    {
      char *d = dst;
      while (*src) {
        *d = *src;
        d++;
        src++;
      }
      printf("Called my strcpy()\n");
    
      return (dst);
    }
    
    int main(void)
    {
      char foo[10];
      strcpy(foo, "hello");
    
      puts(foo);
    
      return 0;
    }
    

    然后像这样构建它:

    gcc -fno-builtin -o strcpy strcpy.c
    

    然后:

    $ ./strcpy 
    Called my strcpy()
    hello
    

    请注意此处-fno-builtin 的重要性。如果你不使用这个,GCC 会将strcpy() 调用替换为一个内置函数,其中 GCC 有一个数字。

    我不确定这是否适用于其他编译器/平台。

    【讨论】:

    • 有趣的是,我上面的strcpy() 有一个非常严重的缺陷。由于这不是这里真正的重点,我将把它留给读者作为练习;)。
    • 这就是重点。用您自己的一个替换久经考验的库函数几乎可以 100% 保证存在严重缺陷。
    • 至于缺陷:在这个版本的strcpy()中,如果srcdst重叠,则循环条件永远不会为假。
    • 我不认为strcpy() 曾经保证不会出现重叠字符串。然而,它保证nul-terminate dst ;).
    【解决方案3】:

    如果您在 Linux 上,可以尝试使用 LD_PRELOAD

    【讨论】:

    • 这似乎是正确的方法。 Here 是一个例子,但真正的问题是为什么?
    • 这称为插入库。您必须创建一个编译为 PIC(位置无关代码)的 C 模块到 .so 文件中。然后你设置 LD_PRELOAD=/path/to/mystrcpy.so 你也可以通过在你的代码中调用 dl_open() 来完成同样的事情。简单地创建 mystrcpy.c 将其编译成一个对象模块并在代码中的其他任何地方调用它,然后链接到 mystrcpy 对象模块就更容易了。您还必须在任何地方为 mystrcpy 使用 extern 声明。见:stackoverflow.com/questions/426230/what-is-the-ld-preload-trick
    猜你喜欢
    • 2018-08-12
    • 2017-01-20
    • 1970-01-01
    • 2021-05-05
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多