📄 dl-elf.c
字号:
libaddr = 0; infile = _dl_open(libname, O_RDONLY, 0); if (infile < 0) {#if 0 /* * NO! When we open shared libraries we may search several paths. * it is inappropriate to generate an error here. */ _dl_dprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);#endif _dl_internal_error_number = LD_ERROR_NOFILE; return NULL; } header = _dl_mmap((void *) 0, _dl_pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (_dl_mmap_check_error(header)) { _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_close(infile); return NULL; }; _dl_read(infile, header, _dl_pagesize); epnt = (ElfW(Ehdr) *) (intptr_t) header; if (epnt->e_ident[0] != 0x7f || epnt->e_ident[1] != 'E' || epnt->e_ident[2] != 'L' || epnt->e_ident[3] != 'F') { _dl_dprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname, libname); _dl_internal_error_number = LD_ERROR_NOTELF; _dl_close(infile); _dl_munmap(header, _dl_pagesize); return NULL; }; if ((epnt->e_type != ET_DYN) || (epnt->e_machine != MAGIC1#ifdef MAGIC2 && epnt->e_machine != MAGIC2#endif )) { _dl_internal_error_number = (epnt->e_type != ET_DYN ? LD_ERROR_NOTDYN : LD_ERROR_NOTMAGIC); _dl_dprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET "\n", _dl_progname, libname); _dl_close(infile); _dl_munmap(header, _dl_pagesize); return NULL; }; ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff]; piclib = 1; for (i = 0; i < epnt->e_phnum; i++) { if (ppnt->p_type == PT_DYNAMIC) { if (dynamic_addr) _dl_dprintf(2, "%s: '%s' has more than one dynamic section\n", _dl_progname, libname); dynamic_addr = ppnt->p_vaddr; }; if (ppnt->p_type == PT_LOAD) { /* See if this is a PIC library. */ if (i == 0 && ppnt->p_vaddr > 0x1000000) { piclib = 0; minvma = ppnt->p_vaddr; } if (piclib && ppnt->p_vaddr < minvma) { minvma = ppnt->p_vaddr; } if (((unsigned long) ppnt->p_vaddr + ppnt->p_memsz) > maxvma) { maxvma = ppnt->p_vaddr + ppnt->p_memsz; } } ppnt++; }; maxvma = (maxvma + ADDR_ALIGN) & ~ADDR_ALIGN; minvma = minvma & ~0xffffU; flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ; if (!piclib) flags |= MAP_FIXED; status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma), maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0); if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map %s\n", _dl_progname, libname); _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_close(infile); _dl_munmap(header, _dl_pagesize); return NULL; }; libaddr = (unsigned long) status; flags |= MAP_FIXED; /* Get the memory to store the library */ ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff]; for (i = 0; i < epnt->e_phnum; i++) { if (ppnt->p_type == PT_GNU_RELRO) { relro_addr = ppnt->p_vaddr; relro_size = ppnt->p_memsz; } if (ppnt->p_type == PT_LOAD) { /* See if this is a PIC library. */ if (i == 0 && ppnt->p_vaddr > 0x1000000) { piclib = 0; /* flags |= MAP_FIXED; */ } if (ppnt->p_flags & PF_W) { unsigned long map_size; char *cpnt; status = (char *) _dl_mmap((char *) ((piclib ? libaddr : 0) + (ppnt->p_vaddr & PAGE_ALIGN)), (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, infile, ppnt->p_offset & OFFS_ALIGN); if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_munmap((char *) libaddr, maxvma - minvma); _dl_close(infile); _dl_munmap(header, _dl_pagesize); return NULL; }; /* Pad the last page with zeroes. */ cpnt = (char *) (status + (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz); while (((unsigned long) cpnt) & ADDR_ALIGN) *cpnt++ = 0; /* I am not quite sure if this is completely * correct to do or not, but the basic way that * we handle bss segments is that we mmap * /dev/zero if there are any pages left over * that are not mapped as part of the file */ map_size = (ppnt->p_vaddr + ppnt->p_filesz + ADDR_ALIGN) & PAGE_ALIGN; if (map_size < ppnt->p_vaddr + ppnt->p_memsz) status = (char *) _dl_mmap((char *) map_size + (piclib ? libaddr : 0), ppnt->p_vaddr + ppnt->p_memsz - map_size, LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS, -1, 0); } else status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & PAGE_ALIGN) + (piclib ? libaddr : 0), (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, infile, ppnt->p_offset & OFFS_ALIGN); if (_dl_mmap_check_error(status)) { _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname); _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_munmap((char *) libaddr, maxvma - minvma); _dl_close(infile); _dl_munmap(header, _dl_pagesize); return NULL; }; /* if(libaddr == 0 && piclib) { libaddr = (unsigned long) status; flags |= MAP_FIXED; }; */ }; ppnt++; }; _dl_close(infile); /* For a non-PIC library, the addresses are all absolute */ if (piclib) { dynamic_addr += (unsigned long) libaddr; } /* * OK, the ELF library is now loaded into VM in the correct locations * The next step is to go through and do the dynamic linking (if needed). */ /* Start by scanning the dynamic section to get all of the pointers */ if (!dynamic_addr) { _dl_internal_error_number = LD_ERROR_NODYNAMIC; _dl_dprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname); _dl_munmap(header, _dl_pagesize); return NULL; } dpnt = (Elf32_Dyn *) dynamic_addr; _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); _dl_parse_dynamic_info(dpnt, dynamic_info, NULL); /* If the TEXTREL is set, this means that we need to make the pages writable before we perform relocations. Do this now. They get set back again later. */ if (dynamic_info[DT_TEXTREL]) {#ifndef __FORCE_SHAREABLE_TEXT_SEGMENTS__ ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff]; for (i = 0; i < epnt->e_phnum; i++, ppnt++) { if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) _dl_mprotect((void *) ((piclib ? libaddr : 0) + (ppnt->p_vaddr & PAGE_ALIGN)), (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz, PROT_READ | PROT_WRITE | PROT_EXEC); }#else _dl_dprintf(_dl_debug_file, "Can't modify %s's text section. Use GCC option -fPIC for shared objects, please.\n",libname); _dl_exit(1);#endif } tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, dynamic_addr, 0); tpnt->relro_addr = relro_addr; tpnt->relro_size = relro_size; tpnt->ppnt = (ElfW(Phdr) *)(intptr_t) (tpnt->loadaddr + epnt->e_phoff); tpnt->n_phent = epnt->e_phnum; /* * Add this object into the symbol chain */ if (*rpnt) { (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf)); _dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf)); (*rpnt)->next->prev = (*rpnt); *rpnt = (*rpnt)->next; (*rpnt)->dyn = tpnt; tpnt->symbol_scope = _dl_symbol_tables; } tpnt->usage_count++; tpnt->libtype = elf_lib; /* * OK, the next thing we need to do is to insert the dynamic linker into * the proper entry in the GOT so that the PLT symbols can be properly * resolved. */ lpnt = (unsigned long *) dynamic_info[DT_PLTGOT]; if (lpnt) { lpnt = (unsigned long *) (dynamic_info[DT_PLTGOT] + ((int) libaddr)); INIT_GOT(lpnt, tpnt); };#if defined (__SUPPORT_LD_DEBUG__) if(_dl_debug) { _dl_dprintf(2, "\n\tfile='%s'; generating link map\n", libname); _dl_dprintf(2, "\t\tdynamic: %x base: %x\n", dynamic_addr, libaddr); _dl_dprintf(2, "\t\t entry: %x phdr: %x phnum: %x\n\n", epnt->e_entry + libaddr, tpnt->ppnt, tpnt->n_phent); }#endif _dl_munmap(header, _dl_pagesize); return tpnt;}/* now_flag must be RTLD_NOW or zero */int _dl_fixup(struct dyn_elf *rpnt, int now_flag){ int goof = 0; struct elf_resolve *tpnt; unsigned long reloc_size; if (rpnt->next) goof += _dl_fixup(rpnt->next, now_flag); tpnt = rpnt->dyn;#if defined (__SUPPORT_LD_DEBUG__) if(_dl_debug && !(tpnt->init_flag & RELOCS_DONE)) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s\n", tpnt->libname);#endif if (unlikely(tpnt->dynamic_info[UNSUPPORTED_RELOC_TYPE])) {#if defined (__SUPPORT_LD_DEBUG__) if(_dl_debug) { _dl_dprintf(2, "%s: can't handle %s relocation records\n", _dl_progname, UNSUPPORTED_RELOC_STR); }#endif goof++; return goof; } reloc_size = tpnt->dynamic_info[DT_RELOC_TABLE_SIZE];/* On some machines, notably SPARC & PPC, DT_REL* includes DT_JMPREL in its range. Note that according to the ELF spec, this is completely legal! */#ifdef ELF_MACHINE_PLTREL_OVERLAP reloc_size -= tpnt->dynamic_info [DT_PLTRELSZ];#endif if (tpnt->dynamic_info[DT_RELOC_TABLE_ADDR] && !(tpnt->init_flag & RELOCS_DONE)) { tpnt->init_flag |= RELOCS_DONE; goof += _dl_parse_relocation_information(rpnt, tpnt->dynamic_info[DT_RELOC_TABLE_ADDR], reloc_size); } if (tpnt->dynamic_info[DT_BIND_NOW]) now_flag = RTLD_NOW; if (tpnt->dynamic_info[DT_JMPREL] && (!(tpnt->init_flag & JMP_RELOCS_DONE) || (now_flag && !(tpnt->rtld_flags & now_flag)))) { tpnt->rtld_flags |= now_flag; tpnt->init_flag |= JMP_RELOCS_DONE; if (!(tpnt->rtld_flags & RTLD_NOW)) { _dl_parse_lazy_relocation_information(rpnt, tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info [DT_PLTRELSZ]); } else { goof += _dl_parse_relocation_information(rpnt, tpnt->dynamic_info[DT_JMPREL], tpnt->dynamic_info[DT_PLTRELSZ]); } } return goof;}/* Minimal printf which handles only %s, %d, and %x */void _dl_dprintf(int fd, const char *fmt, ...){ int num; va_list args; char *start, *ptr, *string; static char *buf; buf = _dl_mmap((void *) 0, _dl_pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (_dl_mmap_check_error(buf)) { _dl_write(fd, "mmap of a spare page failed!\n", 29); _dl_exit(20); } start = ptr = buf; if (!fmt) return; if (_dl_strlen(fmt) >= (_dl_pagesize - 1)) { _dl_write(fd, "overflow\n", 11); _dl_exit(20); } _dl_strcpy(buf, fmt); va_start(args, fmt); while (start) { while (*ptr != '%' && *ptr) { ptr++; } if (*ptr == '%') { *ptr++ = '\0'; _dl_write(fd, start, _dl_strlen(start)); switch (*ptr++) { case 's': string = va_arg(args, char *); if (!string) _dl_write(fd, "(null)", 6); else _dl_write(fd, string, _dl_strlen(string)); break; case 'i': case 'd': { char tmp[22]; num = va_arg(args, int); string = _dl_simple_ltoa(tmp, num); _dl_write(fd, string, _dl_strlen(string)); break; } case 'x': case 'X': { char tmp[22]; num = va_arg(args, int); string = _dl_simple_ltoahex(tmp, num); _dl_write(fd, string, _dl_strlen(string)); break; } default: _dl_write(fd, "(null)", 6); break; } start = ptr; } else { _dl_write(fd, start, _dl_strlen(start)); start = NULL; } } _dl_munmap(buf, _dl_pagesize); return;}char *_dl_strdup(const char *string){ char *retval; int len; len = _dl_strlen(string); retval = _dl_malloc(len + 1); _dl_strcpy(retval, string); return retval;}void _dl_parse_dynamic_info(Elf32_Dyn *dpnt, unsigned long dynamic_info[], void *debug_addr){ __dl_parse_dynamic_info(dpnt, dynamic_info, debug_addr);}#ifdef __USE_GNU#if ! defined LIBDL || (! defined PIC && ! defined __PIC__)int__dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, size_t size, void *data), void *data){ struct elf_resolve *l; struct dl_phdr_info info; int ret = 0; for (l = _dl_loaded_modules; l != NULL; l = l->next) { info.dlpi_addr = l->loadaddr; info.dlpi_name = l->libname; info.dlpi_phdr = l->ppnt; info.dlpi_phnum = l->n_phent; ret = callback (&info, sizeof (struct dl_phdr_info), data); if (ret) break; } return ret;}strong_alias(__dl_iterate_phdr, dl_iterate_phdr);#endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -