3

没有 RTOS/OS 的小型嵌入式系统是否使用动态/共享库。我的理解是,它很难使用,而且不会有成效。

如果我们多次调用静态库中存在的 API。API 代码是否将放置在每个调用位置,例如宏扩展或代码/文本对于所有调用都是通用的。我认为代码/文本会很常见。

如果我为具有多个 API 的 .c 文件创建了一个静态库,并且我将它与主文件静态链接,并且在主文件中只调用了一个 API,所以我的问题是整个库是否包含在最终的 .bin 中或仅包含特定的 API 代码。

从上述问题中,您可以假设我本身缺少基础知识,因此任何人都可以提供相关链接来复习这些内容。

问候
[编辑]

我尝试过以下事情

add.c 模块

`int addition(int a,int b)`  
`{`  
`int result;`  
`result = a + b;`  
`return result;`  
`}`

`size addition.o`   
23        0       0      23      17 addition.o    

乘法.c 模块

`int multiplication(int a, int b)`  
`{`  
`int result;`  
`result = a * b;`  
`return result;`  
`}`
`size multiplication.o`  
21        0       0      21      15 multiplication.o  

创建两者的目标文件并放入存档

ar cr libarith.a addition.o multiplication.o   

然后静态链接到我的主应用程序
example.c 模块

`#include "header.h"`  
`#include <stdio.h>`  
`1:int main()`  
`2:{`  
`3:int result;`  
`4:result = addition(1,2);`  
`5:printf("addition result is : %d\n",result);`  
`6:result = multiplication(3,2);`  
`7:printf("multiplication result is :  %d\n",result);`  
`8:return 0;`  
`9:}`

gcc -static example.c -L. -larith -o example  

size of example  
511141     1928    7052  520121   7efb9 example  

注释了 example.c 的第 6 行
并再次链接
gcc -static example.c -L。-larith -o example
size of example
511109 1928 7052 520089 7ef99 example
以上两个之间的差异为 32 个字节,
这意味着 add.o 不包括在示例中

将模块 add.c 和 multiplication.c 合并为 addmult.c 如下
int addition(int a,int b)
{
int result;
result = a + b;
return result;
}
int multiplication(int a, int b)
{
int result;
result = a * b;
return result;
}

创建目标文件并在
执行此操作之前放入存档我已删除以前
的存档 ar cr libarith.a addmult.o
现在注释了 example.c
gcc -static example.c -L 的第 6 行。-larith -o 示例
大小示例
511093 1928 7052 520073 7ef89 示例未
注释的第 6 行 example.c
大小示例 511141 1928 7052 520121 7efb9 示例

我的问题是在这两种情况下,如果两个函数都被调用,最终文本大小是相同的,但如果只调用一个函数,则差异为 16,但 multiplication.o 大小为 23,所以肯定不包括在内,但我们将如何证明 16 是合理的。如果我缺少一些基本知识本身?

4

3 回答 3

5

在运行时动态加载和链接库需要代码来执行加载/链接操作。该功能通常是操作系统的一部分。此外,在没有某种海量存储的系统中,动态链接不会有任何好处,因为在任何情况下动态链接的代码都必须存在于内存中,因此也可能是静态链接的。

要回答您问题的第二部分,静态库只是存档中目标文件的集合。链接器将仅提取和链接解析整个可执行文件中引用的符号所需的目标代码。一些智能链接器可以从目标文件中丢弃未使用的函数,但您不应该依赖它。

因此,通过链接静态库,您不会在库中包含所有未使用的代码。您可以通过将所有库文件的大小与可执行二进制文件的大小进行比较来判断 - 您可能会看到您的可执行文件远小于链接的库大小的总和。此外,您的链接器将可以选择创建一个映射文件,该文件将准确告诉您包含了哪些代码,以及它是否具有交叉引用输出工具、哪些代码引用或被什么引用。

如果您正在构建自己的静态库,甚至是您自己的非库代码,那么在目标文件级别确保良好的粒度是值得的。例如,如果一个目标文件包含两个函数,一个已使用,一个未使用,大多数链接器别无选择,只能同时包含这两个函数,而如果这些函数是在单独的编译单元(源文件)中定义的,那么它们将位于单独的目标文件中(即使整理到库中)并且可以单独链接。

于 2012-07-29T10:14:03.003 回答
3

