Concepts
这种共享库的最基本概念。
这方面存在一些变体。您支持库之间的链接吗?参考文献是DAG http://en.wikipedia.org/wiki/Directed_acyclic_graph结构还是全循环?您想将代码放入ROM中,还是支持代码更新?您希望在之后加载库吗?process最初运行的是?最后一项通常是之间的区别静态共享库 and 动态共享库。尽管很多人也会禁止图书馆之间的引用。
设施
最终,一切都将取决于处理器的寻址模式。在本例中为 ARM 拇指。这loader通常与操作系统和使用的二进制格式耦合。您的工具链(编译器和链接器)还必须支持二进制格式并且可以生成所需的代码。
通过寄存器访问数据的支持是固有的APCS http://www.chiark.greenend.org.uk/%7Etheom/riscos/docs/CodeStds/APCS.txt(ARM 过程调用标准)。在这种情况下,数据是通过sb
(对于静态基址)这是寄存器R9
. The 静态基地 and 堆栈检查是可选功能。我相信您可能需要配置/编译 GCC 来启用或禁用这些选项。
选项-msingle-pic-base
and -mpic-register
都在海湾合作委员会手册 https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/ARM-Options.html。这个想法是,操作系统最初会为每个库用户分配单独的数据,然后加载/重新加载sb
在上下文切换上。当代码运行到库时,通过以下方式访问数据sb
对于该实例的数据。
Gcc's arm.c code https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/config/arm/arm.c;hb=HEAD#l6387 has the require_pic_register()
which does code generation for data references in a shared library. It may correspond to the ARM ATPCS shared library http://infocenter.arm.com/help/topic/com.arm.doc.espc0002/ATPCS.pdf mechanics.See Sec 5.5
您可以通过使用宏和内联汇编器以及可能的函数注释来规避工具链,例如naked and section https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html。然而,在这种情况下,库和可能的进程需要修改代码;即,非标准宏,例如EXPORT(myFunction)
, etc.
一种可能性
如果系统已完全指定(ROM 映像),您可以预先生成系统中每个库唯一的数据偏移量。使用链接器脚本可以相当轻松地完成此操作。使用NOLOAD
并将图书馆数据放入某个虚假部分。甚至可以将主程序设为静态共享库。例如,您正在制作一个具有四个以太网端口的网络设备。主应用程序处理一个端口上的流量。您可以使用不同的数据生成应用程序的四个实例,以指示正在处理哪个端口。
如果您有大量混合/匹配的库类型,则库数据的占用空间可能会变大。这种情况下需要重新调整sb
当通过外部 API 上的包装函数对库进行调用时。
void *__wrap_malloc(size_t size) /* Wrapped version. */
{
/* Locals on stack */
unsigned int new_sb = glob_libc; /* accessed via current sb. */
void * rval;
unsigned int old_sb;
volatile asm(" mov %0, sb\n" : "=r" (old_sb);
volatile asm(" mov sb, %0\n" :: "r" (new_sb);
rval = __real_malloc(size);
volatile asm(" mov sb, %0\n" :: "r" (old_sb);
return rval;
}
See the GNU ld --wrap https://sourceware.org/binutils/docs/ld/Options.html选项。如果您有更大的同质库集,则需要这种复杂性。如果您的库仅包含“libc/libsupc++”,那么您可能不需要包装任何内容。
The ARM ATPCS http://infocenter.arm.com/help/topic/com.arm.doc.espc0002/ATPCS.pdf编译器插入了具有等效功能的胶合板,
LDR a4, [PC, #4] ; data address
MOV SB, a4
LDR a4, [PC, #4] ; function-entry
BX a4
DCD data-address
DCD function-entry
使用此技术的库数据的大小为 4k(可能是 8k,但这可能需要编译器修改)。限制是通过ldr rN, [sb, #offset]
,ARM 将偏移量限制为 12 位。使用包装时,每个库都有 4k 的限制。
如果您有多个在构建原始应用程序时未知的库,那么您需要包装每个库,并通过操作系统加载程序将 GOT 类型表放置在主应用程序静态库中的固定位置。每个应用程序都需要为每个库的指针提供空间。如果应用程序不使用该库,则操作系统不需要分配空间,并且该指针可以是NULL
.
The 图书馆桌可以通过已知位置访问.text
,通过原始流程sb
或通过堆栈的掩码。例如,如果所有进程都有 2K 堆栈,则可以为库表保留较低的 16 个字。sp & ~0x7ff
将为所有任务提供隐式锚点。操作系统还需要分配任务堆栈。
请注意,此机制与 ATPCS 不同,后者使用sb
作为一个表格来获取实际库数据的偏移量。由于所描述的 Cortex-M3 的内存相当有限,因此每个单独的库不太可能需要使用超过 4k 的数据。如果系统支持分配器,则可以解决此限制。
参考
-
Xflat 技术概述 http://xflat.sourceforge.net/NoMMUSharedLibs.html- 技术讨论Xflat作者;Xflat http://xflat.sourceforge.net/XFLATTableOfContents.html是支持共享库的 uCLinux 二进制格式。非常好的读物。
-
联动表与GOT https://stackoverflow.com/questions/9688076/process-linkage-table-and-global-offset-table- PLT 和 GOT 也是如此。
-
ARM EABI http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0036b/index.html- 正常的 ARM 二进制格式。
-
组装机和装载机 http://www.davidsalomon.name/assem.advertis/asl.pdf, by 大卫·所罗门。特别是,pg262A.3 基址寄存器
-
ARM ATPCS http://infocenter.arm.com/help/topic/com.arm.doc.espc0002/ATPCS.pdf, 尤其第 5.5 节,共享库, pg18.
-
bFLT https://web.archive.org/web/20080229171450/http://www.beyondlogic.org/uClinux/bflt.htm是另一种支持共享库的 uCLinux 二进制格式。