1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "los_dynlink.h"
31 #include "stdlib.h"
32 #include "string.h"
33 #include "unistd.h"
34 #include "fcntl.h"
35 #include "errno.h"
36 #include "limits.h"
37 #include "sys/stat.h"
38 #include "securec.h"
39 #include "arch_elf.h"
40 #include "los_task.h"
41 #include "los_debug.h"
42 #include "los_mux.h"
43
44 #if (LOSCFG_DYNLINK == 1)
45
46 #if defined(__ICCARM__) || defined(__CC_ARM)
47 /**
48 * Place instructions below in .icf linker file:
49 *
50 * keep {section .TABLE.START};
51 * keep {section .sym.*};
52 * keep {section .table.end};
53 * define block SYMBOL_TABLE with fixed order
54 * {
55 * section .TABLE.START,
56 * section .sym.*,
57 * section .table.end
58 * };
59 * place in ROM_region {readonly, block SYMBOL_TABLE};
60 */
61 const SymInfo symTableStart __attribute__((section(".TABLE.START"))) = {
62 .name = "start",
63 .addr = 0
64 };
65
66 const SymInfo symTableEnd __attribute__((section(".table.end"))) = {
67 .name = "end",
68 .addr = 0
69 };
70 #pragma section = ".TABLE.START"
71 #pragma section = ".table.end"
72 #elif defined(__CLANG_ARM) || defined(__GNUC__)
73 /**
74 * Place instructions below in rodata segment of .ld linker file:
75 *
76 * __sym_table_start = .;
77 * KEEP(*( SORT (.sym.*)));
78 * __sym_table_end = .;
79 */
80 extern char __sym_table_start[];
81 extern char __sym_table_end[];
82 #else
83 #error Unknown compiler.
84 #endif
85
86 STATIC LOS_DL_LIST g_dynSharedObjLink;
87 STATIC UINT32 g_dynlinkMux;
88
OsIsPreLoaded(const CHAR * fileName)89 STATIC DynSharedObj *OsIsPreLoaded(const CHAR *fileName)
90 {
91 DynSharedObj *dso = NULL;
92
93 LOS_DL_LIST_FOR_EACH_ENTRY(dso, &g_dynSharedObjLink, DynSharedObj, dsoNode) {
94 if (!strcmp(fileName, dso->fileName)) {
95 ++dso->ref;
96 return dso;
97 }
98 }
99
100 return NULL;
101 }
102
OsVerifyEhdr(const LD_ELF_EHDR * ehdr,UINT32 fileLen)103 STATIC INT32 OsVerifyEhdr(const LD_ELF_EHDR *ehdr, UINT32 fileLen)
104 {
105 if (memcmp(ehdr->e_ident, LD_ELFMAG, LD_SELFMAG) != LOS_OK) {
106 PRINT_ERR("The file is not elf format\n");
107 return LOS_NOK;
108 }
109 if (ehdr->e_type != ET_DYN) {
110 PRINT_ERR("The file is not shared library\n");
111 return LOS_NOK;
112 }
113 if (!check_arch(ehdr)) {
114 PRINT_ERR("The file can not load in current platform\n");
115 return LOS_NOK;
116 }
117 if (ehdr->e_phnum > PHDR_NUM_MAX) {
118 PRINT_ERR("The num of program header is out of limit\n");
119 return LOS_NOK;
120 }
121 if (ehdr->e_phoff > fileLen) {
122 PRINT_ERR("The offset of program header is invalid, elf file is bad\n");
123 return LOS_NOK;
124 }
125
126 return LOS_OK;
127 }
128
OsReadELFInfo(INT32 fd,UINT8 * buffer,size_t readSize,off_t offset)129 STATIC INT32 OsReadELFInfo(INT32 fd, UINT8 *buffer, size_t readSize, off_t offset)
130 {
131 ssize_t byteNum;
132 off_t returnPos;
133
134 if (readSize > 0) {
135 returnPos = lseek(fd, offset, SEEK_SET);
136 if (returnPos != offset) {
137 PRINT_ERR("Failed to seek the position!, offset: %#x\n", offset);
138 return LOS_NOK;
139 }
140
141 byteNum = read(fd, buffer, readSize);
142 if (byteNum <= 0) {
143 PRINT_ERR("Failed to read from offset: %#x!\n", offset);
144 return LOS_NOK;
145 }
146 }
147 return LOS_OK;
148 }
149
OsGetFileLength(UINT32 * fileLen,const CHAR * fileName)150 STATIC INT32 OsGetFileLength(UINT32 *fileLen, const CHAR *fileName)
151 {
152 struct stat buf;
153 INT32 ret;
154
155 ret = stat(fileName, &buf);
156 if (ret < 0) {
157 PRINT_ERR("Failed to stat file: %s, errno: %d\n", fileName, errno);
158 return LOS_NOK;
159 }
160
161 if (buf.st_size > FILE_LENGTH_MAX) {
162 PRINT_ERR("The file: %s length is out of limit!\n", fileName);
163 return LOS_NOK;
164 }
165
166 *fileLen = (UINT32)buf.st_size;
167 return LOS_OK;
168 }
169
OsReadEhdr(INT32 fd,UINT32 fileLen,DynLinkInfo * dlInfo)170 STATIC INT32 OsReadEhdr(INT32 fd, UINT32 fileLen, DynLinkInfo *dlInfo)
171 {
172 INT32 ret;
173
174 ret = OsReadELFInfo(fd, (UINT8 *)&dlInfo->elfEhdr, sizeof(LD_ELF_EHDR), 0);
175 if (ret != LOS_OK) {
176 return -EIO;
177 }
178
179 ret = OsVerifyEhdr(&dlInfo->elfEhdr, fileLen);
180 if (ret != LOS_OK) {
181 return -ELIBBAD;
182 }
183
184 return LOS_OK;
185 }
186
OsReadPhdrs(INT32 fd,UINT32 fileLen,DynLinkInfo * dlInfo)187 STATIC INT32 OsReadPhdrs(INT32 fd, UINT32 fileLen, DynLinkInfo *dlInfo)
188 {
189 INT32 ret;
190 UINT32 size;
191 LD_ELF_EHDR *ehdr = &dlInfo->elfEhdr;
192
193 if ((ehdr->e_phnum == 0) || (ehdr->e_phentsize != sizeof(LD_ELF_PHDR))) {
194 goto ERR;
195 }
196
197 size = sizeof(LD_ELF_PHDR) * ehdr->e_phnum;
198 if ((ehdr->e_phoff + size) > fileLen) {
199 goto ERR;
200 }
201
202 dlInfo->elfPhdr = (LD_ELF_PHDR *)LOS_MemAlloc(OS_SYS_MEM_ADDR, size);
203 if (dlInfo->elfPhdr == NULL) {
204 return -ENOMEM;
205 }
206
207 ret = OsReadELFInfo(fd, (UINT8 *)dlInfo->elfPhdr, size, ehdr->e_phoff);
208 if (ret != LOS_OK) {
209 LOS_MemFree(OS_SYS_MEM_ADDR, dlInfo->elfPhdr);
210 return -EIO;
211 }
212
213 return LOS_OK;
214
215 ERR:
216 PRINT_ERR("the file is bad\n");
217 return -ELIBBAD;
218 }
219
OsLoadInit(const CHAR * fileName,VOID * pool)220 STATIC DynSharedObj *OsLoadInit(const CHAR *fileName, VOID *pool)
221 {
222 DynSharedObj *dso = NULL;
223 UINT32 allocSize, nameLen;
224 UINT32 fileLen = 0;
225 INT32 ret;
226
227 nameLen = strlen(fileName);
228 if (nameLen > PATH_MAX) {
229 PRINT_ERR("file name length is too long\n");
230 errno = ENAMETOOLONG;
231 return NULL;
232 }
233 allocSize = sizeof(DynSharedObj) + nameLen + 1;
234
235 dso = (DynSharedObj *)LOS_MemAlloc(OS_SYS_MEM_ADDR, allocSize);
236 if (dso == NULL) {
237 PRINT_ERR("failed to alloc for dso\n");
238 errno = ENOMEM;
239 return NULL;
240 }
241 (VOID)memset_s(dso, allocSize, 0, allocSize);
242
243 dso->dlInfo = (DynLinkInfo *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(DynLinkInfo));
244 if (dso->dlInfo == NULL) {
245 LOS_MemFree(OS_SYS_MEM_ADDR, dso);
246 PRINT_ERR("failed to alloc for loadInfo\n");
247 errno = ENOMEM;
248 return NULL;
249 }
250 (VOID)memset_s(dso->dlInfo, sizeof(DynLinkInfo), 0, sizeof(DynLinkInfo));
251
252 ret = OsGetFileLength(&fileLen, fileName);
253 if (ret != LOS_OK) {
254 errno = ENOENT;
255 goto ERR1;
256 }
257
258 dso->fd = open(fileName, O_RDONLY);
259 if (dso->fd < 0) {
260 PRINT_ERR("Failed to open ELF file: %s!\n", fileName);
261 goto ERR1;
262 }
263
264 ret = OsReadEhdr(dso->fd, fileLen, dso->dlInfo);
265 if (ret != LOS_OK) {
266 errno = -ret;
267 goto ERR2;
268 }
269
270 ret = OsReadPhdrs(dso->fd, fileLen, dso->dlInfo);
271 if (ret != LOS_OK) {
272 errno = -ret;
273 goto ERR2;
274 }
275
276 (void)strcpy_s(dso->buf, nameLen + 1, fileName);
277 dso->fileName = dso->buf;
278 dso->ref = 1;
279 dso->pool = (pool ? pool : OS_SYS_MEM_ADDR);
280 LOS_ListInit(&dso->dsoNode);
281
282 return dso;
283
284 ERR2:
285 close(dso->fd);
286 ERR1:
287 LOS_MemFree(OS_SYS_MEM_ADDR, dso->dlInfo);
288 LOS_MemFree(OS_SYS_MEM_ADDR, dso);
289 return NULL;
290 }
291
OsReserveSpace(const DynLinkInfo * dlInfo,UINT32 * boundary)292 STATIC INT32 OsReserveSpace(const DynLinkInfo *dlInfo, UINT32 *boundary)
293 {
294 const LD_ELF_PHDR *elfPhdrTemp = dlInfo->elfPhdr;
295 INT32 phdrNum = dlInfo->elfEhdr.e_phnum;
296 UINTPTR addrMin = SIZE_MAX;
297 UINTPTR addrMax = 0;
298 UINT32 offStart = 0;
299 UINT64 size;
300 INT32 i;
301
302 for (i = 0; i < phdrNum; ++i, ++elfPhdrTemp) {
303 if (elfPhdrTemp->p_type == PT_TLS) {
304 PRINT_ERR("unsupport tls\n");
305 return 0;
306 }
307 if (elfPhdrTemp->p_type != PT_LOAD) {
308 continue;
309 }
310
311 if (*boundary == 0) {
312 *boundary = elfPhdrTemp->p_align;
313 }
314
315 if (elfPhdrTemp->p_vaddr < addrMin) {
316 addrMin = elfPhdrTemp->p_vaddr;
317 offStart = elfPhdrTemp->p_offset;
318 }
319 if ((elfPhdrTemp->p_vaddr + elfPhdrTemp->p_memsz) > addrMax) {
320 addrMax = elfPhdrTemp->p_vaddr + elfPhdrTemp->p_memsz;
321 }
322 }
323
324 if ((addrMin == addrMax) || (addrMax < addrMin)) {
325 return 0;
326 }
327 size = ELF_ALIGN_UP(addrMax, *boundary) - ELF_ALIGN_DOWN(addrMin, *boundary) + ELF_ALIGN_DOWN(offStart, *boundary);
328
329 return (size > UINT_MAX) ? 0 : (UINT32)size;
330 }
331
OsDoLoadFile(INT32 fd,UINTPTR addr,const LD_ELF_PHDR * elfPhdr,UINT32 boundary)332 STATIC UINTPTR OsDoLoadFile(INT32 fd, UINTPTR addr, const LD_ELF_PHDR *elfPhdr, UINT32 boundary)
333 {
334 INT32 ret;
335 UINT32 offset = elfPhdr->p_offset - ELF_ALIGN_OFFSET(elfPhdr->p_vaddr, boundary);
336 UINT32 size = elfPhdr->p_filesz + ELF_ALIGN_OFFSET(elfPhdr->p_vaddr, boundary);
337 if (size == 0) {
338 return 0;
339 }
340
341 addr = ELF_ALIGN_DOWN(addr, boundary);
342 ret = OsReadELFInfo(fd, (UINT8 *)addr, size, offset);
343 if (ret != LOS_OK) {
344 return 0;
345 }
346
347 return addr;
348 }
349
OsLoadELFFile(DynSharedObj * dso,UINT32 boundary)350 STATIC INT32 OsLoadELFFile(DynSharedObj *dso, UINT32 boundary)
351 {
352 DynLinkInfo *dlInfo = dso->dlInfo;
353 const LD_ELF_PHDR *elfPhdrTemp = dlInfo->elfPhdr;
354 const LD_ELF_EHDR *elfEhdr = &dlInfo->elfEhdr;
355 UINTPTR loadBase = dso->loadBase;
356 UINTPTR vAddr, loadAddr, bssStart, bssEnd;
357 INT32 i;
358
359 for (i = 0; i < elfEhdr->e_phnum; ++i, ++elfPhdrTemp) {
360 if (elfPhdrTemp->p_type != PT_LOAD) {
361 continue;
362 }
363
364 if ((elfPhdrTemp->p_flags & PF_R) == 0) {
365 return -ENOEXEC;
366 }
367 vAddr = elfPhdrTemp->p_vaddr;
368
369 loadAddr = OsDoLoadFile(dso->fd, (vAddr + loadBase), elfPhdrTemp, boundary);
370 if (loadAddr == 0) {
371 return -EFAULT;
372 }
373
374 if ((elfPhdrTemp->p_memsz > elfPhdrTemp->p_filesz) && (elfPhdrTemp->p_flags & PF_W)) {
375 bssStart = loadAddr + ELF_ALIGN_OFFSET(vAddr, boundary) + elfPhdrTemp->p_filesz;
376 bssEnd = loadAddr + ELF_ALIGN_OFFSET(vAddr, boundary) + elfPhdrTemp->p_memsz;
377 (VOID)memset_s((VOID *)bssStart, bssEnd - bssStart, 0, bssEnd - bssStart);
378 }
379 }
380
381 return LOS_OK;
382 }
383
OsLoadLibrary(DynSharedObj * dso)384 STATIC INT32 OsLoadLibrary(DynSharedObj *dso)
385 {
386 UINT32 loadSize;
387 UINT32 boundary = 0;
388 INT32 ret;
389
390 loadSize = OsReserveSpace(dso->dlInfo, &boundary);
391 if (loadSize == 0) {
392 PRINT_ERR("failed to reserve space!\n");
393 return -EINVAL;
394 }
395
396 dso->loadBase = (UINTPTR)LOS_MemAllocAlign(dso->pool, loadSize, boundary);
397 if (dso->loadBase == 0) {
398 PRINT_ERR("failed to alloc memory for loading shared library\n");
399 return -ENOMEM;
400 }
401
402 ret = OsLoadELFFile(dso, boundary);
403 if (ret != LOS_OK) {
404 LOS_MemFree(dso->pool, (VOID *)dso->loadBase);
405 PRINT_ERR("failed to load shared library\n");
406 return ret;
407 }
408
409 return LOS_OK;
410 }
411
OsGetDynBase(DynSharedObj * dso)412 STATIC INT32 OsGetDynBase(DynSharedObj *dso)
413 {
414 DynLinkInfo *dlInfo = dso->dlInfo;
415 const LD_ELF_PHDR *elfPhdrTemp = dlInfo->elfPhdr;
416 INT32 phdrNum = dlInfo->elfEhdr.e_phnum;
417 INT32 i;
418
419 for (i = 0; i < phdrNum; ++i, ++elfPhdrTemp) {
420 if (elfPhdrTemp->p_type != PT_DYNAMIC) {
421 continue;
422 }
423 dlInfo->dynBase = dso->loadBase + elfPhdrTemp->p_vaddr;
424 return LOS_OK;
425 }
426
427 return LOS_NOK;
428 }
429
OsParseDynamic(DynSharedObj * dso)430 STATIC INT32 OsParseDynamic(DynSharedObj *dso)
431 {
432 LD_ELF_DYN *dyn = NULL;
433 DynLinkInfo *dlInfo = dso->dlInfo;
434 RelocInfoTab *relInfoTab = &dlInfo->relInfoTab;
435
436 for (dyn = (LD_ELF_DYN *)dlInfo->dynBase; dyn->d_tag != DT_NULL; ++dyn) {
437 switch (dyn->d_tag) {
438 case DT_NEEDED:
439 PRINT_ERR("shared library should not depend on others\n");
440 return -ENOTSUP;
441 case DT_TEXTREL:
442 PRINT_ERR("you should recompile shared library with -fPIC\n");
443 return -EFAULT;
444 case DT_HASH:
445 dlInfo->hashTab = (UINT32 *)(dso->loadBase + dyn->d_un.d_ptr);
446 break;
447 case DT_SYMTAB:
448 dlInfo->symTab = (LD_ELF_SYM *)(dso->loadBase + dyn->d_un.d_ptr);
449 break;
450 case DT_STRTAB:
451 dlInfo->symStrings = (CHAR *)(dso->loadBase + dyn->d_un.d_ptr);
452 break;
453 case DT_REL:
454 relInfoTab->rel.relTab = dso->loadBase + dyn->d_un.d_ptr;
455 relInfoTab->rel.relEntSize = sizeof(LD_ELF_REL);
456 break;
457 case DT_RELSZ:
458 relInfoTab->rel.relTabSize = dyn->d_un.d_val;
459 break;
460 case DT_RELA:
461 relInfoTab->rela.relTab = dso->loadBase + dyn->d_un.d_ptr;
462 relInfoTab->rela.relEntSize = sizeof(LD_ELF_RELA);
463 break;
464 case DT_RELASZ:
465 relInfoTab->rela.relTabSize = dyn->d_un.d_val;
466 break;
467 case DT_JMPREL:
468 relInfoTab->jmpRel.relTab = dso->loadBase + dyn->d_un.d_ptr;
469 break;
470 case DT_PLTRELSZ:
471 relInfoTab->jmpRel.relTabSize = dyn->d_un.d_val;
472 break;
473 case DT_PLTREL:
474 relInfoTab->jmpRel.relEntSize = (dyn->d_un.d_val == DT_REL) ? sizeof(LD_ELF_REL) : sizeof(LD_ELF_RELA);
475 default:
476 break;
477 }
478 }
479
480 return LOS_OK;
481 }
482
OsGetHashVal(const CHAR * name)483 STATIC UINT32 OsGetHashVal(const CHAR *name)
484 {
485 UINT32 hashVal = 0;
486 UINT32 tmp;
487 const UINT8 *str = (const UINT8 *)name;
488
489 while (*str) {
490 hashVal = (*str) + (hashVal << WORD_SHIFT);
491 tmp = hashVal & HASH_MASK;
492 if (tmp != 0) {
493 hashVal ^= tmp >> HASH_SHIFT;
494 }
495
496 hashVal &= ~tmp;
497 ++str;
498 }
499
500 return hashVal;
501 }
502
OsFindSymInDso(const DynLinkInfo * dlInfo,const CHAR * name)503 STATIC LD_ELF_SYM *OsFindSymInDso(const DynLinkInfo *dlInfo, const CHAR *name)
504 {
505 LD_ELF_SYM *symTab = dlInfo->symTab;
506 LD_ELF_SYM *sym = NULL;
507 CHAR *symStr = dlInfo->symStrings;
508 UINT32 *hashTab = dlInfo->hashTab;
509 UINT32 bucketNum = hashTab[0];
510 UINT32 *bucket = &hashTab[BUCKET_IDX];
511 UINT32 *chain = &bucket[bucketNum];
512 UINT32 hashVal = OsGetHashVal(name);
513 UINT32 symIdx;
514
515 for (symIdx = bucket[hashVal % bucketNum]; symIdx; symIdx = chain[symIdx]) {
516 if (strcmp(name, symStr + symTab[symIdx].st_name) != 0) {
517 continue;
518 }
519
520 sym = symTab + symIdx;
521 if ((sym->st_value == 0) || (sym->st_shndx == 0)) {
522 return NULL;
523 }
524 return symTab + symIdx;
525 }
526
527 return NULL;
528 }
529
OsFindSymInTable(const CHAR * name)530 STATIC SymInfo *OsFindSymInTable(const CHAR *name)
531 {
532 #if defined(__ICCARM__) || defined(__CC_ARM)
533 SymInfo *symTab = (SymInfo *)__section_end(".TABLE.START");
534 UINT32 symTableSize = ((UINTPTR)__section_begin(".table.end") -
535 (UINTPTR)__section_end(".TABLE.START")) / sizeof(SymInfo);
536 #elif defined(__CLANG_ARM) || defined(__GNUC__)
537 SymInfo *symTab = (SymInfo *)__sym_table_start;
538 UINT32 symTableSize = (__sym_table_end - __sym_table_start) / sizeof(SymInfo);
539 #endif
540 INT32 startIdx = 0;
541 INT32 endIdx = symTableSize - 1;
542 INT32 ret, midIdx;
543
544 while (startIdx <= endIdx) {
545 midIdx = startIdx + ((UINT32)(endIdx - startIdx) >> 1);
546 ret = strcmp(symTab[midIdx].name, name);
547 if (ret > 0) {
548 endIdx = midIdx - 1;
549 } else if (ret < 0) {
550 startIdx = midIdx + 1;
551 } else {
552 return symTab + midIdx;
553 }
554 }
555
556 return NULL;
557 }
558
OsFindSym(const DynSharedObj * dso,INT32 symIdx)559 STATIC UINTPTR OsFindSym(const DynSharedObj *dso, INT32 symIdx)
560 {
561 DynLinkInfo *dlInfo = dso->dlInfo;
562 CHAR *symStrings = dlInfo->symStrings;
563 CHAR *symStr = NULL;
564 LD_ELF_SYM *symTab = dlInfo->symTab;
565 LD_ELF_SYM *sym = NULL;
566 LD_ELF_SYM *symInDso = NULL;
567 SymInfo *symInTab = NULL;
568
569 sym = symTab + symIdx;
570 symStr = symStrings + sym->st_name;
571 if ((symInDso = OsFindSymInDso(dlInfo, symStr)) != NULL) {
572 return dso->loadBase + symInDso->st_value;
573 } else if ((symInTab = OsFindSymInTable(symStr)) != NULL) {
574 return symInTab->addr;
575 } else {
576 PRINT_ERR("failed to relocate %s, symbol: %s not found\n", dso->fileName, symStr);
577 return 0;
578 }
579 }
580
OsDoReloc(const DynSharedObj * dso,INT32 type,UINTPTR relocAddr,UINT32 addend,UINTPTR symAddr)581 STATIC INT32 OsDoReloc(const DynSharedObj *dso, INT32 type, UINTPTR relocAddr, UINT32 addend, UINTPTR symAddr)
582 {
583 switch (type) {
584 case R_ARCH_NONE:
585 break;
586 case R_ARCH_GLOB_DAT:
587 case R_ARCH_JUMP_SLOT:
588 *(UINTPTR *)relocAddr = symAddr + addend;
589 break;
590 case R_ARCH_ABS32:
591 *(UINTPTR *)relocAddr = symAddr + ((addend != 0) ? addend : *(UINTPTR *)relocAddr);
592 break;
593 case R_ARCH_RELATIVE:
594 *(UINTPTR *)relocAddr = dso->loadBase + ((addend != 0) ? addend : *(UINTPTR *)relocAddr);
595 break;
596 default:
597 PRINT_ERR("failed to relocate %s, unsupported reloc type: %d\n", dso->fileName, type);
598 return -ENOTSUP;
599 }
600
601 return LOS_OK;
602 }
603
OsDoRelocSyms(DynSharedObj * dso,RelocInfo * relInfo)604 STATIC INT32 OsDoRelocSyms(DynSharedObj *dso, RelocInfo *relInfo)
605 {
606 UINT32 relStride = relInfo->relEntSize / sizeof(UINT32);
607 UINT32 *relTab = (UINT32 *)relInfo->relTab;
608 UINT32 addend;
609 UINTPTR relocAddr, symAddr;
610 INT32 i, symIdx, ret, type;
611
612 for (i = 0; i < relInfo->relTabSize; i += relInfo->relEntSize, relTab += relStride) {
613 type = REL_TYPE(relTab[1]);
614 if (type == R_ARCH_NONE) {
615 continue;
616 }
617
618 symIdx = REL_SYM(relTab[1]);
619 if (symIdx == 0) {
620 symAddr = 0;
621 } else {
622 symAddr = OsFindSym(dso, symIdx);
623 if (symAddr == 0) {
624 return -EFAULT;
625 }
626 }
627
628 relocAddr = dso->loadBase + relTab[0];
629 addend = (relInfo->relEntSize == sizeof(LD_ELF_REL)) ? 0 : relTab[relStride - 1];
630 ret = OsDoReloc(dso, type, relocAddr, addend, symAddr);
631 if (ret != LOS_OK) {
632 return ret;
633 }
634 }
635
636 return LOS_OK;
637 }
638
OsRelocSyms(DynSharedObj * dso)639 STATIC INT32 OsRelocSyms(DynSharedObj *dso)
640 {
641 DynLinkInfo *dlInfo = dso->dlInfo;
642 RelocInfo *relInfo = (RelocInfo *)&dlInfo->relInfoTab;
643 INT32 relTypes = sizeof(RelocInfoTab) / sizeof(RelocInfo);
644 INT32 i, ret;
645
646 for (i = 0; i < relTypes; ++i, ++relInfo) {
647 if (relInfo->relTab == 0) {
648 continue;
649 }
650
651 ret = OsDoRelocSyms(dso, relInfo);
652 if (ret != LOS_OK) {
653 return ret;
654 }
655 }
656
657 return LOS_OK;
658 }
659
OsDoDynLink(DynSharedObj * dso)660 STATIC INT32 OsDoDynLink(DynSharedObj *dso)
661 {
662 INT32 ret;
663
664 ret = OsGetDynBase(dso);
665 if (ret != LOS_OK) {
666 PRINT_ERR("there are no dynamic segments in elf file\n");
667 return -ELIBBAD;
668 }
669
670 ret = OsParseDynamic(dso);
671 if (ret != LOS_OK) {
672 return ret;
673 }
674
675 ret = OsRelocSyms(dso);
676 if (ret != LOS_OK) {
677 return ret;
678 }
679
680 return LOS_OK;
681 }
682
OsDeLoadInit(DynSharedObj * dso)683 STATIC VOID OsDeLoadInit(DynSharedObj *dso)
684 {
685 LOS_MemFree(OS_SYS_MEM_ADDR, dso->dlInfo->elfPhdr);
686 dso->dlInfo->elfPhdr = NULL;
687 close(dso->fd);
688 }
689
OsGetInitFini(DynSharedObj * dso)690 STATIC VOID OsGetInitFini(DynSharedObj *dso)
691 {
692 LD_ELF_DYN *dyn = NULL;
693 DynLinkInfo *dlInfo = dso->dlInfo;
694 InitFiniTab *initFiniTab = &dso->initFiniTab;
695
696 for (dyn = (LD_ELF_DYN *)dlInfo->dynBase; dyn->d_tag != DT_NULL; ++dyn) {
697 switch (dyn->d_tag) {
698 case DT_INIT:
699 initFiniTab->init.func = dyn->d_un.d_ptr;
700 break;
701 case DT_INIT_ARRAY:
702 initFiniTab->init.array = dyn->d_un.d_ptr;
703 break;
704 case DT_INIT_ARRAYSZ:
705 initFiniTab->init.arraySz = dyn->d_un.d_val;
706 break;
707 case DT_FINI:
708 initFiniTab->fini.func = dyn->d_un.d_ptr;
709 break;
710 case DT_FINI_ARRAY:
711 initFiniTab->fini.array = dyn->d_un.d_ptr;
712 break;
713 case DT_FINI_ARRAYSZ:
714 initFiniTab->fini.arraySz = dyn->d_un.d_val;
715 break;
716 default:
717 break;
718 }
719 }
720 }
721
OsDoInit(DynSharedObj * dso)722 STATIC VOID OsDoInit(DynSharedObj *dso)
723 {
724 InitFiniTab *initFiniTab = &dso->initFiniTab;
725 INIT_FINI_FUNC initFunc = NULL;
726 UINTPTR *func = NULL;
727 UINT32 funcNum;
728
729 OsGetInitFini(dso);
730 if (initFiniTab->init.func != 0) {
731 initFunc = (INIT_FINI_FUNC)(dso->loadBase + initFiniTab->init.func);
732 initFunc();
733 }
734
735 if (initFiniTab->init.array == 0) {
736 return;
737 }
738
739 funcNum = initFiniTab->init.arraySz / sizeof(UINTPTR);
740 func = (UINTPTR *)(dso->loadBase + initFiniTab->init.array);
741 while (funcNum--) {
742 initFunc = (INIT_FINI_FUNC)(*func);
743 initFunc();
744 ++func;
745 }
746 }
747
LOS_SoLoad(const CHAR * fileName,VOID * pool)748 VOID *LOS_SoLoad(const CHAR *fileName, VOID *pool)
749 {
750 INT32 ret;
751 DynSharedObj *dso = NULL;
752
753 if (fileName == NULL) {
754 PRINT_ERR("invalid file name\n");
755 errno = EINVAL;
756 return NULL;
757 }
758
759 (VOID)LOS_MuxPend(g_dynlinkMux, LOS_WAIT_FOREVER);
760 dso = OsIsPreLoaded(fileName);
761 if (dso != NULL) {
762 (VOID)LOS_MuxPost(g_dynlinkMux);
763 return dso;
764 }
765
766 dso = OsLoadInit(fileName, pool);
767 if (dso == NULL) {
768 (VOID)LOS_MuxPost(g_dynlinkMux);
769 return NULL;
770 }
771
772 ret = OsLoadLibrary(dso);
773 if (ret != LOS_OK) {
774 errno = -ret;
775 goto ERR1;
776 }
777
778 ret = OsDoDynLink(dso);
779 if (ret != LOS_OK) {
780 errno = -ret;
781 goto ERR2;
782 }
783
784 OsDoInit(dso);
785
786 LOS_ListAdd(&g_dynSharedObjLink, &dso->dsoNode);
787 (VOID)LOS_MuxPost(g_dynlinkMux);
788 OsDeLoadInit(dso);
789
790 return dso;
791
792 ERR2:
793 (VOID)LOS_MemFree(dso->pool, (VOID *)dso->loadBase);
794 ERR1:
795 close(dso->fd);
796 (VOID)LOS_MuxPost(g_dynlinkMux);
797 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dso->dlInfo->elfPhdr);
798 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dso->dlInfo);
799 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dso);
800 return NULL;
801 }
802
OsCheckHandle(VOID * handle)803 STATIC DynSharedObj *OsCheckHandle(VOID *handle)
804 {
805 DynSharedObj *dso = NULL;
806
807 LOS_DL_LIST_FOR_EACH_ENTRY(dso, &g_dynSharedObjLink, DynSharedObj, dsoNode) {
808 if (handle == dso) {
809 return dso;
810 }
811 }
812
813 return NULL;
814 }
815
LOS_FindSym(VOID * handle,const CHAR * name)816 VOID *LOS_FindSym(VOID *handle, const CHAR *name)
817 {
818 LD_ELF_SYM *sym = NULL;
819 DynSharedObj *dso = NULL;
820 VOID *symAddr = NULL;
821
822 if ((handle == NULL) || (name == NULL)) {
823 goto ERR;
824 }
825
826 (VOID)LOS_MuxPend(g_dynlinkMux, LOS_WAIT_FOREVER);
827 dso = OsCheckHandle(handle);
828 if (dso == NULL) {
829 (VOID)LOS_MuxPost(g_dynlinkMux);
830 goto ERR;
831 }
832
833 sym = OsFindSymInDso(dso->dlInfo, name);
834 if (sym == NULL) {
835 (VOID)LOS_MuxPost(g_dynlinkMux);
836 PRINT_ERR("failed to find symbol: %s\n", name);
837 errno = EFAULT;
838 return NULL;
839 }
840 symAddr = (VOID *)(dso->loadBase + sym->st_value);
841 (VOID)LOS_MuxPost(g_dynlinkMux);
842 return symAddr;
843
844 ERR:
845 PRINT_ERR("invalid input param\n");
846 errno = EINVAL;
847 return NULL;
848 }
849
OsDoFini(DynSharedObj * dso)850 STATIC VOID OsDoFini(DynSharedObj *dso)
851 {
852 InitFiniTab *initFiniTab = &dso->initFiniTab;
853 INIT_FINI_FUNC finiFunc = NULL;
854 UINTPTR *func = NULL;
855 UINT32 funcNum;
856
857 if (initFiniTab->fini.array != 0) {
858 funcNum = initFiniTab->fini.arraySz / sizeof(UINTPTR);
859 func = (UINTPTR *)(dso->loadBase + initFiniTab->fini.array) + funcNum;
860 while (funcNum--) {
861 --func;
862 finiFunc = (INIT_FINI_FUNC)(*func);
863 finiFunc();
864 }
865 }
866
867 if (initFiniTab->fini.func != 0) {
868 finiFunc = (INIT_FINI_FUNC)(dso->loadBase + initFiniTab->fini.func);
869 finiFunc();
870 }
871 }
872
LOS_SoUnload(VOID * handle)873 INT32 LOS_SoUnload(VOID *handle)
874 {
875 DynSharedObj *dso = NULL;
876
877 if (handle == NULL) {
878 goto ERR;
879 }
880
881 (VOID)LOS_MuxPend(g_dynlinkMux, LOS_WAIT_FOREVER);
882 dso = OsCheckHandle(handle);
883 if (dso == NULL) {
884 (VOID)LOS_MuxPost(g_dynlinkMux);
885 goto ERR;
886 }
887
888 if (dso->ref > 1) {
889 --dso->ref;
890 (VOID)LOS_MuxPost(g_dynlinkMux);
891 return LOS_OK;
892 }
893
894 OsDoFini(dso);
895
896 LOS_ListDelete(&dso->dsoNode);
897 (VOID)LOS_MuxPost(g_dynlinkMux);
898
899 (VOID)LOS_MemFree(dso->pool, (VOID *)dso->loadBase);
900 if (dso->dlInfo != NULL) {
901 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dso->dlInfo->elfPhdr);
902 }
903 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dso->dlInfo);
904 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dso);
905
906 return LOS_OK;
907 ERR:
908 PRINT_ERR("invalid handle\n");
909 errno = EINVAL;
910 return LOS_NOK;
911 }
912
LOS_DynlinkInit(VOID)913 INT32 LOS_DynlinkInit(VOID)
914 {
915 UINT32 ret;
916
917 LOS_ListInit(&g_dynSharedObjLink);
918 ret = LOS_MuxCreate(&g_dynlinkMux);
919 if (ret != LOS_OK) {
920 return LOS_NOK;
921 }
922 return LOS_OK;
923 }
924
925 #endif /* LOSCFG_DYNLINK */
926