How To Write Shared Libraries(26)

2.2.3 Define Per-Symbol Visibility

Instead of changing the default visibility the programmer can choose to define to hide individual symbols. Or, if the default visibility is hidden, make specific symbols ex- portable by setting the visibility to default.
开发者可以设置可见性替代默认值。如果默认是隐藏的,设置需要导出的为默认。

Since the C language does not provide mechanisms to define the visibility of a function or variable gcc resorts once more to using attributes:
由于c语言没有提供可见性的机制,gcc用法如下:

int last
__attribute__ ((visibility ("hidden")));
int
__attribute__ ((visibility ("hidden"))) next (void) {
  return ++last;
}
int index (int scale) {
  return next () << scale;
}

This defines the variable last and the function next as hidden. All the object files which make up the DSO which contains this definition can use these symbols. I.e., while static restricts the visibility of a symbol to the file it is defined in, the hidden attribute limits the visibil- ity to the DSO the definition ends up in. In the example above the definitions are marked. This does not cause any harm but it is in any case necessary to mark the declaration. In fact it is more important that the declarations are marked appropriately since it is mainly the code generated for in a reference that is influenced by the attribute.
设置last和next隐藏。组成DSO的所有文件都可以使用这些内容。static限制范围为本文件,属性hidden限制为组成的DSO。定义如示例。这样除了需要在使用的地方声明没有任何其他副作用。事实上适当的标记更重要,因为代码依赖这些内容生成。

Instead of adding an visibility attribute to each declaration or definition, it is possible to change the default temporarily for all definitions and declarations the compiler sees at this time. This is mainly useful in header files since it reduces changes to a minimum but can also be useful for definitions. This compiler feature was also in- troduced in gcc 4.0 and is implemented using a pragma:
替代设置属性的方式是临时改变编译器可见的定义和声明属性。这主要用于头文件减少代码改变并且好用。这个编译器特征在gcc 4.0引入,实现用法如下:

#pragma GCC visibility push(hidden)
int last;
int next (void) {
  return ++last;
}
#pragma GCC visibility pop
int index (int scale) {
  return next () << scale;
}

As in the example using the attributes, last and next are both defined with hidden visibility while index is defined with default visibility (assuming this is the default currently in use). As the pragma syntax suggests, it is possible to nest the pragmas with the expected result.
示例中last、next为hidden,index为default。可以嵌套使用。

In case the -fvisibility=hidden command line op- tion is used, individual symbols can be marked as exportable by using the same syntax as presented in this section, except with default in place of hidden. In fact, the names of all four visibilities are allowed in the attribute or pragma.
在使用-fvisibility=hidden的编译中可以使用这里的内容标记一些语法内容为导出,使用defualt替代hidden。实际上4个属性都可使用。

Beside telling the backend of the compiler to emit code to flag the symbol as hidden, changing the visibility has another purpose: it allows the compiler to assume the defi- nition is local. This means the addressing of variables and function can happen as if the definitions would be locally defined in the file as static. Therefore the same code sequences we have seen in the previous section can be generated. Using the hidden visibility attribute is therefore almost completely equivalent to using static; the only difference is that the compiler cannot automatically inline the function since it need not see the definition.
除了标记代码hidden,这些标记还有其他目的:允许编译器假定本地使用。这就意味着变量和函数的地址就像文件内static定义一样使用。
因此,可以生成我们在前一节中看到的相同的代码序列。(有道翻译)
使用hidden属性几乎等价于使用static,唯一的不同是编译器不能自动内联函数,原因是需要隐藏。

We can now refine the rule for using static: merge source files and mark as many functions static as far as one feels comfortable. In any case merge the files which contain functions which potentially can be inlined. In all other cases mark functions (the declarations) which are not to be exported from the DSO as hidden.
现在完善static的规则:合并尽量多的设置static的文件。一方面合并文件包含函数可以是内联的。另一方面标记的内容不能导出DSO。

Note that the linker will not add hidden symbols to the dynamic symbol table. I.e., even though the symbol tables of the object files contain hidden symbols they will disappear automatically. By maximizing the number of hidden declarations we therefore reduce the size of the symbol table to the minimum.
注意,连接器不会增加hidden到动态表。即使这个对象语法标记了hidden。最大限度的增加hidden声明减少语法表的大小。

The generic ELF ABI defines another visibility mode: protected. In this scheme references to symbols defined in the same object are always satisfied locally. But the symbols are still available outside the DSO. This sounds like an ideal mechanism to optimize DSO by avoiding the use of exported symbols (see section 2.2.7) but it isn’t.
一般ELF定义另一个可见性:protected。
在这个方案中,对同一对象中定义的符号的引用总是局部满足的。(有道翻译)
但是这些标识在DSO之外可见。
这听起来像是一个通过避免使用输出符号来优化DSO的理想机制(见第2.2.7节),但事实并非如此。(有道翻译)
Processing references to protected symbols is even more expensive than normal lookup. The problem is a requirement in the ISO C standard. The standard requires that function pointers, pointing to the same function, can be compared for equality. This rule would be violated with a fast and simple-minded implementation of the protected visibility. Assume an application which references a protected function in a DSO. Also in the DSO is another function which references said function.
处理protected的语法比处理普通的要更费力。这是c标准的一个问题。标准要求指向相同函数指针可以比较是否相等。这个规则可一个更快的protected实现冲突。假定一个应用使用一个protected的函数。DSO中另一个函数应用了这个函数。
The pointer in the application points to the PLT entry for the function in the application’s PLT. If a protected symbol lookup would simply return the address of the function inside the DSO the addresses would differ.
应用程序中的指针指向应用程序的PLT中的函数的PLT条目。如果一个受保护的符号查找只是返回DSO中函数的地址,那么地址就会不同。(有道翻译)

In programming environments without this requirement on function pointers the use of the protected visibility would be useful and fast. But since there usually is only one implementation of the dynamic linker on the system and this implementation has to handle C programs as well, the use of protected is highly discouraged.
如果开发环境没有这个要求速度会更快。
但是,由于动态连接器在系统上通常只有一个实现,而且这个实现还必须处理C程序,因此非常不建议使用protected。(有道翻译)

There are some exceptions to these rules. It is possible to create ELF binaries with non-standard lookup scopes. The simplest example is the use of DF SYMBOLIC (or of DT SYMBOLIC in old-style ELF binaries, see page 25).In these cases the programmer decided to create a non- standard binary and therefore accepts the fact that the rules of the ISO C standard do not apply.
有一些异常情况不需要遵循这个规则。可以实现非标准的ELF查找表。最简单的实现是使用DF SYMBOLIC。这种情况下开发者决定创建一个非标准的程序并接受C标准没有处理的事实。

你可能感兴趣的:(How To Write Shared Libraries(26))