【问题标题】:C questions about static and shared libraries关于静态库和共享库的 C 题
【发布时间】:2016-06-24 15:46:07
【问题描述】:

我有一些 .c.h 文件,主要功能封装在 MAIN_FUNC.c 中。我需要将它们传递给一个将 MAIN_FUNC() 与他的文件集成的人。

但是,由于我的算法是机密的,我不能只发送 .c.h 文件,因此我一直在研究静态和共享库。不过我还是有些疑惑。

1:在我看过的每个教程中,.h 也是必需的。有什么方法可以让他只发送一个库文件,他可以在他的代码中#include

2:即使我必须传递 .hs 文件,我真的需要传递所有这些文件吗?我怎样才能只给他 libMAIN_FUNC.a 和 MAIN_FUNC.h?

3: 对于 .a.so 库,是否有任何方法可以对文件进行逆向工程,以便可以看到.c.h 代码?

【问题讨论】:

  • 您分发的 .h 文件必须与您用于编译库的文件相同,只要您确保函数原型完全匹配即可。也就是说,最好分发您实际使用的那些,这样就不会有不匹配的可能性。您可以重组您的 .h 文件,使其中一个仅包含导出的函数,不包含其他任何内容。\
  • 啊,好吧,这很有帮助。我的 .h 文件中有一些宏,这就是我不想放弃它们的原因。

标签: c shared-libraries static-libraries


【解决方案1】:
  1. 不,您必须向他提供至少一个 .h 文件。
  2. 不,您只需要传递那些足以定义您的库和用户之间的接口的内容。我建议你阅读pimpl范式
  3. 理论上是的,您的 .a.so 文件可以进行逆向工程,但非常重要。

【讨论】:

  • 我仍然不明白如何只添加主头文件,即使使用 pimpl 范例。我使用gccar 制作.a 库的方式,我需要包含所有头文件。你能帮我吗?
  • @JoãoPereira 可能是的,SO 社区可以在一定程度上帮助您,但您需要详细说明您的问题,我会问一个更具体的问题。这将是一种小型的设计审查。你必须解释你的库在做什么,你想向它的用户公开什么接口,你的 .h 文件中有什么。目前看来他们组织得不好。基本上,您应该为用户提供一个包含必须公开内容的头文件,并将内部内容保留在其他头文件中......我认为 Mark Ransom 在他们的评论中比我更好地表达了这个想法
【解决方案2】:

我的理解是,您有一个 .c 和 .h 文件,其他人将实施该文件,但您希望对您的代码保密。

如果您只关心分发源代码,那么始终可以选择部分编译。如果您在确保您的代码正常运行方面遇到了麻烦,您可以将您的程序部分编译成 .o 文件。

我不知道你的代码的细节,但如果你提到的这个人只是像库一样实现你的功能,那么 .o 就是他所需要的。

为您准备的示例生成文件:

all: MAIN_FUNC.o

MAIN_FUNC.o: MAIN_FUNC.c MAIN_FUNC.h
    gcc -c MAIN_FUNC.c

其他人的示例makefile:

all: main

main: main.c main.h MAIN_FUNC.o
    gcc -o main.c MAIN_FUNC.o main

很多公司为了保护自己的财产而做这种事情。当一家公司向另一家公司出售软件时,他们通常会出售这些 .o 文件。您只需要提供有关该函数的功能的知识(即“此函数从控制台获取输入并返回写入为整数的字数”)——一些基本的知识,可以在不透露的情况下实施您的工作你的源代码。

编辑:修正了一个错字

【讨论】:

    【解决方案3】:

    首先,关于逆向工程。给定无限的时间和资源,您的代码总是可以被逆向工程。话虽如此,您的目标是让其他人无法对您的代码进行逆向工程。

    现在回答您的问题: 从 c 代码生成可执行二进制文件发生在“两个主要”步骤中。编译和链接。 编译后,您的 files.c 成为目标文件(机器代码)。它们还不能执行。

    如果你有两个文件:file1.c 和 file2.c,你会得到例如 file1.o 和 file2.o。

    现在,file1.c 中的代码可能正在调用 file2.o 中存在的函数。在编译阶段,file1.c 需要知道的只是函数原型。

    当调用链接器生成可执行二进制文件时,它会确保从 file1.o 调用的函数存在于某处,例如在 file2.o 中。

    这对您有何影响:

    头文件不应该是专有的(但可能是出于法律原因)。头文件主要用于告诉其他 .c 文件期望的函数和返回值(声明,而不是实现)。

    现在,也许您出于某种原因不想向世界公开一些专有功能原型。假设您希望世界通过调用函数来启动您的代码

    start_magic();
    

    那么,你要做的是:

    • 提供一个头文件:magic.h 以包含在 main.c 中
    • 头文件将有函数:void start_magic();
    • 然后将您的专有代码放入 algo.c 和 algo.h
    • algo.c 将有 start_magic() 实现
    • algo.c 将包含专有的 algo.h

    现在您可以做的是编译(不链接)您的 algo.c 文件,并去除调试符号以使其难以进行逆向工程。具体如何完成取决于您使用的编译器。

    现在您可以将目标文件和头文件提供给想要调用函数 start_magic() 的人。

    main 的实现者必须使用您提供的目标文件链接程序。

    示例

    假设您的算法中有 algo.c。假设 algo.c 具有以下功能:

    float sqrt(float x){ 
        taylor_approx(x); 
    }
    

    假设 sqrt 函数将与供应商共享。然而,sqrt 函数调用专有函数 taylor_approx(x) 来计算平方根。

    您可以创建一个 algo.h 文件发送给用户,其中包含:

    extern float sqrt(float x);
    

    然后您可以将您的-stripped from debugging symbols-compiled object file(例如algo.o)发送给用户,并要求他们将algo.h放在他们的main.c中

    请注意,这是一种方法。

    【讨论】:

    • 我还是不明白怎么只添加主头文件。我使用gccar 制作.a 库的方式,我需要包含所有头文件。你能帮我吗?
    • 你需要包含所有的头文件,在哪里?在主函数中?您必须为要调用的函数提供定义。如果您提供更多信息,将会很有帮助。你可以调用你的函数 func1(), func2(), ...
    • 假设我有 5 个 .c 和 5.h 文件。 file1.h 包括 file2.h,而 file2.h 又包括 file3.h 等等。在这种情况下如何制作一个只有 file1.h + libXXX.a 的库?
    • 您只需在单独的文件中提供有关用户将使用的功能的信息。确保使用“extern”告诉编译器它们是在另一个地方定义的。我添加的示例是否说明了这一点?
    • 这些链接显示了我的想法:network-theory.co.uk/docs/gccintro/gccintro_13.htmlnetwork-theory.co.uk/docs/gccintro/gccintro_14.html。基本上,使用 gcc -c 编译成目标文件
    【解决方案4】:

    1) 你可以将你的C 文件编译成一个库(*.a 或其他),前提是它被正确编写并与h 文件一起分发。您必须提供 h 文件,因为它们是您的库的接口,否则它只是一个二进制 blob。

    2) 您需要传递标头来声明您的库正在导出的公共接口。 IE。您希望库的用户可以访问的功能和符号。

    3) 是的,总有对任何事物进行逆向工程的方法。唯一的问题是增益/努力比。

    【讨论】:

    • 回答问题。关于第 2 点:我该怎么做?任何教程链接就足够了
    • @JoãoPereira 编写一个头文件,声明属于您的库 API 的所有函数。不需要更多。
    • 我还是不明白怎么只添加主头文件。我使用gccar 制作.a 库的方式,我需要包含所有头文件。你能帮我吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    相关资源
    最近更新 更多