如果你真的有一个没有任何操作系统的嵌入式系统,那么你的硬件本质上是一个固定的软件,你只能通过物理方式来改变它(例如烙铁,或插上什么东西……)。在这种情况下,该软件在“裸机”上运行,并且以某种方式执行操作系统提供的功能(它管理物理资源并通过适当的机器指令直接与 I/O 端口交互)。

特别是,没有任何操作系统的嵌入式系统不能拥有任何类型的动态库,因为根据定义,这些库需要位于某些文件中(在嵌入式处理器上),并且要拥有文件,您需要操作系统。

究竟什么是操作系统的确切定义是有争议和模糊的。我相信提供文件系统是大多数当前操作系统的角色之一

由于共享库(或静态库)是位于某些文件中的库,因此没有操作系统就无法拥有它们。根据定义,提供文件的东西是操作系统。

也许您正在使用交叉开发链来开发您的嵌入式软件。如果您想获得在裸机上运行的东西,您的链最终必须提供一个二进制映像,您可以将其闪存到 ROM 中,然后焊接或插入该 ROM - 或以某种方式物理传输 - 到您的嵌入式硬件中(一些工具使您能够刷新整个独立处理器)。

我相信你可能会感到困惑,你应该阅读更多关于操作系统内核linux内核文件系统系统调用RTOS链接器加载器、交叉编译器微控制器共享库动态链接器......

正如 Clifford 在评论中建议的那样,您可以拥有一个带有一些文件系统和一些动态链接器的嵌入式系统;在我看来,这将是一个胚胎操作系统,但这是一个有争议的定义问题。

请注意,制作动态链接器可能不是一件容易的事(您需要进行重定位);你可以制作一个通用的ELF动态加载器,或者你可以限制动态加载模块的形式,或者使用你的特定ld 脚本来生成它们。

于 2012-07-29T09:09:05.277 回答
2

您已经具备了所需的所有基础知识。如果没有操作系统、大容量存储(磁盘、文件系统等)和多个/许多不同的程序可以利用共享库,它就没有任何意义。你没有保存任何东西,如果你伪造它足以在固定的裸机环境中使用共享库,它可能会花费你更多。

你提到有codesourcery,你是如何学习这些东西的?你反汇编你的二进制文件,看看编译器做了什么。它是否因为您使用了一个分割而链接了整个 gcc 库?它是否因为您使用了一个函数而链接了整个 C 库(它甚至可以尝试链接 C 库函数,许多系统调用必须解决您必须解决的操作系统)。首先在一个非常简单的函数中使用一个简单的除法(需要是通用的)

unsigned int fun ( unsigned int a, unsigned int b )
{
 return(a/b);
}

不要使用固定常量调用该函数,也不要从同一个 .c 文件中调用它,最好的办法是简单地按原样添加该函数,并且不做任何其他事情,让它坐在那里。即使尝试编译它,您也可能会遇到问题,一旦您这样做,反汇编并查看编译器对它做了什么,查看是否添加了整个 gcc 库或仅添加了该函数的代码。

您不能信任任何旧网页或资源,因为它可能与您正在使用的工具不同并且可能已经过时,您现在使用的编译器是最重要的,现在,没有其他。答案就在你面前。

不,他们不使用动态库,所需的功能根据需要链接。优化器可能会选择内联一些代码,但一般来说,每个函数的代码都在一个地方,每次调用都是一次调用,一般来说,它不像宏。再次,优化器可能出于性能原因选择其他方式(足够小的函数不会消耗太多内存,并且足够小以至于与函数本身相比,进行函数调用所需的代码过多。此外,该函数需要进行相同的优化空间,对于 gcc,这是同一个 .c 文件,对于 llvm,这可以是项目中的任何代码。

我有一些例子,cortex-m 和其他的,裸机。 http://github.com/dwelch67您可能会发现一些可能有助于回答您的问题,例如检查编译器是否会实现与上述类似的公共函数并在使用时将其内联。如果您将该函数声明为静态,则优化器(如果它内联)不需要在二进制文件中实现该函数。例如,如果您在同一个 .c 文件中调用类似的函数

c = fun(10,5);

如果使用优化器,很有可能会将该代码替换为

c = 2;

并且根本不执行除法。

于 2012-07-30T03:06:00.533 回答