Separate library code, build .a/.so
[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 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 %u size %x\n",
17              mstarget->shdr.sh_type,
18              (unsigned)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       Elf64_Word a64 = rel->addend;
45       Elf64_Addr p64 = mstarget->shdr.sh_addr + rel->offset;
46       Elf64_Addr s64 = elfu_mSymtabLookupVal(metarget, msrt->linkptr, rel->sym);
47
48       /* x86-64 only uses RELA with explicit addend. */
49       assert(rel->addendUsed);
50
51       switch(rel->type) {
52         case R_X86_64_NONE:
53           ELFU_DEBUG("Skipping relocation: R_386_NONE\n");
54           break;
55         case R_X86_64_64:
56           *dest64 = s64 + a64;
57           break;
58         case R_X86_64_PC32:
59           *dest32 = s64 + a64 - p64;
60           break;
61         case R_X86_64_32:
62           *dest32 = s64 + a64;
63           break;
64
65         default:
66           ELFU_DEBUG("Skipping relocation: Unknown type %d", rel->type);
67       }
68     }
69   }
70 }