|
|
All external data symbols are visible to applications. This can make maintenance difficult. Try to reduce global data, as described below.
First, try to use automatic (stack) variables. Don't use permanent storage if automatic variables work. Using automatic variables saves static data space and reduces the number of symbols visible to application processes.
Second, see whether variables really must be external. Static symbols are not visible outside the library, so they may change addresses between library versions. Only external variables must remain constant. For further tips, see ``Use #hide and #export to limit externally visible symbols''.
Third, allocate buffers at run time instead of defining them at compile time. This reduces the size of the library's data region for all processes (saving memory). It also allows the size of the buffer to change from one release to the next without affecting compatibility. Statically allocated buffers cannot change size without affecting the addresses of other symbols and, perhaps, breaking compatibility.
Separating text from global data
to prevent data symbols from moving.
If new external variables are needed, they can be added at the end
of the old definitions
to preserve the old symbols' addresses.
Libraries let the link editor extract individual members. This works fine for relocatable files, but shared libraries have a different set of restrictions. If external variables were scattered throughout the library modules resulting in external and static data being intermixed. Changing static data, like hello in the following example, moves subsequent data symbols, even the external symbols:
Before Broken Successor... ... int head = 0; int head = 0; ... ... func() func() { { ... ... p = "hello"; p = "hello, world"; ... ... } } ... ... int tail = 0; int tail = 0; ... ...
Assume the relative virtual address of head is 0 for
both examples.
The string literals will have the same address too,
but they have different lengths.
The old and new addresses of tail
thus might be 12 and 20, respectively.
If tail is supposed to be visible outside the library,
the two versions will not be compatible.
Adding new external variables to a shared library may change the addresses of static symbols, but this does not affect compatibility. An a.out file has no way to reference static library symbols directly, so it cannot depend on their values.
To avoid these problems, group all exported data symbols and place them at lower addresses than static (hidden) data. The following are suggestions for locating exported data symbols at lower addresses than static data:
Initialize external variables, including the pointers for imported symbols. Although this uses more disk space in the target shared library, the expansion is limited to a single file. mkshlib will give a fatal error if it finds an uninitialized external symbol.