/* * Extract a trace specification field, and setup the tracespec struct * accordingly. */ const char * _dl_trace_parse_spec(const char *var, struct tracespec *spec) { const char *start, *end; if (*var == '!') { spec->inverse = 1; var++; } start = var; end = _dl_strchr(start, ':'); if (end == NULL) end = start + _dl_strlen(start); if (end != start) { spec->spec = _dl_malloc(1 + end - start); if (spec->spec == NULL) _dl_exit(8); _dl_bcopy(start, spec->spec, end - start); spec->spec[end - start] = '\0'; } if (*end == ':') end++; return end; }
int _dl_md_reloc(elf_object_t *object, int rel, int relasz) { long i; long numrela; int fails = 0; Elf64_Addr loff; Elf64_Rela *relas; struct load_list *llist; loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela); relas = (Elf64_Rela *)(object->Dyn.info[rel]); if (relas == NULL) return(0); /* * unprotect some segments if we need it. * XXX - we unprotect way to much. only the text can have cow * relocations. */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) { _dl_mprotect(llist->start, llist->size, llist->prot|PROT_WRITE); } } } for (i = 0; i < numrela; i++, relas++) { Elf64_Addr *r_addr; Elf64_Addr ooff; const Elf64_Sym *sym, *this; const char *symn; r_addr = (Elf64_Addr *)(relas->r_offset + loff); if (ELF64_R_SYM(relas->r_info) == 0xffffffff) continue; sym = object->dyn.symtab; sym += ELF64_R_SYM(relas->r_info); symn = object->dyn.strtab + sym->st_name; this = NULL; switch (ELF64_R_TYPE(relas->r_info)) { case R_TYPE(REFQUAD): ooff = _dl_find_symbol_bysym(object, ELF64_R_SYM(relas->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, sym, NULL); if (this == NULL) goto resolve_failed; *r_addr += ooff + this->st_value + relas->r_addend; break; case R_TYPE(RELATIVE): /* * There is a lot of unaligned RELATIVE * relocs generated by gcc in the exception handlers. */ if ((((Elf_Addr) r_addr) & 0x7) != 0) { Elf_Addr tmp; #if 0 _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr, ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff); #endif _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); tmp += loff; _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); } else *r_addr += loff; break; case R_TYPE(JMP_SLOT): ooff = _dl_find_symbol(symn, &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, NULL); if (this == NULL) goto resolve_failed; *r_addr = ooff + this->st_value + relas->r_addend; break; case R_TYPE(GLOB_DAT): ooff = _dl_find_symbol_bysym(object, ELF64_R_SYM(relas->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, sym, NULL); if (this == NULL) goto resolve_failed; *r_addr = ooff + this->st_value + relas->r_addend; break; case R_TYPE(NONE): break; default: _dl_printf("%s:" " %s: unsupported relocation '%s' %d at %lx\n", _dl_progname, object->load_name, symn, ELF64_R_TYPE(relas->r_info), r_addr ); _dl_exit(1); } continue; resolve_failed: if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; } __asm __volatile("imb" : : : "memory"); /* reprotect the unprotected segments */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) _dl_mprotect(llist->start, llist->size, llist->prot); } } return (fails); }
int _dl_md_reloc(elf_object_t *object, int rel, int relasz) { Elf_RelA *rela; Elf_Addr loff; int i, numrela, fails = 0; size_t size; loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA); rela = (Elf_RelA *)(object->Dyn.info[rel]); #ifdef DEBUG DL_DEB(("object %s relasz %x, numrela %x loff %x\n", object->load_name, object->Dyn.info[relasz], numrela, loff)); #endif if (rela == NULL) return (0); /* either it's an ld bug or a wacky hpux abi */ if (!object->dyn.pltgot) object->Dyn.info[DT_PLTGOT] += loff; if (object->dyn.init && !((Elf_Addr)object->dyn.init & 2)) { Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.init, object->dyn.pltgot); #ifdef DEBUG DL_DEB(("PLABEL32: %p:%p(_init) -> 0x%x in %s\n", object->dyn.init, object->dyn.pltgot, addr, object->load_name)); #endif object->dyn.init = (void *)addr; } if (object->dyn.fini && !((Elf_Addr)object->dyn.fini & 2)) { Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.fini, object->dyn.pltgot); #ifdef DEBUG DL_DEB(("PLABEL32: %p:%p(_fini) -> 0x%x in %s\n", object->dyn.fini, object->dyn.pltgot, addr, object->load_name)); #endif object->dyn.fini = (void *)addr; } /* * this is normally done by the crt0 code but we have to make * sure it's set here to allow constructors to call functions * that are overridden in the user binary (that are un-pic) */ if (object->obj_type == OBJTYPE_EXE) _hppa_dl_set_dp(object->dyn.pltgot); for (i = 0; i < numrela; i++, rela++) { const elf_object_t *sobj; const Elf_Sym *sym, *this; Elf_Addr *pt, ooff; const char *symn; int type; type = ELF_R_TYPE(rela->r_info); if (type == RELOC_NONE) continue; sym = object->dyn.symtab + ELF_R_SYM(rela->r_info); sobj = object; symn = object->dyn.strtab + sym->st_name; pt = (Elf_Addr *)(rela->r_offset + loff); ooff = 0; this = NULL; if (ELF_R_SYM(rela->r_info) && sym->st_name) { ooff = _dl_find_symbol_bysym(object, ELF_R_SYM(rela->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| ((type == RELOC_IPLT) ? SYM_PLT: SYM_NOTPLT), sym, &sobj); if (this == NULL) { if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; continue; } } #ifdef DEBUG DL_DEB(("*pt=%x r_addend=%x r_sym=%x\n", *pt, rela->r_addend, ELF_R_SYM(rela->r_info))); #endif switch (type) { case RELOC_DIR32: if (ELF_R_SYM(rela->r_info) && sym->st_name) { *pt = ooff + this->st_value + rela->r_addend; #ifdef DEBUG DL_DEB(("[%x]DIR32: %s:%s -> 0x%x in %s\n", i, symn, object->load_name, *pt, sobj->load_name)); #endif } else { /* * XXX should objects ever get their * sections loaded insequential this * would have to get a section number * (ELF_R_SYM(rela->r_info))-1 and then: * *pt = sect->addr + rela->r_addend; */ if (ELF_R_SYM(rela->r_info)) *pt += loff; else *pt += loff + rela->r_addend; #ifdef DEBUG DL_DEB(("[%x]DIR32: %s @ 0x%x\n", i, object->load_name, *pt)); #endif } break; case RELOC_PLABEL32: if (ELF_R_SYM(rela->r_info)) { if (ELF_ST_TYPE(this->st_info) != STT_FUNC) { DL_DEB(("[%x]PLABEL32: bad\n", i)); break; } *pt = _dl_md_plabel(sobj->obj_base + this->st_value + rela->r_addend, sobj->dyn.pltgot); #ifdef DEBUG DL_DEB(("[%x]PLABEL32: %s:%s -> 0x%x in %s\n", i, symn, object->load_name, *pt, sobj->load_name)); #endif } else { *pt = loff + rela->r_addend; #ifdef DEBUG DL_DEB(("[%x]PLABEL32: %s @ 0x%x\n", i, object->load_name, *pt)); #endif } break; case RELOC_IPLT: if (ELF_R_SYM(rela->r_info)) { pt[0] = ooff + this->st_value + rela->r_addend; pt[1] = (Elf_Addr)sobj->dyn.pltgot; #ifdef DEBUG DL_DEB(("[%x]IPLT: %s:%s -> 0x%x:0x%x in %s\n", i, symn, object->load_name, pt[0], pt[1], sobj->load_name)); #endif } else { pt[0] = loff + rela->r_addend; pt[1] = (Elf_Addr)object->dyn.pltgot; #ifdef DEBUG DL_DEB(("[%x]IPLT: %s @ 0x%x:0x%x\n", i, object->load_name, pt[0], pt[1])); #endif } break; case RELOC_COPY: { const Elf32_Sym *cpysrc = NULL; size = sym->st_size; ooff = _dl_find_symbol(symn, &cpysrc, SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, sym, object, NULL); if (cpysrc) { _dl_bcopy((void *)(ooff + cpysrc->st_value), pt, sym->st_size); #ifdef DEBUG DL_DEB(("[%x]COPY: %s[%x]:%s -> %p[%x] in %s\n", i, symn, ooff + cpysrc->st_value, object->load_name, pt, sym->st_size, sobj->load_name)); #endif } else DL_DEB(("[%x]COPY: no sym\n", i)); break; } default: DL_DEB(("[%x]UNKNOWN(%d): type=%d off=0x%lx " "addend=0x%lx rel=0x%x\n", i, type, ELF_R_TYPE(rela->r_info), rela->r_offset, rela->r_addend, *pt)); break; } } return (fails); }
int _dl_md_reloc(elf_object_t *object, int rel, int relsz) { int i; int numrel; int fails = 0; struct load_list *load_list; Elf64_Addr loff; Elf64_Addr ooff; Elf64_Addr got_start, got_end; Elf64_Rel *relocs; const Elf64_Sym *sym, *this; loff = object->obj_base; numrel = object->Dyn.info[relsz] / sizeof(Elf64_Rel); relocs = (Elf64_Rel *)(object->Dyn.info[rel]); if (relocs == NULL) return(0); /* * Change protection of all write protected segments in the * object so we can do relocations in the .rodata section. * After relocation restore protection. */ load_list = object->load_list; while (load_list != NULL) { if ((load_list->prot & PROT_WRITE) == 0) _dl_mprotect(load_list->start, load_list->size, load_list->prot|PROT_WRITE); load_list = load_list->next; } /* XXX We need the got limits to know if reloc is in got. */ /* XXX Relocs against the got should not include the STUB address! */ this = NULL; got_start = 0; got_end = 0; ooff = _dl_find_symbol("__got_start", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) got_start = ooff + this->st_value; this = NULL; ooff = _dl_find_symbol("__got_end", &this, SYM_SEARCH_OBJ|SYM_NOWARNNOTFOUND|SYM_PLT, NULL, object, NULL); if (this != NULL) got_end = ooff + this->st_value; DL_DEB(("relocating %d\n", numrel)); for (i = 0; i < numrel; i++, relocs++) { Elf64_Addr r_addr = relocs->r_offset + loff; const char *symn; int type; if (ELF64_R_SYM(relocs->r_info) == 0xffffff) continue; ooff = 0; sym = object->dyn.symtab; sym += ELF64_R_SYM(relocs->r_info); symn = object->dyn.strtab + sym->st_name; type = ELF64_R_TYPE(relocs->r_info); this = NULL; if (ELF64_R_SYM(relocs->r_info) && !(ELF64_ST_BIND(sym->st_info) == STB_LOCAL && ELF64_ST_TYPE (sym->st_info) == STT_NOTYPE)) { ooff = _dl_find_symbol(symn, &this, SYM_SEARCH_ALL | SYM_WARNNOTFOUND | SYM_PLT, sym, object, NULL); if (this == NULL) { if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; continue; } } switch (ELF64_R_TYPE(relocs->r_info)) { /* XXX Handle non aligned relocs. .eh_frame * XXX in libstdc++ seems to have them... */ u_int64_t robj; case R_MIPS_REL32_64: if (ELF64_ST_BIND(sym->st_info) == STB_LOCAL && (ELF64_ST_TYPE(sym->st_info) == STT_SECTION || ELF64_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { if ((long)r_addr & 7) { _dl_bcopy((char *)r_addr, &robj, sizeof(robj)); robj += loff + sym->st_value; _dl_bcopy(&robj, (char *)r_addr, sizeof(robj)); } else { *(u_int64_t *)r_addr += loff + sym->st_value; } } else if (this && ((long)r_addr & 7)) { _dl_bcopy((char *)r_addr, &robj, sizeof(robj)); robj += this->st_value + ooff; _dl_bcopy(&robj, (char *)r_addr, sizeof(robj)); } else if (this) { *(u_int64_t *)r_addr += this->st_value + ooff; } break; case R_MIPS_NONE: break; default: _dl_printf("%s: unsupported relocation '%d'\n", _dl_progname, ELF64_R_TYPE(relocs->r_info)); _dl_exit(1); } } DL_DEB(("done %d fails\n", fails)); load_list = object->load_list; while (load_list != NULL) { if ((load_list->prot & PROT_WRITE) == 0) _dl_mprotect(load_list->start, load_list->size, load_list->prot); load_list = load_list->next; } return(fails); }
/* * char *dl_realpath(const char *path, char resolved[PATH_MAX]); * * Find the real name of path, by removing all ".", ".." and symlink * components. Returns (resolved) on success, or (NULL) on failure, * in which case the path which caused trouble is left in (resolved). */ char * _dl_realpath(const char *path, char *resolved) { struct stat sb; const char *p, *s; char *q; size_t left_len, resolved_len; unsigned symlinks; int slen, mem_allocated, ret; char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; if (path[0] == '\0') { return (NULL); } if (resolved == NULL) { resolved = _dl_malloc(PATH_MAX); if (resolved == NULL) return (NULL); mem_allocated = 1; } else mem_allocated = 0; symlinks = 0; if (path[0] == '/') { resolved[0] = '/'; resolved[1] = '\0'; if (path[1] == '\0') return (resolved); resolved_len = 1; left_len = _dl_strlcpy(left, path + 1, sizeof(left)); } else { if (_dl_getcwd(resolved, PATH_MAX) <= 0) { if (mem_allocated) _dl_free(resolved); else _dl_strlcpy(resolved, ".", PATH_MAX); return (NULL); } resolved_len = _dl_strlen(resolved); left_len = _dl_strlcpy(left, path, sizeof(left)); } if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { goto err; } /* * Iterate over path components in `left'. */ while (left_len != 0) { /* * Extract the next path component and adjust `left' * and its length. */ p = _dl_strchr(left, '/'); s = p ? p : left + left_len; if (s - left >= sizeof(next_token)) { goto err; } _dl_bcopy(left, next_token, s - left); next_token[s - left] = '\0'; left_len -= s - left; if (p != NULL) _dl_bcopy(s + 1, left, left_len + 1); if (resolved[resolved_len - 1] != '/') { if (resolved_len + 1 >= PATH_MAX) { goto err; } resolved[resolved_len++] = '/'; resolved[resolved_len] = '\0'; } if (next_token[0] == '\0') continue; else if (_dl_strcmp(next_token, ".") == 0) continue; else if (_dl_strcmp(next_token, "..") == 0) { /* * Strip the last path component except when we have * single "/" */ if (resolved_len > 1) { resolved[resolved_len - 1] = '\0'; q = _dl_strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } continue; } /* * Append the next path component and lstat() it. If * lstat() fails we still can return successfully if * there are no more path components left. */ resolved_len = _dl_strlcat(resolved, next_token, PATH_MAX); if (resolved_len >= PATH_MAX) { goto err; } if ((ret = _dl_lstat(resolved, &sb)) != 0) { if (ret == ENOENT && p == NULL) { return (resolved); } goto err; } if (S_ISLNK(sb.st_mode)) { if (symlinks++ > SYMLOOP_MAX) { goto err; } slen = _dl_readlink(resolved, symlink, sizeof(symlink) - 1); if (slen < 0) goto err; symlink[slen] = '\0'; if (symlink[0] == '/') { resolved[1] = 0; resolved_len = 1; } else if (resolved_len > 1) { /* Strip the last path component. */ resolved[resolved_len - 1] = '\0'; q = _dl_strrchr(resolved, '/') + 1; *q = '\0'; resolved_len = q - resolved; } /* * If there are any path components left, then * append them to symlink. The result is placed * in `left'. */ if (p != NULL) { if (symlink[slen - 1] != '/') { if (slen + 1 >= sizeof(symlink)) { goto err; } symlink[slen] = '/'; symlink[slen + 1] = 0; } left_len = _dl_strlcat(symlink, left, sizeof(symlink)); if (left_len >= sizeof(left)) { goto err; } } left_len = _dl_strlcpy(left, symlink, sizeof(left)); } } /* * Remove trailing slash except when the resolved pathname * is a single "/". */ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') resolved[resolved_len - 1] = '\0'; return (resolved); err: if (mem_allocated) _dl_free(resolved); return (NULL); }
int _dl_md_reloc(elf_object_t *object, int rel, int relasz) { int i; int numrela; int relrel; int fails = 0; struct load_list *llist; Elf32_Addr loff; Elf32_Rela *relas; loff = object->obj_base; numrela = object->Dyn.info[relasz] / sizeof(Elf32_Rela); relrel = rel == DT_RELA ? object->relacount : 0; relas = (Elf32_Rela *)(object->Dyn.info[rel]); #ifdef DL_PRINTF_DEBUG _dl_printf("object relocation size %x, numrela %x\n", object->Dyn.info[relasz], numrela); #endif if (relas == NULL) return(0); if (relrel > numrela) { _dl_printf("relacount > numrela: %ld > %ld\n", relrel, numrela); _dl_exit(20); } /* * Change protection of all write protected segments in the object * so we can do relocations such as PC32. After relocation, * restore protection. */ if (object->dyn.textrel == 1 && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) { _dl_mprotect(llist->start, llist->size, llist->prot|PROT_WRITE); } } } /* tight loop for leading RELATIVE relocs */ for (i = 0; i < relrel; i++, relas++) { Elf32_Addr *r_addr; #ifdef DEBUG if (ELF_R_TYPE(relas->r_info) != R_68K_RELATIVE) { _dl_printf("RELACOUNT wrong\n"); _dl_exit(20); } #endif r_addr = (Elf32_Addr *)(relas->r_offset + loff); *r_addr = relas->r_addend + loff; } for (; i < numrela; i++, relas++) { Elf32_Addr *r_addr = (Elf32_Addr *)(relas->r_offset + loff); Elf32_Addr ooff, addend, newval; const Elf32_Sym *sym, *this; const char *symn; int type; Elf32_Addr prev_value = 0, prev_ooff = 0; const Elf32_Sym *prev_sym = NULL; type = ELF32_R_TYPE(relas->r_info); if (type == R_68K_JMP_SLOT && rel != DT_JMPREL) continue; if (type == R_68K_NONE) continue; sym = object->dyn.symtab; sym += ELF32_R_SYM(relas->r_info); symn = object->dyn.strtab + sym->st_name; if (type == R_68K_COPY) { /* * we need to find a symbol, that is not in the current * object, start looking at the beginning of the list, * searching all objects but _not_ the current object, * first one found wins. */ const Elf32_Sym *cpysrc = NULL; Elf32_Addr src_loff; int size; src_loff = 0; src_loff = _dl_find_symbol(symn, &cpysrc, SYM_SEARCH_OTHER|SYM_WARNNOTFOUND| SYM_NOTPLT, sym, object, NULL); if (cpysrc != NULL) { size = sym->st_size; if (sym->st_size != cpysrc->st_size) { /* _dl_find_symbol() has warned about this already */ size = sym->st_size < cpysrc->st_size ? sym->st_size : cpysrc->st_size; } _dl_bcopy((void *)(src_loff + cpysrc->st_value), r_addr, size); } else fails++; continue; } if (ELF32_R_SYM(relas->r_info) && !(ELF32_ST_BIND(sym->st_info) == STB_LOCAL && ELF32_ST_TYPE (sym->st_info) == STT_NOTYPE) && sym != prev_sym) { this = NULL; ooff = _dl_find_symbol_bysym(object, ELF32_R_SYM(relas->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| ((type == R_68K_JMP_SLOT) ? SYM_PLT:SYM_NOTPLT), sym, NULL); if (this == NULL) { if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; continue; } prev_sym = sym; prev_value = this->st_value; prev_ooff = ooff; } if (ELF32_ST_BIND(sym->st_info) == STB_LOCAL && (ELF32_ST_TYPE(sym->st_info) == STT_SECTION || ELF32_ST_TYPE(sym->st_info) == STT_NOTYPE)) addend = relas->r_addend; else addend = prev_value + relas->r_addend; switch (type) { case R_68K_PC32: newval = prev_ooff + addend; newval -= (Elf_Addr)r_addr; *r_addr = newval; break; case R_68K_32: case R_68K_GLOB_DAT: case R_68K_JMP_SLOT: newval = prev_ooff + addend; *r_addr = newval; break; case R_68K_RELATIVE: newval = loff + addend; *r_addr = newval; break; default: _dl_printf("%s:" " %s: unsupported relocation '%s' %d at %x\n", _dl_progname, object->load_name, symn, ELF32_R_TYPE(relas->r_info), r_addr); _dl_exit(1); } } /* reprotect the unprotected segments */ if (object->dyn.textrel == 1 && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) _dl_mprotect(llist->start, llist->size, llist->prot); } } return(fails); }
/* * Perform $ORIGIN substitutions on path */ static void _dl_origin_subst_path(elf_object_t *object, const char *origin_path, char **path) { char tmp_path[PATH_MAX]; char *new_path, *tp; const char *pp, *name, *value; static struct utsname uts; size_t value_len; int skip_brace; if (uts.sysname[0] == '\0') { if (_dl_uname(&uts) != 0) return; } tp = tmp_path; pp = *path; while (*pp != '\0' && (tp - tmp_path) < sizeof(tmp_path)) { /* copy over chars up to but not including $ */ while (*pp != '\0' && *pp != '$' && (tp - tmp_path) < sizeof(tmp_path)) *tp++ = *pp++; /* substitution sequence detected */ if (*pp == '$' && (tp - tmp_path) < sizeof(tmp_path)) { pp++; if ((skip_brace = (*pp == '{'))) pp++; /* skip over name */ name = pp; while (_dl_isalnum((unsigned char)*pp) || *pp == '_') pp++; switch (_dl_subst_name(name, pp - name)) { case SUBST_ORIGIN: value = origin_path; break; case SUBST_OSNAME: value = uts.sysname; break; case SUBST_OSREL: value = uts.release; break; case SUBST_PLATFORM: value = uts.machine; break; default: value = ""; } value_len = _dl_strlen(value); if (value_len >= sizeof(tmp_path) - (tp - tmp_path)) return; _dl_bcopy(value, tp, value_len); tp += value_len; if (skip_brace && *pp == '}') pp++; } } /* no substitution made if result exceeds sizeof(tmp_path) */ if (tp - tmp_path >= sizeof(tmp_path)) return; /* NULL terminate tmp_path */ *tp = '\0'; if (_dl_strcmp(tmp_path, *path) == 0) return; new_path = _dl_strdup(tmp_path); if (new_path == NULL) return; DL_DEB(("orig_path %s\n", *path)); DL_DEB(("new_path %s\n", new_path)); _dl_free(*path); *path = new_path; }
int _dl_md_reloc(elf_object_t *object, int rel, int relsz) { long i; long numrel; long relrel; int fails = 0; Elf_Addr loff; Elf_Addr prev_value = 0; const Elf_Sym *prev_sym = NULL; Elf_RelA *rels; struct load_list *llist; loff = object->obj_base; numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); relrel = rel == DT_RELA ? object->relacount : 0; rels = (Elf_RelA *)(object->Dyn.info[rel]); if (rels == NULL) return(0); if (relrel > numrel) { _dl_printf("relacount > numrel: %ld > %ld\n", relrel, numrel); _dl_exit(20); } /* * unprotect some segments if we need it. */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) _dl_mprotect(llist->start, llist->size, PROT_READ | PROT_WRITE); } } /* tight loop for leading RELATIVE relocs */ for (i = 0; i < relrel; i++, rels++) { Elf_Addr *where; #ifdef DEBUG if (ELF_R_TYPE(rels->r_info) != R_TYPE(RELATIVE)) { _dl_printf("RELACOUNT wrong\n"); _dl_exit(20); } #endif where = (Elf_Addr *)(rels->r_offset + loff); *where = rels->r_addend + loff; } for (; i < numrel; i++, rels++) { Elf_Addr *where, value, ooff, mask; Elf_Word type; const Elf_Sym *sym, *this; const char *symn; type = ELF_R_TYPE(rels->r_info); if (RELOC_ERROR(type)) { _dl_printf("relocation error %d idx %d\n", type, i); _dl_exit(20); } if (type == R_TYPE(NONE)) continue; if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) continue; where = (Elf_Addr *)(rels->r_offset + loff); if (RELOC_USE_ADDEND(type)) value = rels->r_addend; else value = 0; sym = NULL; symn = NULL; if (RELOC_RESOLVE_SYMBOL(type)) { sym = object->dyn.symtab; sym += ELF_R_SYM(rels->r_info); symn = object->dyn.strtab + sym->st_name; if (sym->st_shndx != SHN_UNDEF && ELF_ST_BIND(sym->st_info) == STB_LOCAL) { value += loff; } else if (sym == prev_sym) { value += prev_value; } else { this = NULL; ooff = _dl_find_symbol_bysym(object, ELF_R_SYM(rels->r_info), &this, SYM_SEARCH_ALL|SYM_WARNNOTFOUND| ((type == R_TYPE(JUMP_SLOT))? SYM_PLT:SYM_NOTPLT), sym, NULL); if (this == NULL) { resolve_failed: if (ELF_ST_BIND(sym->st_info) != STB_WEAK) fails++; continue; } prev_sym = sym; prev_value = (Elf_Addr)(ooff + this->st_value); value += prev_value; } } if (type == R_TYPE(JUMP_SLOT)) { _dl_reloc_plt(where, value); continue; } if (type == R_TYPE(COPY)) { void *dstaddr = where; const void *srcaddr; const Elf_Sym *dstsym = sym, *srcsym = NULL; Elf_Addr soff; soff = _dl_find_symbol(symn, &srcsym, SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, dstsym, object, NULL); if (srcsym == NULL) goto resolve_failed; srcaddr = (void *)(soff + srcsym->st_value); _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); continue; } if (RELOC_PC_RELATIVE(type)) value -= (Elf_Addr)where; if (RELOC_BASE_RELATIVE(type)) value += loff; mask = RELOC_VALUE_BITMASK(type); value >>= RELOC_VALUE_RIGHTSHIFT(type); value &= mask; if (RELOC_TARGET_SIZE(type) > 32) { *where &= ~mask; *where |= value; } else { Elf32_Addr *where32 = (Elf32_Addr *)where; *where32 &= ~mask; *where32 |= value; } } /* reprotect the unprotected segments */ if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { for (llist = object->load_list; llist != NULL; llist = llist->next) { if (!(llist->prot & PROT_WRITE)) _dl_mprotect(llist->start, llist->size, llist->prot); } } return (fails); }