/* * Provide a machine specific interface to the conversion routine. By calling * the machine specific version, rather than the generic version, we insure that * the data tables/strings for all known machine versions aren't dragged into * ld.so.1. */ const char * _conv_reloc_type(uint_t rel) { static Conv_inv_buf_t inv_buf; return (conv_reloc_386_type(rel, 0, &inv_buf)); }
/* * Generic front-end that determines machine specific relocations. */ const char * conv_reloc_type(Half mach, Word type, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf) { switch (mach) { case EM_386: return (conv_reloc_386_type(type, fmt_flags, inv_buf)); case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: return (conv_reloc_SPARC_type(type, fmt_flags, inv_buf)); case EM_AMD64: return (conv_reloc_amd64_type(type, fmt_flags, inv_buf)); } /* If didn't match a machine type, use integer value */ return (conv_invalid_val(inv_buf, type, fmt_flags)); }
/* * Function binding routine - invoked on the first call to a function through * the procedure linkage table; * passes first through an assembly language interface. * * Takes the offset into the relocation table of the associated * relocation entry and the address of the link map (rt_private_map struct) * for the entry. * * Returns the address of the function referenced after re-writing the PLT * entry to invoke the function directly. * * On error, causes process to terminate with a signal. */ ulong_t elf_bndr(Rt_map *lmp, ulong_t reloff, caddr_t from) { Rt_map *nlmp, *llmp; ulong_t addr, symval, rsymndx; char *name; Rel *rptr; Sym *rsym, *nsym; uint_t binfo, sb_flags = 0, dbg_class; Slookup sl; Sresult sr; int entry, lmflags; Lm_list *lml; /* * For compatibility with libthread (TI_VERSION 1) we track the entry * value. A zero value indicates we have recursed into ld.so.1 to * further process a locking request. Under this recursion we disable * tsort and cleanup activities. */ entry = enter(0); lml = LIST(lmp); if ((lmflags = lml->lm_flags) & LML_FLG_RTLDLM) { dbg_class = dbg_desc->d_class; dbg_desc->d_class = 0; } /* * Perform some basic sanity checks. If we didn't get a load map or * the relocation offset is invalid then its possible someone has walked * over the .got entries or jumped to plt0 out of the blue. */ if (!lmp || ((reloff % sizeof (Rel)) != 0)) { Conv_inv_buf_t inv_buf; eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_PLTREF), conv_reloc_386_type(R_386_JMP_SLOT, 0, &inv_buf), EC_NATPTR(lmp), EC_XWORD(reloff), EC_NATPTR(from)); rtldexit(lml, 1); } /* * Use relocation entry to get symbol table entry and symbol name. */ addr = (ulong_t)JMPREL(lmp); rptr = (Rel *)(addr + reloff); rsymndx = ELF_R_SYM(rptr->r_info); rsym = (Sym *)((ulong_t)SYMTAB(lmp) + (rsymndx * SYMENT(lmp))); name = (char *)(STRTAB(lmp) + rsym->st_name); /* * Determine the last link-map of this list, this'll be the starting * point for any tsort() processing. */ llmp = lml->lm_tail; /* * Find definition for symbol. Initialize the symbol lookup, and * symbol result, data structures. */ SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, rsymndx, rsym, 0, LKUP_DEFT); SRESULT_INIT(sr, name); if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) { eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), demangle(name)); rtldexit(lml, 1); } name = (char *)sr.sr_name; nlmp = sr.sr_dmap; nsym = sr.sr_sym; symval = nsym->st_value; if (!(FLAGS(nlmp) & FLG_RT_FIXED) && (nsym->st_shndx != SHN_ABS)) symval += ADDR(nlmp); if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) { /* * Record that this new link map is now bound to the caller. */ if (bind_one(lmp, nlmp, BND_REFER) == 0) rtldexit(lml, 1); } if ((lml->lm_tflags | AFLAGS(lmp)) & LML_TFLG_AUD_SYMBIND) { uint_t symndx = (((uintptr_t)nsym - (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); symval = audit_symbind(lmp, nlmp, nsym, symndx, symval, &sb_flags); } if (!(rtld_flags & RT_FL_NOBIND)) { addr = rptr->r_offset; if (!(FLAGS(lmp) & FLG_RT_FIXED)) addr += ADDR(lmp); if (((lml->lm_tflags | AFLAGS(lmp)) & (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && AUDINFO(lmp)->ai_dynplts) { int fail = 0; uint_t pltndx = reloff / sizeof (Rel); uint_t symndx = (((uintptr_t)nsym - (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); symval = (ulong_t)elf_plt_trace_write(addr, lmp, nlmp, nsym, symndx, pltndx, (caddr_t)symval, sb_flags, &fail); if (fail) rtldexit(lml, 1); } else { /* * Write standard PLT entry to jump directly * to newly bound function. */ *(ulong_t *)addr = symval; } } /* * Print binding information and rebuild PLT entry. */ DBG_CALL(Dbg_bind_global(lmp, (Addr)from, (Off)(from - ADDR(lmp)), (Xword)(reloff / sizeof (Rel)), PLT_T_FULL, nlmp, (Addr)symval, nsym->st_value, name, binfo)); /* * Complete any processing for newly loaded objects. Note we don't * know exactly where any new objects are loaded (we know the object * that supplied the symbol, but others may have been loaded lazily as * we searched for the symbol), so sorting starts from the last * link-map know on entry to this routine. */ if (entry) load_completion(llmp); /* * Some operations like dldump() or dlopen()'ing a relocatable object * result in objects being loaded on rtld's link-map, make sure these * objects are initialized also. */ if ((LIST(nlmp)->lm_flags & LML_FLG_RTLDLM) && LIST(nlmp)->lm_init) load_completion(nlmp); /* * Make sure the object to which we've bound has had it's .init fired. * Cleanup before return to user code. */ if (entry) { is_dep_init(nlmp, lmp); leave(lml, 0); } if (lmflags & LML_FLG_RTLDLM) dbg_desc->d_class = dbg_class; return (symval); }
int /* ARGSUSED2 */ do_relocate(struct module *mp, char *reltbl, Word relshtype, int nreloc, int relocsize, Addr baseaddr) { unsigned long stndx; unsigned long off; /* can't be register for tnf_reloc_resolve() */ register unsigned long reladdr, rend; register unsigned int rtype; long value; Sym *symref; int err = 0; tnf_probe_control_t *probelist = NULL; tnf_tag_data_t *taglist = NULL; int symnum; reladdr = (unsigned long)reltbl; rend = reladdr + nreloc * relocsize; #ifdef KOBJ_DEBUG if (kobj_debug & D_RELOCATIONS) { _kobj_printf(ops, "krtld:\ttype\t\t\toffset symbol\n"); _kobj_printf(ops, "krtld:\t\t\t\t\t value\n"); } #endif symnum = -1; /* loop through relocations */ while (reladdr < rend) { symnum++; rtype = ELF32_R_TYPE(((Rel *)reladdr)->r_info); off = ((Rel *)reladdr)->r_offset; stndx = ELF32_R_SYM(((Rel *)reladdr)->r_info); if (stndx >= mp->nsyms) { _kobj_printf(ops, "do_relocate: bad strndx %d\n", symnum); return (-1); } if ((rtype > R_386_NUM) || IS_TLS_INS(rtype)) { _kobj_printf(ops, "krtld: invalid relocation type %d", rtype); _kobj_printf(ops, " at 0x%llx:", off); _kobj_printf(ops, " file=%s\n", mp->filename); err = 1; continue; } reladdr += relocsize; if (rtype == R_386_NONE) continue; #ifdef KOBJ_DEBUG if (kobj_debug & D_RELOCATIONS) { Sym * symp; symp = (Sym *) (mp->symtbl+(stndx * mp->symhdr->sh_entsize)); _kobj_printf(ops, "krtld:\t%s", conv_reloc_386_type(rtype)); _kobj_printf(ops, "\t0x%8x", off); _kobj_printf(ops, " %s\n", (const char *)mp->strings + symp->st_name); } #endif if (!(mp->flags & KOBJ_EXEC)) off += baseaddr; /* * if R_386_RELATIVE, simply add base addr * to reloc location */ if (rtype == R_386_RELATIVE) { value = baseaddr; } else { /* * get symbol table entry - if symbol is local * value is base address of this object */ symref = (Sym *) (mp->symtbl+(stndx * mp->symhdr->sh_entsize)); if (ELF32_ST_BIND(symref->st_info) == STB_LOCAL) { /* *** this is different for .o and .so */ value = symref->st_value; } else { /* * It's global. Allow weak references. If * the symbol is undefined, give TNF (the * kernel probes facility) a chance to see * if it's a probe site, and fix it up if so. */ if (symref->st_shndx == SHN_UNDEF && sdt_reloc_resolve(mp, mp->strings + symref->st_name, (uint8_t *)off) == 0) continue; if (symref->st_shndx == SHN_UNDEF && tnf_reloc_resolve(mp->strings + symref->st_name, &symref->st_value, off, &probelist, &taglist) != 0) { if (ELF32_ST_BIND(symref->st_info) != STB_WEAK) { _kobj_printf(ops, "not found: %s\n", mp->strings + symref->st_name); err = 1; } continue; } else { /* symbol found - relocate */ /* * calculate location of definition * - symbol value plus base address of * containing shared object */ value = symref->st_value; } /* end else symbol found */ } /* end global or weak */ } /* end not R_386_RELATIVE */ /* * calculate final value - * if PC-relative, subtract ref addr */ if (IS_PC_RELATIVE(rtype)) value -= off; #ifdef KOBJ_DEBUG if (kobj_debug & D_RELOCATIONS) { _kobj_printf(ops, "krtld:\t\t\t\t0x%8x", off); _kobj_printf(ops, " 0x%8x\n", value); } #endif if (do_reloc(rtype, (unsigned char *)off, (Word *)&value, (const char *)mp->strings + symref->st_name, mp->filename, 0) == 0) err = 1; } /* end of while loop */ if (err) return (-1); if (tnf_splice_probes(mp->flags & KOBJ_PRIM, probelist, taglist)) mp->flags |= KOBJ_TNF_PROBE; return (0); }