2017-06-17 85 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