Linker Plugins
Overview
The ELD allows one or more linker plugins to be loaded and called during link time.
Develop the linker plug-ins to query the linker about objects being linked during link time, and to evaluate their properties.
You can also change the order and contents of output sections using this approach.
Use C++ to develop the linker plugins.
They are built as shared libraries that allow the linker to dynamically load at link time.
The plugins use a fixed API that allows you to communicate with the linker.
Plugins are currently supported on all architectures where the functionality is available.
The Map file records any changes made by the plugin for the layout. This is a good place to determine how the layout was affected due to the plug-in algorithm.
Plugin Usage
Most developers use linker scripts, and the linker plugin functionality can therefore be exercised using linker scripts.
This is to promote ease of use and have less maintenance overhead.
It is also easier to integrate with existing builds.
The linker can also provide better diagnostics.
Linker wrapper
Build a plugin as a dynamic library and interact with the linker using an opaque LinkerWrapper handle.
The linker wrapper exists as a shared library that you link with the user plugin.
The linkerwrapper is named libLW.so on Linux platforms and LW.dll on Windows platforms.
User Plugin Types
The intent of each user-developed plugin is associated with an appropriate interface.
You can implement the plugin algorithm by deriving it from one such interface.
You can use more than one interface in a single plugin.
Plugin chaining can be used interchangeably to denote when you are mixing more than one interface in a single plug-in.
The rest of this section might use PluginType interchangeably to denote this.
Currently, four interface types are available. More interface types will be added based on new use cases in the future.
Interface type
Header file
Section iterator plugin type
SectionIteratorPlugin.h
Chunk iterator plugin type
ChunkIteratorPlugin.h
Control memory size plugin type
ControlMemorySizePlugin.h
Control file size plugin type
ControlFileSizePlugin.h
LinkerScript changes
Linker plugins can be enabled using linker scripts. The linker script keyword uses a fixed syntax:
<PluginType>("LibraryName", "PluginName" [, "PluginOptions"])
- PluginType
Corresponds to one of the available interface types.
- LibraryName
Corresponds to the dynamic library that contains the plugin for the linker to load.
Uses the same linker semantics for linking to the linker in a library, allowing ease of use.
Uses the name of the library without the lib prefix on Linux and without the .so/.dll suffix on Linux/Windows, respectively
- PluginName
Specifies the name of the plugin. The linker queries the dynamic library to provide an implementation for the specified interface type.
- PluginOptions
Used to pass an option to the plug-in.
User Plugin Work Flow
Use the following steps to create a linker plugin.
Determine the appropriate interface(s).
Include the appropriate header file.
Create a C++ class derived from one of the interface types.
Associate the implementation of the interface to have a unique name.
Build a shared library.
Make the shared library report Plugin API version.
Write a RegisterAll function to register the plugin(s).
Write a getPlugin function to return the appropriate plugin when the linker queries with PluginName.
Linker Work Flow
All user plugins that are loaded by the linker must be initialized properly before the plugin can communicate with the linker and perform the steps.
Linker Operation
The linker performs the following sequence of operations with respect to plugins:
Parses the linker script and finds all plug-ins.
- Loads the library specified by LibraryName.
Uses LD_LIBRARY_PATH on Linux.
Uses a standard method for searching dynamic libraries in Windows.
Calls the RegisterAll() API in the library, which registers all the plug-ins that are contained in the library.
- Queries the library using the getPlugin() API with PluginName.
The library returns the appropriate object for the linker to use to run the plugin algorithm.
Inspects the plug-in to verify that the linker script keyword and the object have the same interface type.
Initializes the plug-in with any additional options provided.
Passes the appropriate content to the plug-in expressed as data structures for that PluginType.
- Runs the plug-in algorithm.
Because more than one plug-in can be used and because plug-ins can be chained, the linker unloads the library only after all user plug-ins have been called.
- Before the plug-in is unloaded, the linker calls a function to Destroy the plug-in.
This is the last step before the library is unloaded.
The linker then unloads the plug-in.
- Plugin tracing
Trace the linker work flow with the following option:
-trace=plugin
Plugin data structures
Appropriate data structures are exchanged depending on the specified plug-in interface type.
These data structures are also used to communicate with the linker and get appropriate information from the linker.
- Section
Corresponds to an input section from an ELF file.
- OutputSection
Corresponds to an OutputSection section in the LinkerScript or output ELF file.
- Chunk
Corresponds to a piece of an input section. Examples: * Individual strings of a section that contains merged strings * Contents of an output section
- Block
Corresponds to the content of the output section with corrected relocations.
- Symbol
Corresponds to an ELF symbol.
- Use
Corresponds to a relocation from a chunk or section.
- LinkerScriptRule
Corresponds to a LinkerScriptRule in an OutputSection
LinkerWrapper commands
The plug-in uses the LinkerWrapper to communicate and exchange information with the linker. Following are the LinkerWrapper commands.
- getVersion
Returns the version of the LinkerWrapper as a string. This command is useful for diagnostics.
- AllocateMemory
Allocates memory that must live for the duration of the link.
The ControlMemorySize and ControlFileSize interface types are the most common users of this functionality.
- getUses(Chunk)
Queries the linker to find out what a Chunk refers to. The API returns a vector of uses.
- getUses(Section)
Queries the linker to find out what a Section refers to. The API returns a vector of uses.
- getSymbol(SymbolName)
Gets more information from the linker for a symbol (specified by SymbolName).
- getOutputSection(Section)
Determines which OutputSection was chosen by the linker.
The OutputSection is usually chosen by the linker by matching rules in the linker script.
- setOutputSection(Section, OutputSectionName)
Places the Section into the specified OutputSection in the linker script.
This command allows linker script decisions to be overridden for that particular Section.
- MatchPattern(Pattern, Name)
Utility function that allows the plug-in to match a Glob Pattern with a string.
- setLinkerFatalError
Used by the plug-in when it discovers that there is an unhandled case when trying to link input files to produce an output image.
- resetError
Resets any error status
Note
Use the PluginADT.h file to learn about the APIs documented in the header file.
Linker plugin interface
Following is the plugin interface that the linker will use and provide implementation for the functions:
class Plugin { public: /* Initialize the plugin with options specified */ virtual void Init(std::string Options) = 0; /* The actual algorithm that will be implemented */ virtual Status Run (bool Verbose)= 0; /* Linker will call Destroy, and the client can free up any data structures that are not relevant */ virtual void Destroy()= 0; /* Returns the last error; a value of 0 means there was no error */ virtual uint32_t GetLastError()= 0; /* Returns the error as a string */ virtual std::string GetLastErrorAsString ()= 0; /* Returns the name of the plugin */ virtual std::string GetName()= 0; /* Destructor */ virtual -Plugin(){} };
Plugin interfaces
The following interfaces are available currently.
SectionIterator interface
Use the linker script keyword, PLUGIN_ITER_SECTIONS.
This interface allows you to process every input section from every object file by implementing processSection().
class SectionIteratorPlugin : public Plugin { public: /* Section that the linker will call the client with */ virtual void processSection(Section S)= 0; };
SectionMatcher interface
Use the linker script keyword, PLUGIN_SECTION_MATCHER.
This interface allows you to process every input section, and it allows the plugin to read any section.
You can use the interface to read metadata sections or read sections that were garbage collected by the linker.
SectionMatcherPlugin differs from SectionIteratorPlugin in that it allows any section content to be read before assigning output sections.
class SectionMatcherPlugin : public Plugin { public: /* Sections that the linker will call the client with */ virtual void processSection(Section S) = 0; };
ChunkIterator interface
Use the linker script keyword, PLUGIN_ITER_CHUNKS.
This interface allows you to process every input chunk in an output section using PocessChunk().
The processed chunks are returned when the linker calls getChunks().
class ChunkIteratorPlugin : public Plugin { public: /* Chunks that the linker will call the client with */ virtual void processChunk(Chunk C) = 0; virtual std::vector<Chunk> getChunks()= 0; };
ControlFileSize interface
Use the linker script keyword, PLUGIN_CONTROL FILESZ.
This interface allows you to process the output memory block contained in an output section using AddBlocks().
The processed block is returned when the linker calls GetBlocks().
An example of such a plugin is to take the memory block, compress it, and then return it to the linker.
class ControlFileSizePlugin : public Plugin { public: /* Memory blocks that the linker will call the client with */ virtual void AddBlocks(Block memBlock) = 0; /* Return memory blocks to the client */ virtual std::vector<Block> GetBlocks()= 0; };
ControlMemorySize interface
Use the linker script keyword, PLUGIN_CONTROL MEMSZ.
This interface allows you to process the output memory block contained in an output section using AddBlocks().
The processed block is returned when the linker calls GetBlocks().
class ControlMemorySizePlugin : public Plugin { public: /* Memory blocks that the linker will call the client with */ virtual void AddBlocks(Block memBlock) = 0; /* Return memory blocks to the client */ virtual std::vector<Block> GetBlocks()= 0; };
OutputSectionIterator interface
Use the linker script keyword, PLUGIN_OUTPUT_SECTION_ITER.
The interface is defined as below.
class OutputSectionIteratorPlugin : public Plugin { public: /* OutputSection that the linker will call the client with */ virtual void processOutputSection(OutputSection O)= 0; };
The interface allows the plugin to iterate over all output sections and their contents.
Contents of output sections are described by Rules.
- The OutputSectionIterator is called at various times during the linking stages:
BeforeLayout
CreatingSections
AfterLayout
The state of the linker can be queried by calling a function getState in the LinkerWrapper.
Depending on the state of the linker, the plug-in can query OutputSections and its contents appropriately.
The OutputSectionIterator interface allows the plug-in to iterate over rules specified in the OutputSection and what sections are essentially contained in a LinkerScriptRule.
Depending on the state of the Linker, the contents of the LinkerScriptRule can be modified.
Modifications of LinkerScriptRule contents include changing the OutputSection for a Section, changing the OutputSection for a Chunk
- BeforeLayout
When the state of the linker is set to BeforeLayout, the plug-in can query each rule for its contents.
The contents of the Rule can only be Sections.
Call the setOutputSection function in the LinkerWrapper to set the Section point to a different OutputSection.
Finish with all the assignments to different output sections by calling
finishAssignOutputSections in the LinkerWrapper.
- CreatingSections
When the state of the linker is set to CreatingSections, the plug-in can query each rule for its contents. The contents of the Rule can only be Chunks.
- Call APIs specified in the LinkerScriptRule to do either of the following:
addChunk – Add a Chunk to a LinkerScriptRule
removeChunk – Remove a Chunk from a LinkerScriptRule.
updateChunk – Replace Chunks in a LinkerScriptRule.
- AfterLayout
When the state of the linker is set to AfterLayout, the plugin can query for the size of the OutputSection.