aboutsummaryrefslogtreecommitdiffstats
path: root/xen/tools/elf-reloc.c
blob: e2a5860e272fbacaf6471c192e9e0d514a575c96 (plain)
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);
}