Ordinary object file
As the notes say, the -R
is only meaningful for dynamic objects. For ordinary .o
files from simple programs, the -r
will show the relocation entries. As an example, this simple program:
#include <stdio.h>
int main() {
puts("Hello, world!\");
}
We can produce an object file with this:
cc -Wall -Wextra -pedantic -std=c11 -c -o sample.o sample.c
Produces this output when we run the command objdump -r sample.o
:
sample.o: file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000005 R_X86_64_32 .rodata
000000000000000a R_X86_64_PC32 puts-0x0000000000000004
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
0000000000000020 R_X86_64_PC32 .text
(This is an x86_64 Linux box.)
With objdump -R sample.o
we get this:
objdump: sample.o: not a dynamic object
objdump: sample.o: Invalid operation
This is expected since this is not a shared library.
Shared library
By contrast, we can use this code:
#include <stdio.h>
int hello() {
return puts("Hello, world!\n");
}
And create a library with this:
gcc -Wall -Wextra -pedantic -std=c11 -fPIC -shared -o libsample.so sample.c
Now the -R
makes sense:
objdump -R libsample.so
Output:
libsample.so: file format elf64-x86-64
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
0000000000200df8 R_X86_64_RELATIVE *ABS*+0x0000000000000660
0000000000200e00 R_X86_64_RELATIVE *ABS*+0x0000000000000620
0000000000200e10 R_X86_64_RELATIVE *ABS*+0x0000000000200e10
0000000000200fd8 R_X86_64_GLOB_DAT _ITM_deregisterTMCloneTable
0000000000200fe0 R_X86_64_GLOB_DAT __gmon_start__
0000000000200fe8 R_X86_64_GLOB_DAT _Jv_RegisterClasses
0000000000200ff0 R_X86_64_GLOB_DAT _ITM_registerTMCloneTable
0000000000200ff8 R_X86_64_GLOB_DAT __cxa_finalize@GLIBC_2.2.5
0000000000201018 R_X86_64_JUMP_SLOT puts@GLIBC_2.2.5
Playing games
There are two other utilities: readelf
and elfedit
that allows us to look at and modify the binary in more detail. If we create a shared object as shown above, but on a 32-bit Linux machine and then run readelf -a libsample.so
the output is long, but starts with this:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x3f0
Start of program headers: 52 (bytes into file)
Start of section headers: 5884 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 29
Section header string table index: 26
We can then play games such as changing the file to a EXEC type instead of a DYN type:
elfedit --output-type=EXEC test.so
Now if we rerun readelf
, everything is the same except for that tag:
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x3f0
Start of program headers: 52 (bytes into file)
Start of section headers: 5884 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 29
Section header string table index: 26
Although the type has changed, it will still function as a shared library.