• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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