summaryrefslogtreecommitdiff
path: root/components/lwp/arch/arm/common/reloc.c
blob: 499ba5f58943f671837aa5c30d4fd2492c562cc1 (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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "mm_aspace.h"
#include <rtthread.h>
#include <stdint.h>
#include <string.h>
#include <lwp_elf.h>
#ifdef ARCH_MM_MMU
#include <mmu.h>
#include <page.h>
#endif

typedef struct
{
    Elf32_Word st_name;
    Elf32_Addr st_value;
    Elf32_Word st_size;
    unsigned char st_info;
    unsigned char st_other;
    Elf32_Half st_shndx;
} Elf32_sym;

#ifdef ARCH_MM_MMU
void arch_elf_reloc(rt_aspace_t aspace, void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym)
{
    size_t rel_off;
    void* addr;

    if (rel_dyn_size && !dynsym)
    {
        return;
    }
    for (rel_off = 0; rel_off < rel_dyn_size; rel_off += 8)
    {
        uint32_t v1, v2;

        /*
        memcpy(&v1, rel_dyn_start + rel_off, 4);
        memcpy(&v2, rel_dyn_start + rel_off + 4, 4);
        */

        addr = rt_hw_mmu_v2p(aspace, (void*)((char*)rel_dyn_start + rel_off));
        addr = (void*)((char*)addr - PV_OFFSET);
        memcpy(&v1, addr, 4);
        addr = rt_hw_mmu_v2p(aspace, (void*)((char*)rel_dyn_start + rel_off + 4));
        addr = (void*)((char*)addr - PV_OFFSET);
        memcpy(&v2, addr, 4);

        addr = rt_hw_mmu_v2p(aspace, (void*)((char*)text_start + v1));
        addr = (void*)((char*)addr - PV_OFFSET);
        if ((v2 & 0xff) == R_ARM_RELATIVE)
        {
            // *(uint32_t*)(text_start + v1) += (uint32_t)text_start;
            *(uint32_t*)addr += (uint32_t)text_start;
        }
        else if ((v2 & 0xff) == R_ARM_ABS32)
        {
            uint32_t t;
            t = (v2 >> 8);
            if (t) /* 0 is UDF */
            {
                // *(uint32_t*)(text_start + v1) = (uint32_t)(text_start + dynsym[t].st_value);
                *(uint32_t*)addr = (uint32_t)((char*)text_start + dynsym[t].st_value);
            }
        }
    }
    /* modify got */
    if (got_size)
    {
        uint32_t *got_item = (uint32_t*)got_start;

        for (rel_off = 0; rel_off < got_size; rel_off += 4, got_item++)
        {
            //*got_item += (uint32_t)text_start;
            addr = rt_hw_mmu_v2p(aspace, got_item);
            addr = (void*)((char*)addr - PV_OFFSET);
            *(uint32_t *)addr += (uint32_t)text_start;
        }
    }
}
#else

void arch_elf_reloc(void *text_start, void *rel_dyn_start, size_t rel_dyn_size, void *got_start, size_t got_size, Elf32_sym *dynsym)
{
    size_t rel_off;

    if (rel_dyn_size && !dynsym)
    {
        return;
    }
    for (rel_off = 0; rel_off < rel_dyn_size; rel_off += 8)
    {
        uint32_t v1, v2;

        memcpy(&v1, (void*)((char*)rel_dyn_start + rel_off), 4);
        memcpy(&v2, (void*)((char*)rel_dyn_start + rel_off + 4), 4);

        if ((v2 & 0xff) == R_ARM_RELATIVE)
        {
            *(uint32_t*)((char*)text_start + v1) += (uint32_t)text_start;
        }
        else if ((v2 & 0xff) == R_ARM_ABS32)
        {
            uint32_t t;
            t = (v2 >> 8);
            if (t) /* 0 is UDF */
            {
                *(uint32_t*)((char*)text_start + v1) = (uint32_t)((char*)text_start + dynsym[t].st_value);
            }
        }
    }
    /* modify got */
    if (got_size)
    {
        uint32_t *got_item = (uint32_t*)got_start;

        for (rel_off = 0; rel_off < got_size; rel_off += 4, got_item++)
        {
            *got_item += (uint32_t)text_start;
        }
    }
}
#endif