90a319bd2a04ce80d5fffa2a7950fc3fea430445
[centaur.git] / src / modelops / relocate.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <libelfu/libelfu.h>
5
6
7 /* Apply relocation information from section *msrt to data in
8  * section *mstarget (which is stored in *metarget). */
9 void elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
10 {
11   ElfuRel *rel;
12
13   assert(mstarget);
14   assert(msrt);
15
16   ELFU_DEBUG("Relocating in section of type %d size %jx\n",
17              mstarget->shdr.sh_type,
18              mstarget->shdr.sh_size);
19
20   CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) {
21     Elf32_Word *dest32 = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
22     Elf64_Word *dest64 = (Elf64_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
23
24
25     if (metarget->elfclass == ELFCLASS32) {
26       Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32;
27       Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset;
28       Elf32_Addr s32 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym);
29       switch(rel->type) {
30         case R_386_NONE:
31           ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
32           break;
33         case R_386_32:
34           *dest32 = s32 + a32;
35           break;
36         case R_386_PC32:
37           *dest32 = s32 + a32 - p32;
38           break;
39
40         default:
41           ELFU_DEBUG("Skipping relocation: Unknown type %d\n", rel->type);
42       }
43     } else if (metarget->elfclass == ELFCLASS64) {
44       /* x86-64 only uses RELA with explicit addend. */
45       assert(rel->addendUsed);
46       Elf64_Word a64 = rel->addend;
47       Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
48       Elf64_Addr s64 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym);
49
50       switch(rel->type) {
51         case R_X86_64_NONE:
52           ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
53           break;
54         case R_X86_64_64:
55           *dest64 = s64 + a64;
56           break;
57         case R_X86_64_PC32:
58           *dest32 = s64 + a64 - p64;
59           break;
60         case R_X86_64_32:
61           *dest32 = s64 + a64;
62           break;
63
64         default:
65           ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
66       }
67     }
68   }
69 }