E25 Relocation Entries

Relocation is the process by which undefined symbols in ELF files are associated with valid values. In the standard example (test.o), this means that undefined references to printf and add must be replaced with the addresses at which the appropriate machine code is located in the virtual address space of the process. Replacement must be performed at all points in the object file where one of the symbols is used.

The kernel is not involved in symbol replacement in userspace programs because all replacement operations are carried out fully by external tools. The situation is different for kernel modules, as demonstrated in Chapter 7. Because the kernel receives the raw data of a module in the exact same form as it is stored in the binary file, the kernel itself is responsible for relocation.

A special table with relocation entries is present in each object file to identify where relocation must be performed. Each table entry holds the following information:

□ An offset that specifies the position of the entry to be modified.

□ A reference to the symbol (as an index into a symbol table) that supplies the data to be inserted in relocation positions.

To illustrate how relocation information is used, let's revisit the test.c test program described previously. First, all relocation entries in the file are displayed using readelf as follows:

[email protected]> readelf -r Relocation section '.rel.text

Offset Info Type

00000009 00000501 R_386_32

0000000e 00000802 R_386_PC32

00000046 00000702 R_386_PC32

00000050 00000501 R_386_32

00000055 00000802 R_386_PC32

00000061 00000a02 R 386 PC32

test.o at offset 0x374 contains 6 entries: Sym.Value Sym. Name .rodata

00000000 00000000 00000000 00000000 00000000 00000000

printf add

.rodata printf exit

The information in the Offset column is used when the machine code references functions or symbols whose position in virtual address space is not clear when the program is run or when test.o is linked to produce an executable file. The assembly language code of main has a number of function calls at the offsets 0x46 (add), 0xe and 0x55 (printf), and 0x61 (exit) — these can be rendered visible using the objdump tool. The relevant lines are shown in italics in the following output:

[email protected]> objdump — disassemble test.o 0000001a <main>:

1a

55

push

%ebp

1b

89

e5

mov

%esp,%ebp

1d

83

ec

18

sub

$0x18,%esp

20

83

e4

f0

and

$0xfffffff0,%esp

23

b8

00

00

00

00

mov

$0x0,%eax

28

29

c4

sub

%eax,%esp

2a

c7

45

fc

03

00

00

00

movl

$0x3,0xfffffffc(%ebp)

31:

c7

45

f8

04

00

00

00

movl

$0x4,0xfffffff8(%ebp)

38

b 8

45

f8

mov

0xfffffff8(%ebp),%eax

3b:

89

44

24

04

mov

%eax,0x4(%esp,1)

3f:

b 8

5 4

fc

mov

0xfffffffc(%ebp),%eax

42

89

04

24

mov

%eax,(%esp,1)

45

e8

fc

ff

ff

ff

call

4 6 <main+0x2c>

4a

89

45

f4

mov

%eax,0xfffffff4(%ebp)

4d

c7

04

24

17

00

00

00

movl

$0x17,(%esp,1)

54

e8

fc

ff

ff

ff

call

55 <main+0x3b>

59

c7

04

24

00

00

00

00

movl

$0x0,(%esp,1)

60

e8

fc

ff

ff

ff

call

61 <main+0x47>

Once the addresses of the printf and add functions have been determined, they must be inserted at the specified offsets in order to generate executable code that runs correctly.

Continue reading here: Data Structures

Was this article helpful?

0 0