elfedit [-adr] [-e cmd] [-L path] [-o default | simple | num] [infile] [outfile]
elfedit functionality is organized in the form of modules. Each module delivers a set of commands, focused on related functionality. A command is specified by combining the module and command names with a colon (:) delimiter, with no intervening white space. For example, dyn:runpath refers to the runpath command provided by the dyn module. Module names must be unique. The command names within a given module are unique within that module, but the same command names can be used in more than one module.
Some modules designate one of their commands to be the default command for that module. This command is run when the user specifies only a module name. Most elfedit modules supply a command named dump, which produces the same information displayed by the elfdump utility for the part of the ELF file covered by the module. It is common for a module to specify dump as its default command.
The syntax used to execute an elfedit command is intended to be familiar to anyone who uses UNIX command line utilities. It consists of white space delimited tokens. The first token is the command name. Options, which are arguments that start with the hyphen (-) character follow the command. Plain arguments (operands) follow the options. There can be 0 or more options and operands for a given command, but if they are present, options always precede plain arguments. The special option, --, (two hyphens) can be used to delimit the end of the options. When it is encountered, any remaining arguments are considered to be plain arguments even if they start with a -.
The interpretation of the characters in an elfedit token depends on the style of quoting used:
Any other character following a backslash is an error.
The core commands belong to an internal module named sys. All other modules are packaged as dynamically loadable sharable objects. elfedit loads modules on demand, when a command that requires it is executed, or as the result of executing the sys:load command. Due to its special built in status, and because its commands are used heavily, elfedit allows you to specify commands from the sys module without including the sys: prefix, for example, load rather than sys:load. To access a command from any other module, you must specify the full module:cmd form.
elfedit is delivered with the following standard modules:
The status (sys:status) command displays information about the current elfedit session:
Included with every elfedit module is extensive online documentation for every command, in a format similar to UNIX manual pages. The help (sys:help) command is used to display this information. To learn more about elfedit, start elfedit and use the help command without arguments:
% elfedit > help
elfedit displays a welcome message with more information about elfedit, and on how to use the help system.
To obtain summary information for a module:
> help module
To obtain the full documentation for a specific command provided by a module:
> help module:command
Using the dyn module and dyn:runpath commands as examples:
> help dyn > help dyn:runpath
help (sys:help) can be used to obtain help on itself:
> help help
The default module search path for elfedit is:
Expanding the tokens, this is:
The default search path can be changed by setting the ELFEDIT_PATH environment variable, or by using the -L command line option. If you specify both, the -L option supersedes the environment variable.
> set a off
-o default | simple | num
This can be an executable (ET_EXEC), shared object (ET_DYN), or relocatable object file, (ET_REL). Archives are not directly supported. To edit an object in an archive, you must extract the object, edit the copy, and then insert it back into the archive.
If no infile is present, elfedit runs in a limited mode that only allows executing commands from the sys: module. This mode is primarily to allow access to the command documentation available from the help (sys:help) command.
If infile is present, and no outfile is given, elfedit edits the file in place, and writes the results into the same file, causing the original file contents to be overwritten. It is usually recommended that elfedit not be used in this mode, and that an output file be specified. Once the resulting file has been tested and validated, it can be moved into the place of the original file.
The -r option can be used to open infile for read-only access. This can be useful for examining an existing file that you do not wish to modify.
At startup, elfedit uses libelf to open the input file and cache a copy of its contents in memory for editing. It can then execute one or more commands. A session finishes by optionally writing the modified object to the output file, and then exiting.
If no infile is present, elfedit runs in a limited mode that only allows executing commands from the sys module. This mode is primarily to allow access to the command documentation available from the help (sys:help) command.
If one or more -e options are specified, the commands they supply are executed in the order given. elfedit adds implicit calls to write (sys:write) and quit (sys:quit) immediately following the given commands, causing the output file to be written and the elfedit process to exit. This form of use is convenient in shell scripts and makefiles.
If no -e options are specified, elfedit reads commands from stdin and executes them in the order given. The caller must explicitly issue the write (sys:write) and quit (sys:quit) commands to save their work and exit when running in this mode.
Example 1 Changing the Runpath of an Executable
The following example presupposes an executable named prog, installed in a bin directory that has an adjacent lib directory for sharable objects. The following command sets the runpath of that executable to the lib directory:
elfedit -e 'dyn:runpath $ORIGIN/../lib'
The use of single quotes with the argument to the -e option is necessary to ensure that the shell passes the entire command as a single argument to elfedit.
Alternatively, the same operation can be done using elfedit in its non-batch mode:
% elfedit prog > dyn:runpath $ORIGIN/../lib index tag value  RUNPATH 0x3e6 $ORIGIN/../lib > write > quit
The addition or modification of elements such as runpath or needed entries might only be achievable when padding exists within the objects. See Notes.
Example 2 Removing a Hardware Capability Bit
Objects that require optional hardware support to run are built with a capability section that contains a mask of bits specifying which capabilities they need. The runtime linker (ld.so.1) checks this mask against the attributes of the running system to determine whether a given object is able to be run by the current system. Programs that require abilities not available on the system are prevented from running.
This check prevents a naive program that does not explicitly check for the hardware support it requires from crashing in a confusing manner. However, it can be inconvenient for a program that is written to explicitly check the system capabilities at runtime. Such a program might have optimized code to use when the hardware supports it while providing a generic fallback version that can be run, albeit more slowly, otherwise. In this case, the hardware compatibility mask prevents such a program from running on the older hardware. In such a case, removing the relevant bit from the mask allows the program to run.
The following example removes the AV_386_SSE3 hardware capability from an x86 binary that uses the SSE3 CPU extension. This transfers responsibility for validating the ability to use SSE3 from the runtime linker to the program itself:
elfedit -e 'cap:hw1 -and -cmp sse3' prog
Example 3 Reading Information From an Object
elfedit can be used to extract specific targeted information from an object. The following shell command reads the number of section headers contained in the file /usr/bin/ls:
% SHNUM=`elfedit -r -onum -e 'ehdr:e_shnum' /usr/bin/ls` % echo $SHNUM 29
You might get a different value, depending on the version of Solaris and type of machine that you are using. The -r option causes the file to be opened read-only, allowing a user with ordinary access permissions to open the file, and protecting against accidental damage to an important system executable. The num output style is used in order to obtain only the desired value, without any extraneous text.
Similarly, the following extracts the symbol type of the symbol unlink from the C runtime library:
% TYPE=`elfedit -r -osimple -e 'sym:st_type unlink' /lib/libc.so` % echo $TYPE STT_FUNC
|ATTRIBUTE TYPE||ATTRIBUTE VALUE|
Linker and Libraries Guide
elfedit allows the user to alter the ELF metadata in an object, but cannot understand or alter the code of the actual program. Setting ELF attributes such as types, sizes, alignments, and so forth in a manner that does not agree with the actual contents of the file is therefore likely to yield a broken and unusable output object. Such changes might be useful for testing of linker components, but should be avoided otherwise.
Higher level operations, such as the use of the dyn:runpath command to change the runpath of an object, are safe, and can be carried out without the sort of risk detailed in this section.
One area of particular interest is that elfedit might not be able to modify the runpath of a given object. To modify a runpath, the following must be true:
% elfedit -r -e 'dyn:tag DT_SUNW_STRPAD' file
% elfedit -r -e 'dyn:runpath' file
A dynamic section uses an element of type DT_NULL to terminate the array found in that section. The final DT_NULL cannot be changed, but if there are more than one of these, elfedit can convert one of them into a runpath element. To test for extra dynamic slots:
% elfedit -r -e 'dyn:tag DT_NULL' file
Older objects do not have the extra space necessary to complete such operations. The space necessary to do so was introduced in the Solaris Express Community Edition release.
When an operation fails, the detailed information printed using the -d (debug) option can be very helpful in uncovering the reason why.
elfedit modules follow a convention by which commands that directly manipulate a field in an ELF structure have the same name as the field, while commands that implement higher level concepts do not. For instance, the command to manipulate the e_flags field in the ELF header is named ehdr:e_flags. Therefore, you generally find the command to modify ELF fields by identifying the module and looking for a command with the name of the field.
|May 17, 2020|