如何替换C标准库函数?

12

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

例如,我如何用我自己的strcpy()替换标准库中的strcpy(),并让所有调用链接到新实现而不是标准库中的实现?


你为什么要这样做?可能有什么意义吗? - Cody Gray
这真的值得吗?您将不得不编辑string.h头文件,其位置取决于您使用的系统和环境。但我认为编写一个单独的函数会更好。 - Shredderroy
@CodyGray,我猜,看着FatalError的答案,你可以替换可执行文件中的每个调用为自己的调用,以打印调试信息?或者类似于这样的操作,我猜。但这可能不是一个好的做法。你应该编写一个新的函数并更改所有调用的名称。 - Anthony
1
正如 @CodyGray 所说,您不应该尝试覆盖已被证明准确且经过完美优化的标准库函数。 - ApprenticeHacker
@IntermediateHacker,关于标准库函数存在缺陷怎么办?有一些关于rintf()报告漏洞问题 - Daniel Fischer
3个回答

19

至少在使用GCC和glibc的情况下,标准C函数的符号是弱符号,因此您可以覆盖它们。例如,

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 有很多内建函数。

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


1
有趣的是,我上面的strcpy()函数有一个非常严重的缺陷。既然这不是真正的重点,我将其留给读者作为练习;)。 - FatalError
3
虽然这样做有点冒险,但这正是重点所在。用自己的函数替换经过试验和验证的标准库函数几乎百分之百会有严重的缺陷。 - Cody Gray
关于这个缺陷:在这个版本的strcpy()中,如果srcdst重叠,则循环条件永远不会为假。 - Philip
6
我认为strcpy()从来没有保证覆盖字符串的情况下可以正常工作,但是它确保在目标字符串末尾添加空字符。 ;) - FatalError

7

如果你使用的是Linux系统,可以尝试使用LD_PRELOAD进行实验。


这看起来是正确的方法。这里有个例子,但真正的问题是为什么? - Noufal Ibrahim
这被称为库插入。您必须创建一个C模块,编译为PIC(位置无关代码)到.so文件中。然后设置LD_PRELOAD=/path/to/mystrcpy.so。您还可以通过在代码中调用dl_open()来完成相同的事情。更简单的方法是创建mystrcpy.c并将其编译为对象模块,并在代码的其他地方调用它,并链接到mystrcpy对象模块。您还必须在每个地方使用extern声明mystrcpy。请参见:https://dev59.com/QXRC5IYBdhLWcg3wD8tV - jim mcnamara

6

我不确定让连接器按照你的要求操作会有多难,但是这里有一个解决方案,它不需要改变任何连接器设置,而是使用预处理器宏,以便任何尝试调用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. */
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接