我正在编写一个提供sha256实现的库。该库将提供给可能希望提供针对其平台优化的sha256功能的供应商。因此,该库的API允许客户端将函数指针传递给它们的sha256代码。
int mylib_set_sha256_impl( /* function pointers */ );
此后,所有算法都将使用内部提供的函数指针,而不是库提供的库存sha256代码。
问题是:如何在链接时删除死代码,以便删除此库中的默认sha256实现?
这是一个API设计问题,就像编译器优化问题一样。
答案 0 :(得分:3)
就链接器而言,没有特殊要求,也不需要考虑弱混叠。
基本规则是:只要用户代码没有引用您链接到库中的给定.c
或.s
文件中的任何符号,该文件的内容就不会结束在可执行文件中。
在您描述的场景中,您的函数可能永远不会成为死代码,因为您的“实时”代码可能会引用它们的地址来设置默认函数指针值。为确保不会发生这种情况,您必须执行以下操作:
仅在用户可调用的可选 default_init
功能中引用可替换功能。
绝不能在代码中的任何位置调用default_init
,也不得在default_init
内的任何地方引用任何函数。
让可更换的函数和init函数放入至少一个不用于任何其他代码的.c
或汇编文件中。
为了让您的用户替换所有这些功能,他们只需要永远不要调用default_init
功能。如果您希望功能可以逐个更换,则必须另外:
将每个可替换功能放在自己的.c
文件中。
让用户不要直接拨打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();
}