Lookup dynamically linked global variables.
[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         if (!haveSymval) {
40           haveSymval = !elfu_mDynLookupReldynAddrByName(metarget,
41                                        elfu_mSymtabSymToName(msrt->linkptr, sym),
42                                        &s);
43         }
44       }
45     }
46
47     if (metarget->elfclass == ELFCLASS32) {
48       Elf32_Word a32 = rel->addendUsed ? rel->addend : *dest32;
49       Elf32_Addr p32 = mstarget->shdr.sh_addr + rel->offset;
50       Elf32_Addr s32 = (Elf32_Addr)s;
51
52       switch(metarget->ehdr.e_machine) {
53         case EM_386:
54           switch(rel->type) {
55             case R_386_NONE:
56               ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
57               break;
58             case R_386_32:
59               if (!haveSymval) {
60                 goto MISSINGSYM;
61               }
62               *dest32 = s32 + a32;
63               break;
64             case R_386_PC32:
65               if (!haveSymval) {
66                 goto MISSINGSYM;
67               }
68               *dest32 = s32 + a32 - p32;
69               break;
70             default:
71               ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d\n", rel->type);
72           }
73           break;
74         default:
75           ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n");
76       }
77     } else if (metarget->elfclass == ELFCLASS64) {
78       Elf64_Word a64 = rel->addendUsed ? rel->addend : *dest64;
79       Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
80       Elf64_Addr s64 = (Elf64_Addr)s;
81
82       switch(metarget->ehdr.e_machine) {
83         case EM_X86_64:
84           switch(rel->type) {
85             case R_X86_64_NONE:
86               ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
87               break;
88             case R_X86_64_64:
89               if (!haveSymval) {
90                 goto MISSINGSYM;
91               }
92               *dest64 = s64 + a64;
93               break;
94             case R_X86_64_PC32:
95               if (!haveSymval) {
96                 goto MISSINGSYM;
97               }
98               *dest32 = s64 + a64 - p64;
99               break;
100             case R_X86_64_32:
101               if (!haveSymval) {
102                 goto MISSINGSYM;
103               }
104               *dest32 = s64 + a64;
105               break;
106             default:
107               ELFU_DEBUG("elfu_mRelocate: Skipping unknown relocation type %d", rel->type);
108           }
109           break;
110         default:
111           ELFU_WARN("elfu_mRelocate: Unknown machine type. Aborting.\n");
112       }
113     }
114   }
115
116   return 0;
117
118   MISSINGSYM:
119   ELFU_WARN("elfu_mRelocate: Could not resolve symbol %s. Aborting.\n",
120             elfu_mSymtabSymToName(msrt->linkptr, sym));
121   return -1;
122
123 }