summaryrefslogtreecommitdiff
path: root/kc/dynamic_x86_64.c
blob: 6b7abd7a840e3077f90fd50118da95fa570f7f0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <kc.h>

void kc_dynamic_init(void *base, Elf64_Dyn *dyn)
{
    struct rela
    {
        Elf64_Rela *entries;
        size_t size;
        size_t entsize;
    };

    struct rela reladyn = {NULL,};
    struct rela relaplt = {NULL,};

    Elf64_Addr *gotplt;

    while (dyn && dyn->d_tag != DT_NULL)
    {
        switch(dyn->d_tag)
        {
            case DT_RELA:
                reladyn.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base);
                break;
            case DT_RELASZ:
                reladyn.size = dyn->d_val;
                break;
            // NOTE: ELF x86_64 only uses RELA
            // possibly support doing REL also for platforms that want it
            // (am i ever going to use other platforms?)
            case DT_JMPREL:
                relaplt.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base);
                break;
            case DT_PLTRELSZ:
                relaplt.size = dyn->d_val;
                break;
            case DT_RELAENT:
                reladyn.entsize = dyn->d_val;
                relaplt.entsize = dyn->d_val;
                break;
            case DT_PLTGOT:
                gotplt = (uintptr_t *)(dyn->d_ptr + (uintptr_t)base);
                break;
        }
        dyn++;
    }

    // peform relocations
    //
    gotplt[1] = (uintptr_t)NULL;
    gotplt[2] = (uintptr_t)kc_resolve_symbol;
    kc_reloc(base, relaplt.entries, relaplt.size, relaplt.entsize);
    kc_reloc(base, reladyn.entries, reladyn.size, reladyn.entsize);
}