1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018/08/29 Bernard first version
9 */
10
11 #include "../dlmodule.h"
12 #include "../dlelf.h"
13
14 #ifdef __arm__
dlmodule_relocate(struct rt_dlmodule * module,Elf32_Rel * rel,Elf32_Addr sym_val)15 int dlmodule_relocate(struct rt_dlmodule *module, Elf32_Rel *rel, Elf32_Addr sym_val)
16 {
17 Elf32_Addr *where, tmp;
18 Elf32_Sword addend, offset;
19 rt_uint32_t upper, lower, sign, j1, j2;
20
21 where = (Elf32_Addr *)((rt_uint8_t *)module->mem_space
22 + rel->r_offset
23 - module->vstart_addr);
24 switch (ELF32_R_TYPE(rel->r_info))
25 {
26 case R_ARM_NONE:
27 break;
28 case R_ARM_ABS32:
29 *where += (Elf32_Addr)sym_val;
30 RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_ABS32: %x -> %x\n",
31 where, *where));
32 break;
33 case R_ARM_PC24:
34 case R_ARM_PLT32:
35 case R_ARM_CALL:
36 case R_ARM_JUMP24:
37 addend = *where & 0x00ffffff;
38 if (addend & 0x00800000)
39 addend |= 0xff000000;
40 tmp = sym_val - (Elf32_Addr)where + (addend << 2);
41 tmp >>= 2;
42 *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
43 RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_PC24: %x -> %x\n",
44 where, *where));
45 break;
46 case R_ARM_REL32:
47 *where += sym_val - (Elf32_Addr)where;
48 RT_DEBUG_LOG(RT_DEBUG_MODULE,
49 ("R_ARM_REL32: %x -> %x, sym %x, offset %x\n",
50 where, *where, sym_val, rel->r_offset));
51 break;
52 case R_ARM_V4BX:
53 *where &= 0xf000000f;
54 *where |= 0x01a0f000;
55 break;
56
57 case R_ARM_GLOB_DAT:
58 case R_ARM_JUMP_SLOT:
59 *where = (Elf32_Addr)sym_val;
60 RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_JUMP_SLOT: 0x%x -> 0x%x 0x%x\n",
61 where, *where, sym_val));
62 break;
63 #if 0 /* To do */
64 case R_ARM_GOT_BREL:
65 temp = (Elf32_Addr)sym_val;
66 *where = (Elf32_Addr)&temp;
67 RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_GOT_BREL: 0x%x -> 0x%x 0x%x\n",
68 where, *where, sym_val));
69 break;
70 #endif
71
72 case R_ARM_RELATIVE:
73 *where = (Elf32_Addr)sym_val + *where;
74 RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_RELATIVE: 0x%x -> 0x%x 0x%x\n",
75 where, *where, sym_val));
76 break;
77 case R_ARM_THM_CALL:
78 case R_ARM_THM_JUMP24:
79 upper = *(rt_uint16_t *)where;
80 lower = *(rt_uint16_t *)((Elf32_Addr)where + 2);
81
82 sign = (upper >> 10) & 1;
83 j1 = (lower >> 13) & 1;
84 j2 = (lower >> 11) & 1;
85 offset = (sign << 24) |
86 ((~(j1 ^ sign) & 1) << 23) |
87 ((~(j2 ^ sign) & 1) << 22) |
88 ((upper & 0x03ff) << 12) |
89 ((lower & 0x07ff) << 1);
90 if (offset & 0x01000000)
91 offset -= 0x02000000;
92 offset += sym_val - (Elf32_Addr)where;
93
94 if (!(offset & 1) ||
95 offset <= (rt_int32_t)0xff000000 ||
96 offset >= (rt_int32_t)0x01000000)
97 {
98 rt_kprintf("Module: Only Thumb addresses allowed\n");
99
100 return -1;
101 }
102
103 sign = (offset >> 24) & 1;
104 j1 = sign ^ (~(offset >> 23) & 1);
105 j2 = sign ^ (~(offset >> 22) & 1);
106 *(rt_uint16_t *)where = (rt_uint16_t)((upper & 0xf800) |
107 (sign << 10) |
108 ((offset >> 12) & 0x03ff));
109 *(rt_uint16_t *)(where + 2) = (rt_uint16_t)((lower & 0xd000) |
110 (j1 << 13) | (j2 << 11) |
111 ((offset >> 1) & 0x07ff));
112 upper = *(rt_uint16_t *)where;
113 lower = *(rt_uint16_t *)((Elf32_Addr)where + 2);
114 break;
115 default:
116 return -1;
117 }
118
119 return 0;
120 }
121 #endif
122