Go to main content

Oracle® Solaris 11.4 Linkers and Libraries Guide

Exit Print View

Updated: March 2019

Removing Unused Material

The inclusion of functions and data from input relocatable object files, when this material is not used by the object being built, is wasteful. This unneeded material causes the object to be larger than necessary, resulting in added overhead when the object is used at runtime.

References to unused shared object dependencies are also wasteful. Particularly in the absence of lazy loading, these references result in the unnecessary loading and processing of these shared objects at runtime.

Unused sections, unused relocatable object files, and unused shared object dependencies can be diagnosed during a link-edit by using the link-editors debugging option –D unused.

Unused files and dependencies are also diagnosed when using the –z guidance option.

Unused sections, unused files, and unused dependencies should be removed from the link-edit. This removal reduces the cost of the link-edit, and reduces the runtime cost of using the object being built. However, if removing these items is problematic, unused material can be discarded from the object being built by using the –z discard-unused option.

Removing Unused Sections

An ELF section, from an input relocatable object file, is determined to be unused when three conditions are true.

  • The section provides no global symbols.

  • The section contributes to an allocatable segment.

  • The section is not referenced by any other used section, from any object, that contributes to the link-edit.

Unused sections can be discarded from the link-edit by using the –z discard-unused=sections option.

You can improve the link-editor's ability to diagnose and discard unused sections by defining the dynamic object's external interfaces. See Interfaces and Versioning. By defining an interface, global symbols that are not defined as part of the interface are reduced to locals. Reduced symbols that are unreferenced from other objects, are then clearly identified as candidates for discarding.

Individual functions and data variables can be discarded by the link-editor if these items are assigned to their own sections. This section refinement can be achieved by using the –xF compiler option.

Removing Unused Files

An input relocatable object file is determined to be unused if all allocatable sections provided by the relocatable object are unused.

Unused files are diagnosed with the –z guidance option, and can be discarded from the link-edit by using the –z discard-unused=files option.

The –z discard-unused option provides independent control over unused sections and unused files in order to compliment –z guidance processing. Under –z guidance, files that are determined to be unused are identified. Unused files can often easily be removed from a link-edit. However, sections that are determined to be unused are not identified under –z guidance processing. Unused sections can involve much more investigation and effort to remove and can be a consequence of compiler actions that are beyond your control.

By using the –z discard-unused=sections option together with the –z guidance option, unused sections are automatically removed, while unused files are identified for you to remove from the link-edit.

Removing Unused Dependencies

An explicit, shared object dependency is one that is defined on the command line, either using the path name, or more commonly by using the –l option. Explicit dependencies include those that might be provided by the compiler drivers, such as –lc.

Implicit dependencies are the dependencies of explicit dependencies. Implicit dependencies can be processed as part of a link-edit to complete the closure of all symbol resolution. This symbol closure ensures that the object being built is self-contained, with no unreferenced symbols remaining.

All dynamic objects should define the dependencies they require. This requirement is enforced by default when building an executable, but not when building a shared object. Use the –z defs option to enforce this requirement when building a shared object.

All dynamic objects should refrain from defining dependencies that they do not require. Loading such unused dependencies at runtime is unnecessary and wasteful.

An explicit dependency is determined to be unused if two conditions are true.

  • No global symbols that are provided by the dependency are referenced from the object being built.

  • The dependency does not compensate for the requirements of any implicit dependencies.

Unused dependencies are diagnosed with the –z guidance option. These dependencies should be removed from the link-edit. However, if removing these items is problematic, unused dependencies can be discarded from the object being built by using the –z discard-unused=dependencies option.

Unfortunately, shared objects exist that have not defined all the dependencies they require. In these cases, developers often add the missing dependencies to the executable, or other shared objects they are building, rather than rebuild the original dependency correctly. Such dependencies are referred to as compensating dependencies.

For example, consider a shared object, foo.so, that references the symbol bar() from the shared object bar.so. However, foo.so does not express a dependency upon bar.so. An inspection of foo.so reveals the lack of the required dependency, as the symbol bar() can not be found.

% ldd -r foo.so
     libc.so.1 =>     /lib/libc.so.1
     symbol not found: bar           (foo.so)

Now consider an application developer that wishes to create an executable that references the symbol foo() from the shared object foo.so. The required dependency upon foo.so is specified, but the link-edit of the executable fails.

% cc -B direct -o main main.c -L. -lfoo
Undefined                       first referenced
  symbol                             in file
  bar                                 ./libfoo.so
ld: fatal: symbol referencing errors

The developer forcibly corrects this situation by adding a compensating dependency on bar.so.

% cc -B direct -o main main.c -L. -lfoo -lbar

This correction creates an application that loads all the necessary dependencies at runtime, and therefore appears to resolve the issue. However, the result is fragile. If a future delivery of foo.so is made that does not require a symbol from bar.so, then this application will load bar.so for no reason. The better solution is to correct foo.so by adding the missing dependency bar.so.

The occurrence of a compensating dependency is diagnosed though guidance.

% cc -B direct -z guidance -o main main.c -L. -lfoo -lbar
ld: guidance: removal of compensating dependency recommended: libbar.so

Compensating dependencies are diagnosed through guidance, but they are not removed under –z discard-unused=dependencies. Although the dependency might be unused in relation to the object being created, the dependency is used by other components of the link-edit. To remove this dependency could result in creating an object that can not be executed at runtime.

The need for compensating dependencies can be eliminated by the systematic use of the –z defs option to build all dynamic objects.

The –z ignore and –z record options are positional options that can be used in conjunction with the –z discard-unused=dependencies option. These positional options turn the discard feature on and off selectively for targeted objects.