普通目标文件
正如注释所说,-R
仅对动态对象有意义。对于.o
来自简单程序的普通文件,-r
将显示重定位条目。例如,这个简单的程序:
#include <stdio.h>
int main() {
puts("Hello, world!\");
}
我们可以用这个生成一个目标文件:
cc -Wall -Wextra -pedantic -std=c11 -c -o sample.o sample.c
当我们运行命令时产生这个输出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
(这是一个 x86_64 Linux 机器。)
随着objdump -R sample.o
我们得到这样的:
objdump: sample.o: not a dynamic object
objdump: sample.o: Invalid operation
这是意料之中的,因为这不是共享库。
共享库
相比之下,我们可以使用以下代码:
#include <stdio.h>
int hello() {
return puts("Hello, world!\n");
}
并用这个创建一个库:
gcc -Wall -Wextra -pedantic -std=c11 -fPIC -shared -o libsample.so sample.c
现在-R
是有道理的:
objdump -R libsample.so
输出:
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
玩游戏
还有其他两个工具:readelf
和elfedit
,让我们来看看和修改二进制的更多细节。如果我们创建一个如上图所示的共享对象,但是在 32 位 Linux 机器上然后运行readelf -a libsample.so
输出很长,但从这个开始:
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
然后我们可以玩游戏,例如将文件更改为 EXEC 类型而不是 DYN 类型:
elfedit --output-type=EXEC test.so
现在,如果我们重新运行readelf
,除了那个标签之外,一切都是一样的:
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
尽管类型已更改,但它仍将用作共享库。