summaryrefslogtreecommitdiff
path: root/kc/reloc_x86_64.c
blob: 0204700c2d803dd1fb1423c42b9e35eb073c2f4d (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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <kernel/component.h>

#include <elf/elf64.h>

#include <stddef.h>

#define STARTCODE __attribute__((section(".text.start")))

STARTCODE 
static void do_rela(Elf64_Rela *rela, void *base)
{
    union
    {
        Elf_Byte word8;
        Elf64_Half word16;
        Elf64_Word word32;
        Elf64_Xword word64;
    }
    *fixup;

    switch (ELF64_R_TYPE(rela->r_info))
    {
        case R_AMD64_RELATIVE:
            fixup = (void *)(rela->r_offset + (uintptr_t)base);
            fixup->word64 = (rela->r_addend + (uintptr_t)base);
            break;
        default:
            break;
    }
}

STARTCODE
void kc_reloc(Elf64_Dyn *dyn, void *base)
{
    struct
    {
        Elf64_Rela *entries;
        size_t *size;
        size_t *entsize;
    }
    rela = {NULL, NULL, NULL};

    // parse the dynamic segment
    while (dyn && dyn++->d_tag != DT_NULL)
    {
        switch (dyn->d_tag)
        {
            case DT_RELA:
                rela.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base);
                break;
            case DT_RELASZ:
                rela.size = &dyn->d_val;
                break;
            case DT_RELAENT:
                rela.entsize = &dyn->d_val;
                break;
            default:
                break;
        }
    }

    // perform the actual relocation

    for (size_t i = 0; rela.entries && (i < *rela.size / *rela.entsize); i++)
    {
        do_rela(&rela.entries[i], base);
    }
}