The link-editor performs many operations including the opening of files and the concatenation of sections from these files. Monitoring, and sometimes modifying, these operations can often be beneficial to components of a compilation system.
This section describes the ld-support interface for input file inspection, and to some degree, input file data modification of those files that compose a link-edit. Two applications that employ this interface are the link-editor itself, which uses it to process debugging information within relocatable objects, and the make(1S) utility, which uses it to save state information.
The ld-support interface is composed of a support library that offers one or more support interface routines. This library is loaded as part of the link-edit process, and any support routines found are called at various stages of link-editing.
You should be familiar with the elf(3ELF) structures and file format when using this interface.
The link-editor accepts one or more support libraries provided by either the SGS_SUPPORT
environment variable or with the link-editor's -S
option. The environment variable consists of a colon separated list of support libraries:
$ SGS_SUPPORT=./support.so.1:libldstab.so.1 cc ... |
The -S option specifies a single support library. Multiple -S options can be specified:
$ LD_OPTIONS="-S./support.so.1 -Slibldstab.so.1" cc ... |
A support library is a shared object. The link-editor opens each support library, in the order they are specified, using dlopen(3DL). If both the environment variable and -S option are encountered, then the support libraries specified with the environment variable are processed first. Each support library is then searched, using dlsym(3DL), for any support interface routines. These support routines are then called at various stages of link-editing.
A support library must be consistent with the ELF class of the link-editor being invoked, either 32–bit or 64–bit. See 32–Bit and 64–Bit Environments for more details.
By default, the Solaris support library libldstab.so.1 is used by the link-editor to process, and compact, compiler-generated debugging information supplied within input relocatable objects. This default processing is suppressed if you invoke the link-editor with any support libraries specified using the -S option. If the default processing of libldstab.so.1 is required in addition to your support library services, add libldstab.so.1 explicitly to the list of support libraries supplied to the link-editor.
As described in 32–Bit and 64–Bit Environments, the 64–bit link-editor (ld(1)) is capable of generating 32–bit objects and the 32–bit link-editor is capable of generating 64–bit objects. Each of these objects has an associated support interface defined.
The support interface for 64–bit objects is similar to that of 32–bit objects, but ends in a 64 suffix, for example ld_start() and ld_start64(). This convention allows both implementations of the support interface to reside in a single shared object libldstab.so.1 of each class, 32–bit and 64–bit.
The SGS_SUPPORT
environment variable can be specified with a _32 or _64 suffix, and the link-editor options -z ld32 and -z ld64 can be used to define -S option requirements. These definitions will only be interpreted, respectively, by the 32–bit or 64–bit class
of the link-editor. This enables both classes of support library to be specified when the class of the link-editor may not be known.
All ld-support interfaces are defined in the header file link.h. All interface arguments are basic C types or ELF types. The ELF data types can be examined with the ELF access library libelf. See elf(3ELF) for a description of libelf contents. The following interface functions are provided by the ld-support interface, and are described in their expected order of use.
This function provides the initial handshake between the link-editor and the support library.
uint_t ld_version(uint_t version);
The link-editor calls this interface with the highest version of the ld-support interface it is capable of supporting. The support library can verify that this version is sufficient for its use, and return the version it expects to use. This version is normally LD_SUP_VCURRENT.
If the support library does not provide this interface, the initial support level LD_SUP_VERSION1 is assumed.
If the support library returns a version of zero, or a value greater than the ld-support interface the link-editor supports, the support library will not be used.
This function is called after initial validation of the link-editor command line, and indicates the start of input file processing.
void ld_start(const char * name, const Elf32_Half type, const char * caller); void ld_start64(const char * name, const Elf64_Half type, const char * caller);
name is the output file name being created. type is the output file type, which is either ET_DYN, ET_REL, or ET_EXEC, as defined in sys/elf.h. caller is the application calling the interface, which is normally /usr/ccs/bin/ld.
This function is called for each input file before any processing of the files data is carried out.
void ld_file(const char * name, const Elf_Kind kind, int flags, Elf * elf); void ld_file64(const char * name, const Elf_Kind kind, int flags, Elf * elf);
name is the input file about to be processed. kind indicates the input file type, which is either ELF_K_AR, or ELF_K_ELF, as defined in libelf.h. flags indicates how the link-editor obtained the file, and can be one or more of the following definitions:
LD_SUP_DERIVED – The file name was not explicitly named on the command line. It was either derived from a -l expansion, or it identifies an extracted archive member.
LD_SUP_EXTRACTED – The file was extracted from an archive.
LD_SUP_INHERITED – The file was obtained as a dependency of a command-line shared object.
If no flags values are specified then the input file has been explicitly named on the command line. elf is a pointer to the file's ELF descriptor.
This function is called for each section of the input file. This function is called before the link-editor has determined whether the section should be propagated to the output file. This function differs from ld_section() processing, which is only called for sections that contribute to the output file.
void ld_input_section(const char * name, Elf32_Shdr ** shdr, Elf32_Word sndx, Elf_Data * data, Elf * elf, unit_t flags); void ld_input_section64(const char * name, Elf64_Shdr ** shdr, Elf64_Word sndx, Elf_Data * data, Elf * elf, uint_t flags);
name is the input section name. shdr is a pointer to the associated section header. sndx is the section index within the input file. data is a pointer to the associated data buffer. elf is a pointer to the file's ELF descriptor. flags is reserved for future use.
Modification of the section header is permitted by reallocating a section header and reassigning the *shdr to the new header. The link-editor uses the section header information that *shdr points to upon return from ld_input_section() to process the section.
You can modify the data by reallocating the data and reassigning the Elf_Data buffer's d_buf pointer. Any modification to the data should ensure the correct setting of the Elf_Data buffer's d_size element. For input sections that become part of the output image, setting the d_size element to zero effectively removes the data from the output image.
The flags field points to a uint_t data field that is initially zero filled. No flags are currently assigned, although the ability to assign flags in future updates, by the link-editor or the support library, is provided.
This function is called for each section of the input file that will be propagated to the output file, but before any processing of the section data is carried out.
void ld_section(const char * name, Elf32_Shdr * shdr, Elf32_Word sndx, Elf_Data * data, Elf * elf); void ld_section64(const char * name, Elf64_Shdr * shdr, Elf64_Word sndx, Elf_Data * data, Elf * elf);
name is the input section name. shdr is a pointer to the associated section header. sndx is the section index within the input file. data is a pointer to the associated data buffer. elf is a pointer to the files ELF descriptor.
You can modify the data by reallocating the data itself and reassigning the Elf_Data buffer's d_buf pointer. Any modification to the data should ensure the correct setting of the Elf_Data buffer's d_size element. For input sections that will become part of the output image, setting the d_size element to zero will effectively remove the data from the output image.
Sections that are stripped using the link-editor's -s option, or discarded due to SHT_SUNW_COMDAT processing or SHF_EXCLUDE identification, are not reported to ld_section(). See COMDAT Section, and Table 7–14.
This function is called when input file processing is complete but before the output file is laid out.
void ld_input_done(uint_t flags);
The flags field points to a uint_t data field that is initially zero filled. No flags are currently assigned, although the ability to assign flags in future updates, by the link-editor or the support library, is provided.
This function is called when the link-edit is complete.
void ld_atexit(int status); void ld_atexit64(int status);
status is the exit(2) code that will be returned by the link-editor and is either EXIT_FAILURE or EXIT_SUCCESS, as defined in stdlib.h.
The following example creates a support library that prints the section name of any relocatable object file processed as part of a 32–bit link-edit.
$ cat support.c #include <link.h> #include <stdio.h> static int indent = 0; void ld_start(const char * name, const Elf32_Half type, const char * caller) { (void) printf("output image: %s\n", name); } void ld_file(const char * name, const Elf_Kind kind, int flags, Elf * elf) { if (flags & LD_SUP_EXTRACTED) indent = 4; else indent = 2; (void) printf("%*sfile: %s\n", indent, "", name); } void ld_section(const char * name, Elf32_Shdr * shdr, Elf32_Word sndx, Elf_Data * data, Elf * elf) { Elf32_Ehdr * ehdr = elf32_getehdr(elf); if (ehdr->e_type == ET_REL) (void) printf("%*s section [%ld]: %s\n", indent, "", (long)sndx, name); } |
This support library is dependent upon libelf to provide the ELF access function elf32_getehdr(3ELF) that is used to determine the input file type. The support library is built using:
$ cc -o support.so.1 -G -K pic support.c -lelf -lc |
The following example shows the section diagnostics resulting from the construction of a trivial application from a relocatable object and a local archive library. The invocation of the support library, in addition to default debugging information processing, is brought about by the -S option usage.
$ LD_OPTIONS="-S./support.so.1 -Slibldstab.so.1" \ cc -o prog main.c -L. -lfoo output image: prog file: /opt/COMPILER/crti.o section [1]: .shstrtab section [2]: .text ....... file: /opt/COMPILER/crt1.o section [1]: .shstrtab section [2]: .text ....... file: /opt/COMPILER/values-xt.o section [1]: .shstrtab section [2]: .text ....... file: main.o section [1]: .shstrtab section [2]: .text ....... file: ./libfoo.a file: ./libfoo.a(foo.o) section [1]: .shstrtab section [2]: .text ....... file: /usr/lib/libc.so file: /opt/COMPILER/crtn.o section [1]: .shstrtab section [2]: .text ....... file: /usr/lib/libdl.so.1 |
The number of sections displayed in this example have been reduced to simplify the output. Also, the files included by the compiler driver can vary.