static #endif void*_dl_open(const char*filename,int flags) { int fd; char buf[PATH_MAX]; const char*p=0; for (fd=0;filename[fd] && (p==0);++fd) if (filename[fd]=='/') p=filename; if (p) { #ifdef __DIET_LD_SO__ if ((fd=_dl_sys_open(p,O_RDONLY,0))<0) fd=-1; #else fd=open(p,O_RDONLY); #endif } else { p=buf; fd=_dl_search(buf,sizeof(buf)-1,filename); } if (fd==-1) { _dl_error_data=filename; _dl_error=1; return 0; } return _dl_load(filename,p,fd,flags); }
static int _new_file(DL * dl, char const * pathname) { Elf_Phdr * phdr; size_t i; ssize_t len; dl->fd = open(pathname, O_RDONLY); dl->path = strdup(pathname); if(dl->fd < 0 || dl->path == NULL) return _dl_error_set_errno(-1); /* read the ELF header */ if(_file_read_ehdr(dl->fd, &dl->ehdr) != 0) return -1; /* read the program headers */ if((phdr = _dl_load(dl, dl->ehdr.e_phoff, sizeof(*phdr) * dl->ehdr.e_phnum)) == NULL) return -1; for(i = 0; i < dl->ehdr.e_phnum; i++) { if(phdr[i].p_type != PT_LOAD) continue; if(phdr[i].p_filesz > phdr[i].p_memsz) { free(phdr); return _dl_error_set(DE_INVALID_FORMAT, -1); } if(_file_mmap(dl, &phdr[i]) == 0) continue; free(phdr); return -1; } free(phdr); /* read the section headers */ if((len = dl->ehdr.e_shnum * sizeof(*dl->shdr)) < 0) /* XXX relevant? */ return _dl_error_set(DE_INVALID_FORMAT, -1); if((dl->shdr = _dl_load(dl, dl->ehdr.e_shoff, len)) == NULL) return -1; if(_file_symbols(dl) != 0 || _file_relocations(dl) != 0) return -1; return 0; }
static int _file_relocations(DL * dl) { size_t i; Elf_Shdr * shdr; size_t j; Elf_Rel * rel = NULL; Elf_Rela rela; Elf_Sym * symtab; size_t symtab_cnt; char * strtab; size_t strtab_cnt; Elf_Sym * sym; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); #endif for(i = 0; i < dl->ehdr.e_shnum; i++) { shdr = &dl->shdr[i]; if((shdr->sh_type != SHT_REL || shdr->sh_entsize != sizeof(*rel)) && (shdr->sh_type != SHT_RELA || shdr->sh_entsize != sizeof(rela))) continue; if((rel = _dl_load(dl, shdr->sh_offset, shdr->sh_size)) == NULL) break; if(_dl_symtab(dl, shdr->sh_link, SHT_DYNSYM, &symtab, &symtab_cnt) != 0) break; if(_dl_strtab(dl, dl->shdr[shdr->sh_link].sh_link, &strtab, &strtab_cnt) != 0) { free(symtab); break; } for(j = 0; j < shdr->sh_size; j += shdr->sh_entsize) { rela.r_addend = 0; memcpy(&rela, (char *)rel + j, shdr->sh_entsize); if(ELF_R_SYM(rela.r_info) >= symtab_cnt) break; /* XXX */ sym = &symtab[ELF_R_SYM(rela.r_info)]; _file_relocations_arch(dl, &rela, strtab, strtab_cnt, sym); } free(strtab); free(symtab); } free(rel); return 0; }
/* dl_strtab */ static int _dl_strtab(DL * dl, Elf_Word index, char ** strtab, size_t * strtab_cnt) { Elf_Shdr * shdr; if(index >= dl->ehdr.e_shnum || dl->shdr[index].sh_type != SHT_STRTAB) return -_dl_error_set(DE_INVALID_FORMAT, 1); shdr = &dl->shdr[index]; if((*strtab = _dl_load(dl, shdr->sh_offset, shdr->sh_size)) == NULL) return -1; if((*strtab)[shdr->sh_size - 1] != '\0') { free(*strtab); return -_dl_error_set(DE_INVALID_FORMAT, 1); } *strtab_cnt = shdr->sh_size; return 0; }
/* dl_symtab */ static int _dl_symtab(DL * dl, Elf_Word index, Elf_Word type, Elf_Sym ** symtab, size_t * symtab_cnt) { Elf_Shdr * shdr; #ifdef DEBUG fprintf(stderr, "DEBUG: %s(%p, %u, %u, symtab, symtab_cnt)\n", __func__, dl, index, type); #endif if(index >= dl->ehdr.e_shnum) return -_dl_error_set(DE_INVALID_FORMAT, 1); shdr = &dl->shdr[index]; if(shdr->sh_type != type || shdr->sh_entsize != sizeof(**symtab)) return -_dl_error_set(DE_INVALID_FORMAT, 1); if((*symtab = _dl_load(dl, shdr->sh_offset, shdr->sh_size)) == NULL) return -1; *symtab_cnt = shdr->sh_size / shdr->sh_entsize; return 0; }