7f78524acf962b9af6ce1736376fde770bdbe7dd
[centaur.git] / src / libelfu / 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 int elfu_mRelocate(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
10 {
11   ElfuRel *rel;
12   ElfuSym *sym;
13
14   assert(mstarget);
15   assert(msrt);
16
17   ELFU_DEBUG("Relocating in section of type %u size %x\n",
18              mstarget->shdr.sh_type,
19              (unsigned)mstarget->shdr.sh_size);
20
21   CIRCLEQ_FOREACH(rel, &msrt->reltab.rels, elem) {
22     Elf32_Word *dest32 = (Elf32_Word*)(mstarget->databuf + rel->offset);
23     Elf64_Word *dest64 = (Elf64_Word*)(mstarget->databuf + rel->offset);
24     GElf_Addr s;
25     int haveSymval = 0;
26
27     sym = elfu_mSymtabIndexToSym(msrt->linkptr, rel->sym);
28     assert(sym);
29
30     haveSymval = !elfu_mSymtabLookupSymToAddr(metarget,
31                                               msrt->linkptr,
32                                               sym,
33                                               &s);
34     if (!haveSymval) {
35       if (sym->shndx == SHN_UNDEF) {
36         haveSymval = !elfu_mDynLookupPltAddrByName(metarget,
37                                      elfu_mSymtabSymToName(msrt->linkptr, sym),
38                                      &s);
39       } else if (sym->shndx == SHN_COMMON) {
40         // TODO: Lookup in .rel.dyn
41       }
42     }
43
44     if (metarget->elfclass == ELFCLASS32) {
45       Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32;
46       Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset;
47       Elf32_Addr s32 = (Elf32_Addr)s;
48
49       switch(metarget->ehdr.e_machine) {
50         case EM_386:
51           switch(rel->type) {
52             case R_386_NONE:
53               ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
54               break;
55             case R_386_32:
56               if (!haveSymval) {
57                 goto MISSINGSYM;
58               }
59               *dest32 = s32 + a32;
60               break;
61             case R_386_PC32:
62               if (!haveSymval) {
63                 goto MISSINGSYM;
64               }
65               *dest32 = s32 + a32 - p32;
66               break;
67             default:
68               ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d\n", rel->type);
69           }
70           break;
71         default:
72           ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n");
73       }
74     } else if (metarget->elfclass == ELFCLASS64) {
75       Elf64_Word a64 = rel->addendUsed ? rel->addend : *dest64;
76       Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
77       Elf64_Addr s64 = (Elf64_Addr)s;
78
79       switch(metarget->ehdr.e_machine) {
80         case EM_X86_64:
81           switch(rel->type) {
82             case R_X86_64_NONE:
83               ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
84               break;
85             case R_X86_64_64:
86               if (!haveSymval) {
87                 goto MISSINGSYM;
88               }
89               *dest64 = s64 + a64;
90               break;
91             case R_X86_64_PC32:
92               if (!haveSymval) {
93                 goto MISSINGSYM;
94               }
95               *dest32 = s64 + a64 - p64;
96               break;
97             case R_X86_64_32:
98               if (!haveSymval) {
99                 goto MISSINGSYM;
100               }
101               *dest32 = s64 + a64;
102               break;
103             default:
104               ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d", rel->type);
105           }
106           break;
107         default:
108           ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n");
109       }
110     }
111   }
112
113   return 0;
114
115   MISSINGSYM:
116   ELFU_WARN("elfu_mRelocate: Could not resolve symbol %s. Aborting.\n",
117             elfu_mSymtabSymToName(msrt->linkptr, sym));
118   return -1;
119
120 }