2017-06-17 33 views
1

因为我想勾STRCMP,代码是如下:在Linux中使用LD_PRELOAD钩strcmp?

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


int strcmp(const char *s1, const char *s2) 
{ 
    printf("hooked strcmp\n"); 
    return 0; 
} 

// gcc test.c -shared -fPIC -o libtest.so 

#include <stdio.h> 
#include <string.h> 
#include "test.h" 

int main(int argc, char *argv[]) 
{ 
    strcmp(argv[1], "aba");   // didn't call strcmp in libtest 
    int i = strcmp(argv[1], "aba"); // call strcmp in libtest 
} 

// gcc main.c 
// LD_PRELOAD=./libtest.so ./a.out 12123 

我的问题是:为什么在的strcmp这两个条件的diff?

+0

固有使用? – 0andriy

回答

0

如果您不使用strcmp返回的值,则该呼叫不执行任何操作。所以编译器可以自由地删除这个调用。在某些情况下,编译器也可能会内联strcmp,因为它确切知道strcmp的功能。

§ 7.1.3/1:

这是通过标准的,这保留在标准库头声明的所有标识符(报头是否被实际包括)纵容“与任何外部链接所有的标识符以下小节[即标准库头] hellip的;总是保留用作具有外部链接标识符

§ 7.1.3/2:“如果程序声明或在 上下文定义的标识符,其中它。保留(7.1.4所允许的除外)&hellip;行为是不确定的。

根据§ 7.1.4/2规定的例外情况:“只要可以声明库函数而不引用头中定义的任何类型,也可以声明函数并使用它,而不包括其关联头“。


自定义自己的strcmp显然是不确定的行为(除非你使用一个独立的编译器),它或许应该简单地避免。但是,在实践中,使用一些通用的编译器可以以不可移植的方式进行操作。

首先,您必须避免包含string.h标准库标头。与海湾合作委员会发布的标准C库头文件中声明strcmp__attribute__((pure))

许多功能,除了有返回值没有影响,它们的返回值只取决于参数和/或全局变量。这样的函数可以像算术运算符那样经受常见的子表达式消除和循环优化。这些函数应该用属性pure来声明。

这个声明(这是一个扩展的C标准),让编译器消除strcmp第一个呼叫,因为它认为该函数有没有副作用(其中包括写入标准输出)。即使没有优化,gcc和clang都会消除第一个呼叫。

你能说服铛到两个呼叫编译成strcmp,你可以不包括string.h头(和没有pure属性声明strcmp自己)避免简单地消除。但是这对于gcc是不够的,因为默认情况下,gcc会自动包含许多标准库函数的内联版本的声明(当前列表可以在here in the GCC manual中找到)。如上一个链接所述,您可以通过将-fno-builtin-strcmp添加到命令行(以及不包括标准头文件)。

+0

谢谢!它工作,因为我删除#include 并使用-fno-builtin-strcmp进行编译。 – binnnliu