应当对提供不同实现的已多次定义的同名符号进行隔离以避免意外的插入。从目标文件导出的接口中删除符号的最简单方法是将符号降级为局部符号。可以通过将符号定义为 "static" 或使用编译器提供的符号属性将符号降级为局部符号。
还可以通过使用链接编辑器和 mapfile 将符号降级为局部符号。以下示例显示了一个 mapfile,它通过使用 local 作用域指令将全局函数 error() 降级为一个局部符号。
$ cc -o A.so.1 -G -Kpic error.c a.c b.c .... $ elfdump -sN.symtab A.so.1 | fgrep error [36] 0x2d0 0x14 FUNC GLOB D 0 .text error $ cat mapfile $mapfile_version 2 SYMBOL_SCOPE { local: error; }; $ cc -o A.so.2 -G -Kpic -M mapfile error.c a.c b.c .... $ elfdump -sN.symtab A.so.2 | fgrep error [24] 0x2c8 0x14 FUNC LOCL H 0 .text error
虽然可以通过使用显式的 mapfile 定义将各个符号降级为局部符号,但建议通过符号版本控制来定义整个接口系列。请参见Chapter 9, 接口和版本控制。
版本控制是一项通常用于标识从共享目标文件导出的接口的有用技术。类似地,可以对动态可执行文件进行版本控制以定义其导出的接口。动态可执行文件只需要导出必须可供要绑定到的目标文件的依赖项使用的接口。通常,您添加到动态可执行文件的代码不需要导出接口。
从动态可执行文件删除导出的接口时应考虑已由编译器驱动程序建立的任何符号定义。这些定义源自编译器驱动程序添加到最终链接编辑的辅助文件。请参见使用编译器驱动程序。
以下示例 mapfile 导出了编译器驱动程序可以建立的一组常见的符号定义,同时将所有其他全局定义降级为局部定义。
$ cat mapfile $mapfile_version 2 SYMBOL_SCOPE { global: __Argv; __environ_lock; _environ; _lib_version; environ; local: *; };
您应当决定您的编译器驱动程序建立的符号定义。在动态可执行文件内使用的这些定义中的任何一个都应保留为全局定义。
通过从动态可执行文件删除任何导出的接口,可以防止可执行文件出现比目标文件依赖项进化时更多的插入问题。