xref: /nrf52832-nimble/rt-thread/components/libc/libdl/arch/arm.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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__
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