xref: /nrf52832-nimble/rt-thread/components/libc/libdl/dlelf.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 #define DBG_SECTION_NAME    "DLMD"
15 #define DBG_ENABLE          // enable debug macro
16 #define DBG_LEVEL           DBG_INFO
17 #define DBG_COLOR
18 #include <rtdbg.h>          // must after of DEBUG_ENABLE or some other options
19 
20 rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_ptr)
21 {
22     rt_bool_t linked   = RT_FALSE;
23     rt_uint32_t index, module_size = 0;
24     Elf32_Addr vstart_addr, vend_addr;
25     rt_bool_t has_vstart;
26 
27     RT_ASSERT(module_ptr != RT_NULL);
28 
29     if (rt_memcmp(elf_module->e_ident, RTMMAG, SELFMAG) == 0)
30     {
31         /* rtmlinker finished */
32         linked = RT_TRUE;
33     }
34 
35     /* get the ELF image size */
36     has_vstart = RT_FALSE;
37     vstart_addr = vend_addr = RT_NULL;
38     for (index = 0; index < elf_module->e_phnum; index++)
39     {
40         if (phdr[index].p_type != PT_LOAD)
41             continue;
42 
43         LOG_D("LOAD segment: %d, 0x%p, 0x%08x", index, phdr[index].p_vaddr, phdr[index].p_memsz);
44 
45         if (phdr[index].p_memsz < phdr[index].p_filesz)
46         {
47             rt_kprintf("invalid elf: segment %d: p_memsz: %d, p_filesz: %d\n",
48                        index, phdr[index].p_memsz, phdr[index].p_filesz);
49             return RT_NULL;
50         }
51         if (!has_vstart)
52         {
53             vstart_addr = phdr[index].p_vaddr;
54             vend_addr = phdr[index].p_vaddr + phdr[index].p_memsz;
55             has_vstart = RT_TRUE;
56             if (vend_addr < vstart_addr)
57             {
58                 rt_kprintf("invalid elf: segment %d: p_vaddr: %d, p_memsz: %d\n",
59                            index, phdr[index].p_vaddr, phdr[index].p_memsz);
60                 return RT_NULL;
61             }
62         }
63         else
64         {
65             if (phdr[index].p_vaddr < vend_addr)
66             {
67                 rt_kprintf("invalid elf: segment should be sorted and not overlapped\n");
68                 return RT_NULL;
69             }
70             if (phdr[index].p_vaddr > vend_addr + 16)
71             {
72                 /* There should not be too much padding in the object files. */
73                 LOG_W("warning: too much padding before segment %d", index);
74             }
75 
76             vend_addr = phdr[index].p_vaddr + phdr[index].p_memsz;
77             if (vend_addr < phdr[index].p_vaddr)
78             {
79                 rt_kprintf("invalid elf: "
80                            "segment %d address overflow\n", index);
81                 return RT_NULL;
82             }
83         }
84     }
85 
86     module_size = vend_addr - vstart_addr;
87     LOG_D("module size: %d, vstart_addr: 0x%p", module_size, vstart_addr);
88     if (module_size == 0)
89     {
90         rt_kprintf("Module: size error\n");
91         return -RT_ERROR;
92     }
93 
94     module->vstart_addr = vstart_addr;
95     module->nref = 0;
96 
97     /* allocate module space */
98     module->mem_space = rt_malloc(module_size);
99     if (module->mem_space == RT_NULL)
100     {
101         rt_kprintf("Module: allocate space failed.\n");
102         return -RT_ERROR;
103     }
104     module->mem_size = module_size;
105 
106     /* zero all space */
107     rt_memset(module->mem_space, 0, module_size);
108     for (index = 0; index < elf_module->e_phnum; index++)
109     {
110         if (phdr[index].p_type == PT_LOAD)
111         {
112             rt_memcpy(module->mem_space + phdr[index].p_vaddr - vstart_addr,
113                       (rt_uint8_t *)elf_module + phdr[index].p_offset,
114                       phdr[index].p_filesz);
115         }
116     }
117 
118     /* set module entry */
119     module->entry_addr = module->mem_space + elf_module->e_entry - vstart_addr;
120 
121     /* handle relocation section */
122     for (index = 0; index < elf_module->e_shnum; index ++)
123     {
124         rt_uint32_t i, nr_reloc;
125         Elf32_Sym *symtab;
126         Elf32_Rel *rel;
127         rt_uint8_t *strtab;
128         static rt_bool_t unsolved = RT_FALSE;
129 
130         if (!IS_REL(shdr[index]))
131             continue;
132 
133         /* get relocate item */
134         rel = (Elf32_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
135 
136         /* locate .rel.plt and .rel.dyn section */
137         symtab = (Elf32_Sym *)((rt_uint8_t *)module_ptr +
138                                shdr[shdr[index].sh_link].sh_offset);
139         strtab = (rt_uint8_t *)module_ptr +
140                  shdr[shdr[shdr[index].sh_link].sh_link].sh_offset;
141         nr_reloc = (rt_uint32_t)(shdr[index].sh_size / sizeof(Elf32_Rel));
142 
143         /* relocate every items */
144         for (i = 0; i < nr_reloc; i ++)
145         {
146             Elf32_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)];
147 
148             LOG_D("relocate symbol %s shndx %d", strtab + sym->st_name, sym->st_shndx);
149 
150             if ((sym->st_shndx != SHT_NULL) ||(ELF_ST_BIND(sym->st_info) == STB_LOCAL))
151             {
152                 Elf32_Addr addr;
153 
154                 addr = (Elf32_Addr)(module->mem_space + sym->st_value - vstart_addr);
155                 dlmodule_relocate(module, rel, addr);
156             }
157             else if (!linked)
158             {
159                 Elf32_Addr addr;
160 
161                 LOG_D("relocate symbol: %s", strtab + sym->st_name);
162                 /* need to resolve symbol in kernel symbol table */
163                 addr = dlmodule_symbol_find((const char *)(strtab + sym->st_name));
164                 if (addr == 0)
165                 {
166                     LOG_E("Module: can't find %s in kernel symbol table", strtab + sym->st_name);
167                     unsolved = RT_TRUE;
168                 }
169                 else
170                 {
171                     dlmodule_relocate(module, rel, addr);
172                 }
173             }
174             rel ++;
175         }
176 
177         if (unsolved)
178             return -RT_ERROR;
179     }
180 
181     /* construct module symbol table */
182     for (index = 0; index < elf_module->e_shnum; index ++)
183     {
184         /* find .dynsym section */
185         rt_uint8_t *shstrab;
186         shstrab = (rt_uint8_t *)module_ptr +
187                   shdr[elf_module->e_shstrndx].sh_offset;
188         if (rt_strcmp((const char *)(shstrab + shdr[index].sh_name), ELF_DYNSYM) == 0)
189             break;
190     }
191 
192     /* found .dynsym section */
193     if (index != elf_module->e_shnum)
194     {
195         int i, count = 0;
196         Elf32_Sym  *symtab = RT_NULL;
197         rt_uint8_t *strtab = RT_NULL;
198 
199         symtab = (Elf32_Sym *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
200         strtab = (rt_uint8_t *)module_ptr + shdr[shdr[index].sh_link].sh_offset;
201 
202         for (i = 0; i < shdr[index].sh_size / sizeof(Elf32_Sym); i++)
203         {
204             if ((ELF_ST_BIND(symtab[i].st_info) == STB_GLOBAL) &&
205                 (ELF_ST_TYPE(symtab[i].st_info) == STT_FUNC))
206                 count ++;
207         }
208 
209         module->symtab = (struct rt_module_symtab *)rt_malloc
210                          (count * sizeof(struct rt_module_symtab));
211         module->nsym = count;
212         for (i = 0, count = 0; i < shdr[index].sh_size / sizeof(Elf32_Sym); i++)
213         {
214             rt_size_t length;
215 
216             if ((ELF_ST_BIND(symtab[i].st_info) != STB_GLOBAL) ||
217                 (ELF_ST_TYPE(symtab[i].st_info) != STT_FUNC))
218                 continue;
219 
220             length = rt_strlen((const char *)(strtab + symtab[i].st_name)) + 1;
221 
222             module->symtab[count].addr =
223                 (void *)(module->mem_space + symtab[i].st_value - module->vstart_addr);
224             module->symtab[count].name = rt_malloc(length);
225             rt_memset((void *)module->symtab[count].name, 0, length);
226             rt_memcpy((void *)module->symtab[count].name,
227                       strtab + symtab[i].st_name,
228                       length);
229             count ++;
230         }
231     }
232 
233     return RT_EOK;
234 }
235 
236 rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module_ptr)
237 {
238     rt_uint32_t index, rodata_addr = 0, bss_addr = 0, data_addr = 0;
239     rt_uint32_t module_addr = 0, module_size = 0;
240     rt_uint8_t *ptr, *strtab, *shstrab;
241 
242     /* get the ELF image size */
243     for (index = 0; index < elf_module->e_shnum; index ++)
244     {
245         /* text */
246         if (IS_PROG(shdr[index]) && IS_AX(shdr[index]))
247         {
248             module_size += shdr[index].sh_size;
249             module_addr = shdr[index].sh_addr;
250         }
251         /* rodata */
252         if (IS_PROG(shdr[index]) && IS_ALLOC(shdr[index]))
253         {
254             module_size += shdr[index].sh_size;
255         }
256         /* data */
257         if (IS_PROG(shdr[index]) && IS_AW(shdr[index]))
258         {
259             module_size += shdr[index].sh_size;
260         }
261         /* bss */
262         if (IS_NOPROG(shdr[index]) && IS_AW(shdr[index]))
263         {
264             module_size += shdr[index].sh_size;
265         }
266     }
267 
268     /* no text, data and bss on image */
269     if (module_size == 0) return RT_NULL;
270 
271     module->vstart_addr = 0;
272 
273     /* allocate module space */
274     module->mem_space = rt_malloc(module_size);
275     if (module->mem_space == RT_NULL)
276     {
277         rt_kprintf("Module: allocate space failed.\n");
278         return -RT_ERROR;
279     }
280     module->mem_size = module_size;
281 
282     /* zero all space */
283     ptr = module->mem_space;
284     rt_memset(ptr, 0, module_size);
285 
286     /* load text and data section */
287     for (index = 0; index < elf_module->e_shnum; index ++)
288     {
289         /* load text section */
290         if (IS_PROG(shdr[index]) && IS_AX(shdr[index]))
291         {
292             rt_memcpy(ptr,
293                       (rt_uint8_t *)elf_module + shdr[index].sh_offset,
294                       shdr[index].sh_size);
295             LOG_D("load text 0x%x, size %d", ptr, shdr[index].sh_size);
296             ptr += shdr[index].sh_size;
297         }
298 
299         /* load rodata section */
300         if (IS_PROG(shdr[index]) && IS_ALLOC(shdr[index]))
301         {
302             rt_memcpy(ptr,
303                       (rt_uint8_t *)elf_module + shdr[index].sh_offset,
304                       shdr[index].sh_size);
305             rodata_addr = (rt_uint32_t)ptr;
306             LOG_D("load rodata 0x%x, size %d, rodata 0x%x", ptr,
307                 shdr[index].sh_size, *(rt_uint32_t *)data_addr);
308             ptr += shdr[index].sh_size;
309         }
310 
311         /* load data section */
312         if (IS_PROG(shdr[index]) && IS_AW(shdr[index]))
313         {
314             rt_memcpy(ptr,
315                       (rt_uint8_t *)elf_module + shdr[index].sh_offset,
316                       shdr[index].sh_size);
317             data_addr = (rt_uint32_t)ptr;
318             LOG_D("load data 0x%x, size %d, data 0x%x", ptr,
319                 shdr[index].sh_size, *(rt_uint32_t *)data_addr);
320             ptr += shdr[index].sh_size;
321         }
322 
323         /* load bss section */
324         if (IS_NOPROG(shdr[index]) && IS_AW(shdr[index]))
325         {
326             rt_memset(ptr, 0, shdr[index].sh_size);
327             bss_addr = (rt_uint32_t)ptr;
328             LOG_D("load bss 0x%x, size %d", ptr, shdr[index].sh_size);
329         }
330     }
331 
332     /* set module entry */
333     module->entry_addr = (rt_dlmodule_entry_func_t)((rt_uint8_t *)module->mem_space + elf_module->e_entry - module_addr);
334 
335     /* handle relocation section */
336     for (index = 0; index < elf_module->e_shnum; index ++)
337     {
338         rt_uint32_t i, nr_reloc;
339         Elf32_Sym *symtab;
340         Elf32_Rel *rel;
341 
342         if (!IS_REL(shdr[index]))
343             continue;
344 
345         /* get relocate item */
346         rel = (Elf32_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
347 
348         /* locate .dynsym and .dynstr */
349         symtab   = (Elf32_Sym *)((rt_uint8_t *)module_ptr +
350                                  shdr[shdr[index].sh_link].sh_offset);
351         strtab   = (rt_uint8_t *)module_ptr +
352                    shdr[shdr[shdr[index].sh_link].sh_link].sh_offset;
353         shstrab  = (rt_uint8_t *)module_ptr +
354                    shdr[elf_module->e_shstrndx].sh_offset;
355         nr_reloc = (rt_uint32_t)(shdr[index].sh_size / sizeof(Elf32_Rel));
356 
357         /* relocate every items */
358         for (i = 0; i < nr_reloc; i ++)
359         {
360             Elf32_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)];
361 
362             LOG_D("relocate symbol: %s", strtab + sym->st_name);
363 
364             if (sym->st_shndx != STN_UNDEF)
365             {
366                 Elf32_Addr addr = 0;
367 
368                 if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) ||
369                     (ELF_ST_TYPE(sym->st_info) == STT_OBJECT))
370                 {
371                     if (rt_strncmp((const char *)(shstrab +
372                                                   shdr[sym->st_shndx].sh_name), ELF_RODATA, 8) == 0)
373                     {
374                         /* relocate rodata section */
375                         LOG_D("rodata");
376                         addr = (Elf32_Addr)(rodata_addr + sym->st_value);
377                     }
378                     else if (rt_strncmp((const char *)
379                                         (shstrab + shdr[sym->st_shndx].sh_name), ELF_BSS, 5) == 0)
380                     {
381                         /* relocate bss section */
382                         LOG_D("bss");
383                         addr = (Elf32_Addr)bss_addr + sym->st_value;
384                     }
385                     else if (rt_strncmp((const char *)(shstrab + shdr[sym->st_shndx].sh_name),
386                                         ELF_DATA, 6) == 0)
387                     {
388                         /* relocate data section */
389                         LOG_D("data");
390                         addr = (Elf32_Addr)data_addr + sym->st_value;
391                     }
392 
393                     if (addr != 0) dlmodule_relocate(module, rel, addr);
394                 }
395                 else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
396                 {
397                     addr = (Elf32_Addr)((rt_uint8_t *) module->mem_space - module_addr + sym->st_value);
398 
399                     /* relocate function */
400                     dlmodule_relocate(module, rel, addr);
401                 }
402             }
403             else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
404             {
405                 /* relocate function */
406                 dlmodule_relocate(module, rel,
407                                        (Elf32_Addr)((rt_uint8_t *)
408                                                     module->mem_space
409                                                     - module_addr
410                                                     + sym->st_value));
411             }
412             else
413             {
414                 Elf32_Addr addr;
415 
416                 if (ELF32_R_TYPE(rel->r_info) != R_ARM_V4BX)
417                 {
418                     LOG_D("relocate symbol: %s", strtab + sym->st_name);
419 
420                     /* need to resolve symbol in kernel symbol table */
421                     addr = dlmodule_symbol_find((const char *)(strtab + sym->st_name));
422                     if (addr != (Elf32_Addr)RT_NULL)
423                     {
424                         dlmodule_relocate(module, rel, addr);
425                         LOG_D("symbol addr 0x%x", addr);
426                     }
427                     else
428                         LOG_E("Module: can't find %s in kernel symbol table",
429                                    strtab + sym->st_name);
430                 }
431                 else
432                 {
433                     addr = (Elf32_Addr)((rt_uint8_t *) module->mem_space - module_addr + sym->st_value);
434                     dlmodule_relocate(module, rel, addr);
435                 }
436             }
437 
438             rel ++;
439         }
440     }
441 
442     return RT_EOK;
443 }
444