Go to main content

Oracle® Solaris 11.4 Linkers and Libraries Guide

Exit Print View

Updated: October 2019
 
 

Ancillary Objects

By default, objects contain both allocable and non-allocable sections. Allocable sections are the sections that contain executable code and the data needed by that code at runtime. Non-allocable sections contain supplemental information that is not required to execute an object at runtime. These sections support the operation of debuggers and other observability tools. The non-allocable sections in an object are not loaded into memory at runtime by the operating system, and so, they have no impact on memory use or other aspects of runtime performance no matter their size.

For convenience, both allocable and non-allocable sections are normally maintained in the same file. However, there are situations in which it can be useful to separate these sections.

  • To reduce the size of objects in order to improve the speed at which they can be copied across wide area networks.

  • To support fine grained debugging of highly optimized code requires considerable debug data. In modern systems, the debugging data can easily be larger than the code it describes. The size of a 32-bit object is limited to 4 Gbytes. In very large 32-bit objects, the debug data can cause this limit to be exceeded and prevent the creation of the object.

  • To limit the exposure of internal implementation details.

Traditionally, objects have been stripped of non-allocable sections in order to address these issues. Stripping is effective, but destroys data that might be needed later. The Solaris link-editor can instead write non-allocable sections to an ancillary object. This feature is enabled with the –z ancillary option.

$ cc .... -z ancillary[=outfile] ....

By default, the ancillary file is given the same name as the primary output object, with a .anc file extension. However, a different name can be provided by providing an outfile value to the –z ancillary option.

When –z ancillary is specified, the link-editor performs the following actions.

  • All allocable sections are written to the primary object. In addition, all non-allocable sections containing one or more input sections that have the SHF_SUNW_PRIMARY section header flag set are written to the primary object.

  • All remaining non-allocable sections are written to the ancillary object.

  • The following non-allocable sections are written to both the primary object and ancillary object.

    .shstrtab

    The section name string table.

    .symtab

    The full non-dynamic symbol table.

    .symtab_shndx

    The symbol table extended index section associated with .symtab.

    .strtab

    The non-dynamic string table associated with .symtab.

    .SUNW_ancillary

    Contains the information required to identify the primary and ancillary objects, and to identify the object being examined.

  • The primary object and all ancillary objects contain the same array of sections headers. Each section has the same section index in every file.

  • Although the primary and ancillary objects all define the same section headers, the data for most sections will be written to a single file. If the data for a section is not present in a given file, the SHF_SUNW_ABSENT section header flag is set, and the sh_size field is 0.

This organization makes it possible to acquire a full list of section headers, a complete symbol table, and a complete list of the primary and ancillary objects from either of the primary or ancillary objects.

The following example illustrates the underlying implementation of ancillary objects. An ancillary object is created by adding the –z ancillary command line option to an otherwise normal compilation. The file utility shows that the result is an executable named a.out, and an associated ancillary object named a.out.anc.

$ cat hello.c
#include    <stdio.h>

int
main(int argc, char **argv)
{
        (void) printf("hello, world\n");
        return (0);
}
$ cc -g -z ancillary hello.c
$ file a.out a.out.anc
a.out: ELF 32-bit LSB executable 80386 Version 1 [FPU], dynamically \
    linked, not stripped, ancillary object a.out.anc
a.out.anc: ELF 32-bit LSB ancillary 80386 Version 1, primary object a.out
$ ./a.out
hello world

The resulting primary object is an ordinary executable that can be executed in the usual manner. It is no different at runtime than an executable built without the use of ancillary objects, and then stripped of non-allocable content using the strip or mcs commands.

As previously described, the primary object and ancillary objects contain the same section headers. To see how this works, it is helpful to use the elfdump utility to display these section headers and compare them. The following table shows the section header information for a selection of headers from the previous link-edit example.

Index
Section Name
Type
Primary Flags
Ancillary Flags
Primary Size
Ancillary Size
13
.text
PROGBITS
ALLOC EXECINSTR
ALLOC EXECINSTR SUNW_ABSENT
0x131
0
20
.data
PROGBITS
WRITE ALLOC
WRITE ALLOC SUNW_ABSENT
0x4c
0
21
.symtab
SYMTAB
0
0
0x450
0x450
22
.strtab
STRTAB
STRINGS
STRINGS
0x1ad
0x1ad
24
.debug_info
PROGBITS
SUNW_ABSENT
0
0
0x1a7
28
.shstrtab
STRTAB
STRINGS
STRINGS
0x118
0x118
29
.SUNW_ancillary
SUNW_ancillary
0
0
0x30
0x30

