如果实施被覆盖,则删除死代码

时间:2016-01-14 15:37:31

标签: c c99 dead-code

我正在编写一个提供sha256实现的库。该库将提供给可能希望提供针对其平台优化的sha256功能的供应商。因此,该库的API允许客户端将函数指针传递给它们的sha256代码。

int mylib_set_sha256_impl( /* function pointers */ );

此后,所有算法都将使用内部提供的函数指针,而不是库提供的库存sha256代码。

问题是:如何在链接时删除死代码,以便删除此库中的默认sha256实现?

这是一个API设计问题,就像编译器优化问题一样。

1 个答案:

答案 0 :(得分:3)

就链接器而言,没有特殊要求,也不需要考虑弱混叠。

基本规则是:只要用户代码没有引用您链接到库中的给定.c.s文件中的任何符号,该文件的内容就不会结束在可执行文件中。

在您描述的场景中,您的函数可能永远不会成为死代码,因为您的“实时”代码可能会引用它们的地址来设置默认函数指针值。为确保不会发生这种情况,您必须执行以下操作:

  1. 仅在用户可调用的可选 default_init功能中引用可替换功能。

  2. 绝不能在代码中的任何位置调用default_init,也不得在default_init内的任何地方引用任何函数。

  3. 让可更换的函数和init函数放入至少一个不用于任何其他代码的.c或汇编文件中。

  4. 为了让您的用户替换所有这些功能,他们只需要永远不要调用default_init功能。如果您希望功能可以逐个更换,则必须另外:

    1. 将每个可替换功能放在自己的.c文件中。

    2. 让用户不要直接拨打default_init,而是将所需的默认或用户提供的实施传递给init功能。

    3. 你所做的实际上并不是“覆盖”任何实现,而是根本不使用它。

      示例(为清晰起见,省略了保护措施):

      // 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();
      }