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