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