2016-01-14 32 views
2

我正在編寫提供sha256實現的庫。該庫將提供給可能想要提供他們自己的sha256功能的供應商,這些功能已針對他們的平臺進行了優化。所以,這個庫的API允許客戶端將函數指針傳遞給他們的sha256代碼。如果實現被覆蓋,則刪除死代碼

int mylib_set_sha256_impl(/* function pointers */); 

從此以後,所有的算法將使用提供由圖書館提供的股票代碼SHA256在內部而不是函數指針。

問題是:我該如何在鏈接期間促進死代碼刪除,以便刪除此庫中默認的sha256實現?

這是一個API設計問題,它與編譯器優化問題一樣多。

+2

也許看看[弱混疊(HTTP:/ /stackoverflow.com/questions/15525537/what-are-practical-applications-of-weak-linking)。 – Downvoter

+0

弱主要是由主要編譯器供應商(即MSVC,gcc,鐺,Intel C ...)支持的東西 – MarkP

+0

絕對GCC,其他可能也是如此。 – Downvoter

回答

3

就鏈接器而言,沒有特別的要求,並且不需要考慮弱的混疊。

基本規則是:只要用戶代碼沒有引用鏈接到庫中的給定.c.s文件中的任何符號,該文件的內容就不會在可執行文件中結束。

在您描述的場景中,您的函數可能永遠不會成爲死代碼,因爲您的「實時」代碼可能引用其地址來設置默認函數指針值。爲了確保不會發生,你必須做到以下幾點:

  1. 只有從用戶可調用可選default_init功能中,請參閱更換功能。

  2. default_init決不能在你的代碼的任何地方調用,沒有任何必須的功能,在任何地方,但內default_init引用。

  3. 將可替換的函數和init函數放入至少一個.c或彙編文件中,該文件不用於任何其他代碼。

爲用戶更換所有的功能,他們只需要從不調用default_init功能。如果你想功能可更換一個接一個,你必須去,另外:

  1. 在其自己的.c文件中的每個替換功能。

  2. 讓用戶不要直接調用default_init,而是將所需的默認或用戶提供的實現傳遞給您的init函數。

你在做什麼,實際上,不是「覆蓋」的任何實現,但根本就沒有使用它。

例(包括省略清晰後衛):

// api.h 
void api_fun1(void); 
void api_fun2(void); 
void api_default_init(void); 
void api_user_init(void (*f1)(void), void (*f2)(void)); 
void api_use_funs(void); 

// api_internal.h 
extern void (*api_f1)(void); 
extern void (*api_f2)(void);  

// common.c 
#include "api.h" 
#include "api_internal.h" 
void (*api_f1)(void); 
void (*api_f2)(void); 

void api_user_init(void (*f1)(void), void (*f2)(void)) { 
    api_f1 = f1; 
    api_f2 = f2; 
} 

void api_use_funs(void) { 
    api_f1(); 
    api_f2(); 
} 

// api_fun1.c 
#include "api.h" 
void api_fun1(void) {} 

// api_fun2.c 
#include "api.h" 
void api_fun2(void) {} 

// api_default_init.c 
#include "api.h" 
#include "api_internal.h" 

void api_default_init(void) { 
    api_f1 = api_fun1; 
    api_f2 = api_fun2; 
} 

比方說,用戶要覆蓋api_fun2自己:

// main.c 
#include "api.h" 
#include <stdio.h> 

void my_fun2() { 
    printf("%s\n", __FUNCTION__); 
} 

int main() { 
    api_user_init(api_fun1, my_fun2); 
    api_use_funs(); 
} 
+0

我基本上得出這個結論。有一個'set_sha256_defaults()'很好,但我的庫有很多這樣的覆蓋(即其他哈希實現,RNG,HMAC,CRC等),這會拋棄API'* _defaults()'功能。我希望能有一個更優雅的解決方案,但它開始看起來好像一個人可能不比你發佈的那個更好。 – MarkP

+0

唯一的「優雅」將是默認功能不會有'_default'後綴。否則,使用弱符號只會帶來一個好處:根本不需要使用函數指針。用戶提供的具有相同名稱的函數將簡單地覆蓋您的名稱。對於這是否是件好事,我很矛盾。 –