The data for most sections is only present in one of the two files, and absent from the other file. The SHF_SUNW_ABSENT section header flag is set when the data is absent. The data for allocable sections needed at runtime are found in the primary object. The data for non-allocable sections used for debugging but not needed at runtime are placed in the ancillary file. A small set of non-allocable sections are fully present in both files. These are the .SUNW_ancillary section used to relate the primary and ancillary objects together, the section name string table .shstrtab, as well as the symbol table.symtab, and its associated string table .strtab.

It is possible to strip the symbol table from the primary object. A debugger that encounters an object without a symbol table can use the .SUNW_ancillary section to locate the ancillary object, and access the symbol contained within.

The primary object, and all associated ancillary objects, contain a .SUNW_ancillary section that allows all the objects to be identified and related together.

$ elfdump -T SUNW_ancillary a.out a.out.anc
a.out:
Ancillary Section:  .SUNW_ancillary
   index  tag                    value
     [0]  ANC_SUNW_CHECKSUM     0x8724
     [1]  ANC_SUNW_MEMBER       0x1         a.out
     [2]  ANC_SUNW_CHECKSUM     0x8724
     [3]  ANC_SUNW_MEMBER       0x1a3       a.out.anc
     [4]  ANC_SUNW_CHECKSUM     0xfbe2
     [5]  ANC_SUNW_NULL         0

a.out.anc:
Ancillary Section:  .SUNW_ancillary
   index  tag                    value
     [0]  ANC_SUNW_CHECKSUM     0xfbe2
     [1]  ANC_SUNW_MEMBER       0x1         a.out
     [2]  ANC_SUNW_CHECKSUM     0x8724
     [3]  ANC_SUNW_MEMBER       0x1a3       a.out.anc
     [4]  ANC_SUNW_CHECKSUM     0xfbe2
     [5]  ANC_SUNW_NULL         0          

The ancillary sections for both objects contain the same number of elements, and are identical except for the first element. Each object, starting with the primary object, is introduced with a MEMBER element that gives the file name, followed by a CHECKSUM that identifies the object. In this example, the primary object is a.out, and has a checksum of 0x8724. The ancillary object is a.out.anc, and has a checksum of 0xfbe2. The first element in a .SUNW_ancillary section, preceding the MEMBER element for the primary object, is always a CHECKSUM element, containing the checksum for the file being examined.

  • The presence of a .SUNW_ancillary section in an object indicates that the object has associated ancillary objects.

  • The names of the primary and all associated ancillary objects can be obtained from the ancillary section from any one of the files.

  • It is possible to determine which file is being examined from the larger set of files by comparing the first checksum value to the checksum of each member that follows.


Note -  The link editor does not read ancillary objects as input. If a relocatable object is created using the –z ancillary option, and the resulting object is later referenced to build another object, the sections from the ancillary object are not propagated to the final object.

Debugger Access and Use of Ancillary Objects

Debuggers and other observability tools must merge the information found in the primary and ancillary object files in order to build a complete view of the object. This is equivalent to processing the information from a single file. This merging is simplified by the primary object and ancillary objects containing the same section headers, and a single symbol table.

The following steps can be used by a debugger to assemble the information contained in these files.

  1. Starting with the primary object, or any of the ancillary objects, locate the .SUNW_ancillary section. The presence of this section identifies the object as part of an ancillary group, contains information that can be used to obtain a complete list of the files and determine which of those files is the one currently being examined.

  2. Create a section header array in memory, using the section header array from the object being examined as an initial template.

  3. Open and read each file identified by the .SUNW_ancillary section in turn. For each file, fill in the in-memory section header array with the information for each section that does not have the SHF_SUNW_ABSENT flag set.

The result will be a complete in-memory copy of the section headers with pointers to the data for all sections. Once this information has been acquired, the debugger can proceed as it would in the single file case, to access and control the running program.


Note -  The ELF definition of ancillary objects provides for a single primary object, and an arbitrary number of ancillary objects. At this time, the Oracle Solaris link-editor only produces a single ancillary object containing all non-allocable sections. This may change in the future. Debuggers and other observability tools should be written to handle the general case of multiple ancillary objects.