1b4f9ffdb4f710fa0e5675e4362d8ecb644f5e2e
[centaur.git] / src / model / relocate.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <libelfu/libelfu.h>
4
5
6 static GElf_Word symtabLookupVal(ElfuElf *metarget, ElfuScn *msst, GElf_Word entry)
7 {
8   GElf_Word i;
9   ElfuSym *sym;
10
11   assert(metarget);
12   assert(msst);
13   assert(msst->symtab);
14   assert(entry > 0);
15   assert(!CIRCLEQ_EMPTY(&msst->symtab->syms));
16
17   sym = CIRCLEQ_FIRST(&msst->symtab->syms);
18   for (i = 1; i < entry; i++) {
19     sym = CIRCLEQ_NEXT(sym, elem);
20   }
21
22   switch (sym->type) {
23     case STT_NOTYPE:
24     case STT_OBJECT:
25     case STT_FUNC:
26       if (sym->scnptr) {
27         assert(elfu_mScnByOldscn(metarget, sym->scnptr));
28         return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr + sym->value;
29       } else {
30         // TODO: UNDEF, ABS, or COMMON
31         ELFU_WARN("symtabLookupVal: Returning 0 for UNDEF, ABS, or COMMON symbol.\n");
32       }
33       break;
34     case STT_SECTION:
35       assert(sym->scnptr);
36       assert(elfu_mScnByOldscn(metarget, sym->scnptr));
37       return elfu_mScnByOldscn(metarget, sym->scnptr)->shdr.sh_addr;
38     case STT_FILE:
39       // TODO
40       ELFU_WARN("symtabLookupVal: Returning 0 for FILE symbol.\n");
41       break;
42     default:
43       ELFU_WARN("symtabLookupVal: Unknown symbol type %d.\n", sym->type);
44       return 0;
45   }
46 }
47
48 void elfu_mRelocate32(ElfuElf *metarget, ElfuScn *mstarget, ElfuScn *msrt)
49 {
50   ElfuRel *rel;
51
52   assert(mstarget);
53   assert(msrt);
54
55   ELFU_DEBUG("Relocating in section of type %d size %jx\n",
56              mstarget->shdr.sh_type,
57              mstarget->shdr.sh_size);
58
59   CIRCLEQ_FOREACH(rel, &msrt->reltab->rels, elem) {
60     Elf32_Word *dest = (Elf32_Word*)(((char*)(mstarget->data.d_buf)) + rel->offset);
61     Elf32_Word a = rel->addendUsed ? rel->addend : *dest;
62     Elf32_Addr p = mstarget->shdr.sh_addr + rel->offset;
63     Elf32_Addr s = symtabLookupVal(metarget, msrt->linkptr, rel->sym);
64     Elf32_Word newval = *dest;
65
66     switch(rel->type) {
67       case R_386_NONE:
68         ELFU_DEBUG("Skipping relocation: R_386_NONE");
69         break;
70       case R_386_32:
71         ELFU_DEBUG("Relocation: R_386_32");
72         newval = s + a;
73         break;
74       case R_386_PC32:
75         ELFU_DEBUG("Relocation: R_386_PC32");
76         newval = s + a - p;
77         break;
78
79       default:
80         ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
81     }
82     ELFU_DEBUG(", overwriting %x with %x.\n", *dest, newval);
83     *dest = newval;
84   }
85 }