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