elfdiff - compare twoELFfiles
elfdiff [-DeRuV] [-c | -h] [-i section[=class],...] [-r checksum-signature-range] [-s section,...] file1 file2
The elfdiff utility analyzes two ELF files and reports the significant differences between them. This utility is targeted at diagnosing the underlying changes that occur within an ELF file through a series of development updates.
ELF files contain a variety of data structures and associated information, with the most basic building block being a section. Although many types of ELF section exist, sections fall into two main categories.
Sections that contain program data, whose interpretation is meaningful only to the application. These sections include the program .text instructions and the associated data sections such as .rodata and .data.
Sections that contain link-editing information, such as the symbol table information found in the .symtab and .strtab sections, and relocation information such as the .rela.text section.
Software changes typically consist of the addition, deletion or change to program data. These changes can manifest themselves as changes to the link-editing information, such as the symbols that are made available from the ELF file. However, these changes can also propagate though many sections within the ELF file, resulting in different section sizes and offsets. The simple addition of a new function definition or data item can ripple through the ELF file and result in many differences. Trying to extrapolate the underlying cause of a difference between two ELF files, amongst all the differences that exist, can be overwhelming.
The elfdiff utility analyzes a file in a number of phases, constraining the data in an attempt to present the highlights of what differences exist, and reduce diagnostic noise. The following phases of analysis occur.
ELF Class Verification
Checksum Verification
ELF Header Analysis
Symbol Table Analysis
Section Analysis
Program Header Analysis
See USAGE for details.
In general, elfdiff without any arguments should be sufficient to diagnose the basic differences between two ELF files.
In some build environments, one or two sections might always change from build to build. For example, a .comment section might change because of an embedded date stamp. Sections like these can be ignored with the –i option.
Some section differences can provoke an interest in diagnosing the section in more detail. Sections like these can be isolated for analysis with the –s option.
The –u option can be used to capture all differences, either for the entire file, or for specific sections defined using the –s option. Use of the –u option is well suited for collecting all differences in a file for further processing.
The following options are supported.
Provides more detailed information regarding the range of data processed within each file to determine the associated checksum. This option can be useful to analyze signature generation, but is generally unnecessary for normal elfdiff use.
Produce and compare a SHA256 checksum for each file, with no further analysis of the files.
Print a summary of the command line options on the standard output and exit.
Apply heuristics in an attempt to elide differences due to offsets or addresses. For example, should a section differ in size between the two files, all sections that follow will differ in their offset and address. The –e option suppresses diagnosing such differences.
Ignore diagnosing any differences of the class of information for the named section. Without a specified class, any diagnosis of differences related to the named section are ignored. Specifying a class allows refinement of the differences to ignore.
Ignore diagnosing any differences related to the data of the named section.
Ignore diagnosing any differences related to the section header of the named section.
Although the –i option suppresses diagnosing the differences between two sections, the option does not suppress the diagnosis of a section that only exists in one file.
Define the checksum range. The range tokens are a representation of the ELF_SR_* types defined by elf32_sign_range(3ELF). The following range tokens are supported.
As used by elf32_checksum(3ELF).
The whole file. This is the default.
Select the range based on the file type.
Treat the file as a relocatable object.
Select the range based on the file type, with the addition of any signature section.
This option provides a means of exercising the available signature range permutations, but is generally unnecessary for normal elfdiff use.
Diagnose section data differences as raw data. This option can be useful to uncover difference details that might not be evident from formatted differences. See LIMITATIONS.
Diagnose differences only for the named section.
By default, elfdiff limits the number of differences that are diagnosed during symbol table analysis and section data analysis. The –u option disables any limitation.
Print version information and immediately exit.
Print usage message and immediately exit.
Each analysis phase is introduced with a title preceded with the string '***', and separated from previous differences with a blank line.
Differences for sections containing program instructions are shown in a display format similar to the dis(1) utility. Differences for sections containing program data are shown in a display format similar to the od(1) utility. Differences for ELF constructs are shown in the display format similar to the elfdump(1) utility.
Differences for file1 are prefixed with a '<' character, and differences for file2 are prefixed with '>', in the style similar to that used by the diff(1) utility.
If the section data difference can be associated with a symbol, the symbol name is displayed first, followed by the data difference. The data difference is prefixed with the offset within the section of the start of the difference, the symbol, denoted by the token '<sym>', and the offset within the symbol of the start of the difference.
Diagnostics that can be associated to the same symbol for both sections are introduced with the symbol name.
--- <sym>: func(): < 0x288:<sym>+0x10: ... > 0x288:<sym>+0x10: ...
Diagnostics that are associated to different symbols identify each symbol.
< <sym>: data1 < 0x1024:<sym>+0x40: ... > <sym>: data2 > 0x1024:<sym>+0x40: ...
Multiple diagnostics within the same section are separated with the string '---'.
The following descriptions outline each phase of elfdiff analysis, with examples of the diagnostics that can be produced by each phase.
The ELF header resides at the beginning of the file and describes the file's organization, and defines the machine type and class of the file. elfdiff first determines that the two files have the same class. Incompatible classes result in an error diagnostic and termination of any further analysis.
$ elfdiff null.amd64.o null.i386.o *** ehdr: information differs < ei_class: ELFCLASS64 ei_data: ELFDATA2LSB > ei_class: ELFCLASS32 ei_data: ELFDATA2LSB ehdr: incompatible ELF classes, no further analysis is possible
Following class verification, a SHA256 checksum is calculated for each file. If the checksums are equal no further analysis is required. The range of data processed to obtain a checksum follows the model of elf32_sign_range(3ELF), and can be controlled by the –r option. The default behavior is to checksum the whole file.
If checksum verification indicates that the two files differ, a more complete comparison of the ELF header entries is carried out, and any difference diagnosed.
$ elfdiff null.i386 null.sparc *** ehdr: information differs < ei_class: ELFCLASS32 ei_data: ELFDATA2LSB > ei_class: ELFCLASS32 ei_data: ELFDATA2MSB --- < e_machine: EM_386 e_version: EV_CURRENT > e_machine: EM_SPARC32PLUS e_version: EV_CURRENT --- < e_flags: 0 > e_flags: [ EF_SPARC_32PLUS ]
If the –e option is in affect, the entries e_entry, e_shstrndx, e_shoff, and e_shnum are omitted from this analysis. These entries can differ based on section number or offset differences, and can be better diagnosed in later phases.
For more information regarding the ELF header elements see ELF Header in Oracle Solaris 11.4 Linkers and Libraries Guide.
Most program data is associated with symbols. Following ELF header analysis, elfdiff analyzes as much symbol table information as is available in the files, and diagnoses any differences. This phase of analysis often conveys sufficient data to inform you of the most important differences between two files.
Symbol table entries are sorted, and displayed in ascending section-index/value order. This ordering matches the layout of the sections within an ELF file. Symbols with no section-index or value, are typically less significant, and are ordered last.
$ elfdiff null.1 null.2 *** symbols: differ < [59] 0x80508a8 0x7 OBJT GLOB D 0 .rodata name > [58] 0x80508a8 0x9 OBJT GLOB D 0 .rodata name --- > [60] 0x8050b10 0xd FUNC GLOB D 0 .text two --- < [56] 0x8050b10 0x2a FUNC GLOB D 0 .text main > [55] 0x8050b20 0x24 FUNC GLOB D 0 .text main --- < [47] 0x8060d48 0x4 OBJT GLOB D 0 .data one < [1] 0 0 FILE LOCL D 0 ABS null.1 --- > [1] 0 0 FILE LOCL D 0 ABS null.2
For more information regarding symbol table entries see Symbol Table Section in Oracle Solaris 11.4 Linkers and Libraries Guide.
Following symbol table analysis, elfdiff analyzes the sections of each file, first diagnosing any section header information, followed by any section data differences.
Section headers are first analyzed to determine those that are common to both files, and those that are unique. Common sections that are found to differ, and sections that are unique, are diagnosed.
Common sections that differ are identified with the section name, and the section index, together with the differences found between each section header.
$ elfdiff null.1 null.2 ... *** section: [12].text: shdr information differs < sh_size: 0x215 sh_type: [ SHT_PROGBITS ] > sh_size: 0x21f sh_type: [ SHT_PROGBITS ]
If two common sections have different section indexes, then both indexes are displayed, separated with a "<>" token to indicate the association to each file.
$ elfdiff null.1 null.2 ... *** section: [15 <> 16].data: shdr information differs < sh_size: 0x412 sh_type: [ SHT_PROGBITS ] > sh_size: 0x460 sh_type: [ SHT_PROGBITS ]
Sections that are unique are identified with the section name, and the section index, together with all the section header information.
$ elfdiff null.1 null.2 ... *** section: [21].comment: shdr is unique to one file < sh_addr: 0 sh_flags: 0 < sh_size: 0xb1 sh_type: [ SHT_PROGBITS ] < sh_offset: 0x1322 sh_entsize: 0 < sh_link: 0 sh_info: 0 < sh_addralign: 0x1
Following each section header diagnostic are any differences in section data. If any symbol table entries for the section were collected during symbol table analysis, the differences for the symbols associated with this section are displayed. Each symbol that was diagnosed as part of symbol table analysis, has its data difference displayed. If no symbol from this section was diagnosed as part of symbol table analysis, only the first symbol collected during this analysis is diagnosed. If no symbol table entries have been diagnosed for this section, then the first difference in the section data is diagnosed.
$ elfdiff null.1 null.2 ... *** section: [12].text: shdr information differs ... *** section: [12].text: data information differs --- <sym>: _start() < 0xd:<sym>+0xd: 81 c3 44 02 01 00 addl $0x10244,%ebx > 0xd:<sym>+0xd: 81 c3 4c 02 01 00 addl $0x1024c,%ebx ... *** section: [13].rodata: data information differs --- <sym>: title_string < 0x0:<sym>: T i t l e _ O l d : \0 > 0x0:<sym>: T i t l e _ N e w : \0
Section data differences that can not be associated with a symbol name are diagnosed prefixed by the offset in the section of the difference.
$ elfdiff null.1 null.2 ... *** section: [20].strtab: data information differs < 0x20: \0 n u l l . 1 \0 > 0x20: \0 n u l l . 2 \0
Note, if the –e option is in affect, and individual symbol entries were diagnosed during the symbol table analysis phase, no further diagnosis of any symbol table section is carried out. However, any string table sections that might provide symbol table entry names are processed. These string tables can often contain addition strings besides symbol table entry names.
For more information regarding the section header entries see Section Headers in Oracle Solaris 11.4 Linkers and Libraries Guide.
Following section analysis, elfdiff analyses the program headers to determine those that are common to both files, and those that are unique. Common program headers that are found to differ, and program headers that are unique are displayed.
Many program headers encapsulate ranges of sections, and thus their data would have already been more fully described by the preceding section analysis phase.
Common program headers that differ are identified with the header index, the header type, and then the differences found between each program header.
$ elfdiff null.1 null.2 ... *** phdr: [3]: PT_LOAD: phdr information differs < p_filesz: 0xb6f p_memsz: 0xb6f > p_filesz: 0xb77 p_memsz: 0xb77
Program headers that are unique are identified with the header index, the header type, and then all the program header information.
$ elfdiff null.1 null.2 ... *** phdr: [5]: SUNW_UNWIND is unique to one file > p_vaddr: 0x4001a8 p_flags: [ PF_R ] > p_paddr: 0 p_type: [ PT_SUNW_UNWIND ] > p_filesz: 0x1c p_memsz: 0x1c > p_offset: 0x1a8 p_align: 0x8
For more information regarding the program header entries see Program Header in Oracle Solaris 11.4 Linkers and Libraries Guide.
elfdiff is not a panacea for discovering fine grained differences between two files. The goal of elfdiff is to identify the differences between two files that could be caused by software changes you control. At the same time, diagnosing changes to the ELF data that has changed as a result of your software changes, is kept to a minimum.
Any ELF section that differs between the two files results in a diagnostic to indicate that differences exist. However, the differences can be subtle. Entries within many ELF sections define offsets within other ELF sections. The difference between two sections may be that only the offset references differ. It could be argued that nothing substantial had changed between the two sections, however elfdiff diagnoses the first difference between the sections to indicate that differences exist.
Further complications can occur for differences that follow the format of elfdump(1) output. elfdump can embellish raw data, such as symbolically representing symbol and section names. In addition, alignment constraints for ELF data structures can require the presence of holes or padding, which is not evident from an elfdiff style of display. Should conditions like these exist, elfdiff style diagnostics for the data can look identical. The –R option can be used to suppress any attempt to provide formatted differences, and instead present the raw data.
If you want more fine grained detail of the differences between two ELF files, use elfdiff as a starting point. Further analysis can be carried out with tools like dis(1), elfdump(1), and od(1).
The following exit values are returned.
No differences were found between the files.
Differences were found between the files.
An error occurred.
Note, if the –s option is used to explicitly define a section to analyze, and no differences are diagnosed, elfdump will still return 1 if the two files differ in any other manner.
The following provides an example of comparing two versions of a shared object.
$ elfdiff -e foo.so.1 foo.so.2 *** symbols: differ < [9287] 0x935c0 0x1bd FUNC GLOB D 0 .text device_offline > [9287] 0x935c0 0x1f5 FUNC GLOB D 0 .text device_offline --- < [10233] 0x111240 0x20 FUNC GLOB D 0 .text new_device_A < [10010] 0x111260 0x64 FUNC GLOB D 0 .text new_device_B --- > [15317] 0 0 NOTY GLOB D 0 UNDEF __assfailline__13 *** section: [1].SUNW_cap: shdr information differs < sh_size: 0xe0 sh_type: [ SHT_SUNW_cap ] > sh_size: 0x120 sh_type: [ SHT_SUNW_cap ] *** section: [1].SUNW_cap: data information differs < 0x80: [8] CA_SUNW_ID 0x2317 i86pc-clmul > 0x80: [8] CA_SUNW_ID 0x1f59 i86pc-avx2 *** section: [6].text: shdr information differs < sh_size: 0x38e205 sh_type: [ SHT_PROGBITS ] > sh_size: 0x38e245 sh_type: [ SHT_PROGBITS ] *** section: [6].text: data information differs --- <sym>: device_offline() < 0x935d9:<sym>+0x19: 48 8b df movq %rdi,%rbx > 0x935d9:<sym>+0x19: 4c 8b e7 movq %rdi,%r12 --- < <sym>: new_device_A < 0x111240:<sym>: 55 push %rbp --- < <sym>: new_device_B < 0x111260:<sym>: 55 push %rbp *** section: [9].strtab: shdr information differs < sh_size: 0x642c5 sh_type: [ SHT_STRTAB ] > sh_size: 0x642d9 sh_type: [ SHT_STRTAB ] *** section: [9].strtab: data information differs < 0x42297: n e _ _ 1 3 8 5 \0 _ _ ... > 0x42297: n e _ _ 1 3 8 4 \0 _ _ ... *** section: [13].rela.text: shdr information differs < sh_size: 0x36d398 sh_type: [ SHT_RELA ] > sh_size: 0x36d428 sh_type: [ SHT_RELA ] *** section: [13].rela.text: data information differs < 0x0: [0] R_AMD64_32S 0x1635f4 0x1638b4 .text > 0x0: [0] R_AMD64_32S 0x163634 0x1638f4 .text *** section: [33].SUNW_ctf: shdr information differs < sh_size: 0xb33c sh_type: [ SHT_PROGBITS ] > sh_size: 0xb4e4 sh_type: [ SHT_PROGBITS ] *** section: [33].SUNW_ctf: data information differs < 0xd: \0 \0 \0 \08 \0 \0 \0 \b2 \03 \0 \0 D ... > 0xd: \0 \0 \0 \08 \0 \0 \0 \ba \03 \0 \0 $ ... *** section: [34].SUNW_signature: data information differs < 0x73: j o h n d o e \t \93 \ab \ff \fa ... > 0x73: j o h n d o e \c2 \c5 \98 r a ...Example 2 Suppressing Section Differences
In the previous example, the .SUNW_ctf section is known to change size and content from one build to another, and the .SUNW_signature section is known to change content from one build to another. These two diagnostics can be suppressed using the –i option, while ensuring that the addition or deletion of either of these sections remains diagnosed.
$ elfdiff -e -i.SUNW_signature=data,.SUNW_ctf foo.so.1 foo.so.2Example 3 Inspecting a Specific Section
In the previous example, the difference in the .SUNW_cap section is of interest, and the full extent of the differences of that section can be analyzed with the –s option.
$ elfdiff -e -u -s.SUNW_cap foo.so.1 foo.so.2 *** section: [1].SUNW_cap: shdr information differs < sh_size: 0xe0 sh_type: [ SHT_SUNW_cap ] > sh_size: 0x120 sh_type: [ SHT_SUNW_cap ] *** section: [1].SUNW_cap: data information differs < 0x80: [8] CA_SUNW_ID 0x2317 i86pc-clmul > 0x80: [8] CA_SUNW_ID 0x1f59 i86pc-avx2 --- < 0x90: [9] CA_SUNW_HW_1 0x8001000 [ PCLMULQDQ SSE2 ] > 0x90: [9] CA_SUNW_HW_2 0x40 [ AVX2 ] --- < 0xa0: [10] CA_SUNW_NULL 0 [ 0x0 ] > 0xa0: [10] CA_SUNW_HW_1 0x20401000 [ AVX SSSE3 SSE2 ] --- < 0xb0: [11] CA_SUNW_ID 0x24e5 i86pc-ssse3 > 0xb0: [11] CA_SUNW_NULL 0 [ 0x0 ] --- < 0xc0: [12] CA_SUNW_HW_1 0x401000 [ SSSE3 SSE2 ] > 0xc0: [12] CA_SUNW_ID 0x24f7 i86pc-clmul --- < 0xd0: [13] CA_SUNW_NULL 0 [ 0x0 ] > 0xd0: [13] CA_SUNW_HW_1 0x8001000 [ PCLMULQDQ SSE2 ] --- > 0xe0: [14] CA_SUNW_NULL 0 [ 0x0 ] > 0xf0: [15] CA_SUNW_ID 0x26c5 i86pc-ssse3 > 0x100: [16] CA_SUNW_HW_1 0x401000 [ SSSE3 SSE2 ] > 0x110: [17] CA_SUNW_NULL 0 [ 0x0 ]
See attributes(7) for descriptions of the following attributes:
|
The human readable output is Uncommitted. The options are Committed.
diff(1), dis(1), elfdump(1), od(1), elf(3ELF), elf32_checksum(3ELF), elf64_checksum(3ELF), elf32_sign_range(3ELF), elf64_sign_range(3ELF), attributes(7)