1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
/******************************************************************************
* elf-reloc.c
*
* Usage: elf-reloc <old base> <new base> <image>
*
* Relocates <image> from <old base> address to <new base> address by
* frobbing the Elf headers. Segment contents are unmodified.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned long Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned long Elf32_Off;
typedef unsigned long Elf32_Word;
typedef struct {
unsigned char e_ident[16];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
#define offsetof(_f,_p) ((unsigned long)&(((_p *)0)->_f))
/* Add @reloc_distance to address at offset @off in file @fp. */
void reloc(FILE *fp, long off, unsigned long reloc_distance)
{
unsigned long base;
fseek(fp, off, SEEK_SET);
fread(&base, sizeof(base), 1, fp);
base += reloc_distance;
fseek(fp, off, SEEK_SET);
fwrite(&base, sizeof(base), 1, fp);
}
int main(int argc, char **argv)
{
unsigned long old_base, new_base, reloc_distance;
long virt_section, phys_section;
char *image_name;
FILE *fp;
Elf32_Off phoff;
Elf32_Half phnum, phentsz;
int i;
if ( argc != 4 )
{
fprintf(stderr, "Usage: elf-reloc <old base> <new base> <image>\n");
return(1);
}
old_base = strtoul(argv[1], NULL, 16);
new_base = strtoul(argv[2], NULL, 16);
image_name = argv[3];
fp = fopen(image_name, "rb+");
if ( !fp )
{
fprintf(stderr, "Failed to load image!\n");
return(1);
}
reloc_distance = new_base - old_base;
/* First frob the entry address. */
reloc(fp, offsetof(e_entry, Elf32_Ehdr), reloc_distance);
fseek(fp, offsetof(e_phoff, Elf32_Ehdr), SEEK_SET);
fread(&phoff, sizeof(phoff), 1, fp);
fseek(fp, offsetof(e_phnum, Elf32_Ehdr), SEEK_SET);
fread(&phnum, sizeof(phnum), 1, fp);
fseek(fp, offsetof(e_phentsize, Elf32_Ehdr), SEEK_SET);
fread(&phentsz, sizeof(phentsz), 1, fp);
virt_section = (long)phoff + offsetof(p_vaddr, Elf32_Phdr);
phys_section = (long)phoff + offsetof(p_paddr, Elf32_Phdr);
for ( i = 0; i < phnum; i++ )
{
reloc(fp, phys_section, reloc_distance);
reloc(fp, virt_section, reloc_distance);
phys_section += phentsz;
virt_section += phentsz;
}
fclose(fp);
return(0);
}
|