10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51618Srie * Common Development and Distribution License (the "License"). 61618Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211618Srie 220Sstevel@tonic-gate /* 23*5189Sab196087 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * SPARC relocation code. 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <sys/types.h> 340Sstevel@tonic-gate #include <sys/param.h> 350Sstevel@tonic-gate #include <sys/sysmacros.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/user.h> 380Sstevel@tonic-gate #include <sys/bootconf.h> 390Sstevel@tonic-gate #include <sys/modctl.h> 400Sstevel@tonic-gate #include <sys/elf.h> 410Sstevel@tonic-gate #include <sys/kobj.h> 420Sstevel@tonic-gate #include <sys/kobj_impl.h> 430Sstevel@tonic-gate #include <sys/tnf.h> 440Sstevel@tonic-gate #include <sys/tnf_probe.h> 450Sstevel@tonic-gate #include <sys/sdt.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate #include "reloc.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * Probe discovery support 520Sstevel@tonic-gate */ 530Sstevel@tonic-gate #define PROBE_MARKER_SYMBOL "__tnf_probe_version_1" 540Sstevel@tonic-gate #define TAG_MARKER_SYMBOL "__tnf_tag_version_1" 550Sstevel@tonic-gate 560Sstevel@tonic-gate extern int tnf_splice_probes(int, tnf_probe_control_t *, tnf_tag_data_t *); 570Sstevel@tonic-gate 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * The kernel run-time linker calls this to try to resolve a reference 600Sstevel@tonic-gate * it can't otherwise resolve. We see if it's marking a probe control 610Sstevel@tonic-gate * block or a probe tag block; if so, we do the resolution and return 0. 620Sstevel@tonic-gate * If not, we return 1 to show that we can't resolve it, either. 630Sstevel@tonic-gate */ 640Sstevel@tonic-gate static int 650Sstevel@tonic-gate tnf_reloc_resolve(char *symname, Addr *value_p, 660Sstevel@tonic-gate Elf64_Sxword *addend_p, 670Sstevel@tonic-gate long offset, 680Sstevel@tonic-gate tnf_probe_control_t **probelist, 690Sstevel@tonic-gate tnf_tag_data_t **taglist) 700Sstevel@tonic-gate { 710Sstevel@tonic-gate if (strcmp(symname, PROBE_MARKER_SYMBOL) == 0) { 720Sstevel@tonic-gate *addend_p = 0; 730Sstevel@tonic-gate ((tnf_probe_control_t *)offset)->next = *probelist; 740Sstevel@tonic-gate *probelist = (tnf_probe_control_t *)offset; 750Sstevel@tonic-gate return (0); 760Sstevel@tonic-gate } 770Sstevel@tonic-gate if (strcmp(symname, TAG_MARKER_SYMBOL) == 0) { 780Sstevel@tonic-gate *addend_p = 0; 790Sstevel@tonic-gate *value_p = (Addr)*taglist; 800Sstevel@tonic-gate *taglist = (tnf_tag_data_t *)offset; 810Sstevel@tonic-gate return (0); 820Sstevel@tonic-gate } 830Sstevel@tonic-gate return (1); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate #define SDT_RESTORE_MASK 0xc1f80000 870Sstevel@tonic-gate #define SDT_RESTORE 0x81e80000 880Sstevel@tonic-gate #define SDT_NOP 0x01000000 890Sstevel@tonic-gate #define SDT_RET 0x81c7e008 900Sstevel@tonic-gate #define SDT_RETL 0x81c3e008 910Sstevel@tonic-gate #define SDT_RDO7_MASK 0xbf000000 920Sstevel@tonic-gate #define SDT_RDO7 0x9e000000 930Sstevel@tonic-gate 940Sstevel@tonic-gate static int 950Sstevel@tonic-gate sdt_reloc_resolve(struct module *mp, char *symname, uint32_t *instr, long roff) 960Sstevel@tonic-gate { 970Sstevel@tonic-gate sdt_probedesc_t *sdp; 980Sstevel@tonic-gate 990Sstevel@tonic-gate /* 1000Sstevel@tonic-gate * The "statically defined tracing" (SDT) provider for DTrace uses 1010Sstevel@tonic-gate * a mechanism similar to TNF, but somewhat simpler. (Surprise, 1020Sstevel@tonic-gate * surprise.) The SDT mechanism works by replacing calls to the 1030Sstevel@tonic-gate * undefined routine __dtrace_probe_[name] with nop instructions. 1040Sstevel@tonic-gate * The relocations are logged, and SDT itself will later patch the 1050Sstevel@tonic-gate * running binary appropriately. 1060Sstevel@tonic-gate */ 1070Sstevel@tonic-gate if (strncmp(symname, sdt_prefix, strlen(sdt_prefix)) != 0) 1080Sstevel@tonic-gate return (1); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate symname += strlen(sdt_prefix); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate sdp = kobj_alloc(sizeof (sdt_probedesc_t), KM_WAIT); 1130Sstevel@tonic-gate sdp->sdpd_name = kobj_alloc(strlen(symname) + 1, KM_WAIT); 1140Sstevel@tonic-gate bcopy(symname, sdp->sdpd_name, strlen(symname) + 1); 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate if ((uint32_t *)roff == instr) { 1170Sstevel@tonic-gate /* 1180Sstevel@tonic-gate * This isn't an offset -- it's an absolute value. (This is 1190Sstevel@tonic-gate * typically only true for "unix".) We need to convert the 1200Sstevel@tonic-gate * value into an offset from mp->text. 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate roff -= (uintptr_t)mp->text; 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate sdp->sdpd_offset = roff; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate sdp->sdpd_next = mp->sdt_probes; 1280Sstevel@tonic-gate mp->sdt_probes = sdp; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate /* 1310Sstevel@tonic-gate * If the next instruction is a restore (any variant), then the probe 1320Sstevel@tonic-gate * point is being tail-called. Instead of patching the call to be a 1330Sstevel@tonic-gate * NOP, we must patch it to be a ret. If the next instruction is 1340Sstevel@tonic-gate * writing to %o7, it must be a tail call from a leaf; we must patch 1350Sstevel@tonic-gate * the instruction to be a retl. 1360Sstevel@tonic-gate */ 1370Sstevel@tonic-gate if ((*(instr + 1) & SDT_RESTORE_MASK) == SDT_RESTORE) { 1380Sstevel@tonic-gate *instr = SDT_RET; 1390Sstevel@tonic-gate } else if ((*(instr + 1) & SDT_RDO7_MASK) == SDT_RDO7) { 1400Sstevel@tonic-gate *instr = SDT_RETL; 1410Sstevel@tonic-gate } else { 1420Sstevel@tonic-gate *instr = SDT_NOP; 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate return (0); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate int 1490Sstevel@tonic-gate /* ARGSUSED2 */ 1500Sstevel@tonic-gate do_relocate( 1510Sstevel@tonic-gate struct module *mp, 1520Sstevel@tonic-gate char *reltbl, 1530Sstevel@tonic-gate Word relshtype, 1540Sstevel@tonic-gate int nreloc, 1550Sstevel@tonic-gate int relocsize, 1560Sstevel@tonic-gate Addr baseaddr) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate Word stndx; 1590Sstevel@tonic-gate long off, roff; 1600Sstevel@tonic-gate uintptr_t reladdr, rend; 1610Sstevel@tonic-gate uint_t rtype; 1620Sstevel@tonic-gate Elf64_Sxword addend; 1630Sstevel@tonic-gate Addr value, destination; 1640Sstevel@tonic-gate Sym *symref; 1650Sstevel@tonic-gate int symnum; 1660Sstevel@tonic-gate int err = 0; 1670Sstevel@tonic-gate tnf_probe_control_t *probelist = NULL; 1680Sstevel@tonic-gate tnf_tag_data_t *taglist = NULL; 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate reladdr = (uintptr_t)reltbl; 1710Sstevel@tonic-gate rend = reladdr + nreloc * relocsize; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate #ifdef KOBJ_DEBUG 1740Sstevel@tonic-gate if (kobj_debug & D_RELOCATIONS) { 1750Sstevel@tonic-gate _kobj_printf(ops, "krtld:\ttype\t\t\toffset\t addend" 176*5189Sab196087 " symbol\n"); 1770Sstevel@tonic-gate _kobj_printf(ops, "krtld:\t\t\t\t\t value\n"); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate #endif 1800Sstevel@tonic-gate destination = baseaddr; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 1830Sstevel@tonic-gate * If this machine is loading a module through an alternate address 1840Sstevel@tonic-gate * we need to compute the spot where the actual relocation will 1850Sstevel@tonic-gate * take place. 1860Sstevel@tonic-gate */ 1870Sstevel@tonic-gate if (mp->destination) { 1880Sstevel@tonic-gate int i; 1890Sstevel@tonic-gate Shdr * shp; 1900Sstevel@tonic-gate shp = (Shdr *)mp->shdrs; 1910Sstevel@tonic-gate for (i = 0; i < mp->hdr.e_shnum; i++, shp++) { 1920Sstevel@tonic-gate if (shp->sh_addr == baseaddr) { 1930Sstevel@tonic-gate if ((shp->sh_flags & SHF_ALLOC) && 194*5189Sab196087 !(shp->sh_flags & SHF_WRITE)) 1950Sstevel@tonic-gate destination = (Addr)mp->destination + 196*5189Sab196087 (baseaddr - (Addr)mp->text); 1970Sstevel@tonic-gate break; 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate symnum = -1; 2030Sstevel@tonic-gate /* loop through relocations */ 2040Sstevel@tonic-gate while (reladdr < rend) { 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate symnum++; 2070Sstevel@tonic-gate rtype = ELF_R_TYPE(((Rela *)reladdr)->r_info); 2080Sstevel@tonic-gate roff = off = ((Rela *)reladdr)->r_offset; 2090Sstevel@tonic-gate stndx = ELF_R_SYM(((Rela *)reladdr)->r_info); 2100Sstevel@tonic-gate if (stndx >= mp->nsyms) { 2110Sstevel@tonic-gate _kobj_printf(ops, 2120Sstevel@tonic-gate "do_relocate: bad strndx %d\n", symnum); 2130Sstevel@tonic-gate return (-1); 2140Sstevel@tonic-gate } 2152145Srie if ((rtype > R_SPARC_NUM) || IS_TLS_INS(rtype)) { 2160Sstevel@tonic-gate _kobj_printf(ops, "krtld: invalid relocation type %d", 2170Sstevel@tonic-gate rtype); 2180Sstevel@tonic-gate _kobj_printf(ops, " at 0x%llx:", off); 2190Sstevel@tonic-gate _kobj_printf(ops, " file=%s\n", mp->filename); 2200Sstevel@tonic-gate err = 1; 2210Sstevel@tonic-gate continue; 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate addend = (long)(((Rela *)reladdr)->r_addend); 2240Sstevel@tonic-gate reladdr += relocsize; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate #ifdef KOBJ_DEBUG 2280Sstevel@tonic-gate if (kobj_debug & D_RELOCATIONS) { 2290Sstevel@tonic-gate Sym *symp; 2300Sstevel@tonic-gate symp = (Sym *) 2310Sstevel@tonic-gate (mp->symtbl+(stndx * mp->symhdr->sh_entsize)); 2320Sstevel@tonic-gate _kobj_printf(ops, "krtld:\t%s", 2331618Srie conv_reloc_SPARC_type(rtype)); 2340Sstevel@tonic-gate _kobj_printf(ops, "\t0x%8llx", off); 2350Sstevel@tonic-gate _kobj_printf(ops, " 0x%8llx", addend); 2360Sstevel@tonic-gate _kobj_printf(ops, " %s\n", 2370Sstevel@tonic-gate (const char *)mp->strings + symp->st_name); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate #endif 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate if (rtype == R_SPARC_NONE) 2420Sstevel@tonic-gate continue; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate if (!(mp->flags & KOBJ_EXEC)) 2450Sstevel@tonic-gate off += destination; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate /* 2480Sstevel@tonic-gate * if R_SPARC_RELATIVE, simply add base addr 2490Sstevel@tonic-gate * to reloc location 2500Sstevel@tonic-gate */ 2510Sstevel@tonic-gate if (rtype == R_SPARC_RELATIVE) { 2520Sstevel@tonic-gate value = baseaddr; 2530Sstevel@tonic-gate } else { 2540Sstevel@tonic-gate /* 2550Sstevel@tonic-gate * get symbol table entry - if symbol is local 2560Sstevel@tonic-gate * value is base address of this object 2570Sstevel@tonic-gate */ 2580Sstevel@tonic-gate symref = (Sym *) 259*5189Sab196087 (mp->symtbl+(stndx * mp->symhdr->sh_entsize)); 2600Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) { 2610Sstevel@tonic-gate /* *** this is different for .o and .so */ 2620Sstevel@tonic-gate value = symref->st_value; 2630Sstevel@tonic-gate } else { 2640Sstevel@tonic-gate /* 2650Sstevel@tonic-gate * It's global. Allow weak references. If 2660Sstevel@tonic-gate * the symbol is undefined, give TNF (the 2670Sstevel@tonic-gate * kernel probes facility) a chance to see 2680Sstevel@tonic-gate * if it's a probe site, and fix it up if so. 2690Sstevel@tonic-gate */ 2700Sstevel@tonic-gate if (symref->st_shndx == SHN_UNDEF && 2710Sstevel@tonic-gate sdt_reloc_resolve(mp, mp->strings + 2720Sstevel@tonic-gate symref->st_name, (uint32_t *)off, 2730Sstevel@tonic-gate roff + ((uintptr_t)baseaddr - 2740Sstevel@tonic-gate (uintptr_t)mp->text)) == 0) 2750Sstevel@tonic-gate continue; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate if (symref->st_shndx == SHN_UNDEF && 2780Sstevel@tonic-gate tnf_reloc_resolve(mp->strings + 279*5189Sab196087 symref->st_name, &symref->st_value, 280*5189Sab196087 &addend, off, &probelist, &taglist) != 0) { 2810Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) 2820Sstevel@tonic-gate != STB_WEAK) { 2830Sstevel@tonic-gate _kobj_printf(ops, 2840Sstevel@tonic-gate "not found: %s\n", 2850Sstevel@tonic-gate mp->strings + 2860Sstevel@tonic-gate symref->st_name); 2870Sstevel@tonic-gate err = 1; 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate continue; 2900Sstevel@tonic-gate } else { /* symbol found - relocate */ 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * calculate location of definition 2930Sstevel@tonic-gate * - symbol value plus base address of 2940Sstevel@tonic-gate * containing shared object 2950Sstevel@tonic-gate */ 2960Sstevel@tonic-gate value = symref->st_value; 2970Sstevel@tonic-gate } /* end else symbol found */ 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate } /* end not R_SPARC_RELATIVE */ 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate value += addend; 3020Sstevel@tonic-gate if (IS_EXTOFFSET(rtype)) { 3030Sstevel@tonic-gate value += 304*5189Sab196087 (Word) ELF_R_TYPE_DATA(((Rela *)reladdr)->r_info); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate /* 3080Sstevel@tonic-gate * calculate final value - 3090Sstevel@tonic-gate * if PC-relative, subtract ref addr 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate if (IS_PC_RELATIVE(rtype)) { 3120Sstevel@tonic-gate if (mp->destination) 3130Sstevel@tonic-gate value -= (baseaddr + roff); 3140Sstevel@tonic-gate else 3150Sstevel@tonic-gate value -= off; 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate #ifdef KOBJ_DEBUG 3190Sstevel@tonic-gate if (kobj_debug & D_RELOCATIONS) { 3200Sstevel@tonic-gate _kobj_printf(ops, "krtld:\t\t\t\t0x%8llx", off); 3210Sstevel@tonic-gate _kobj_printf(ops, " 0x%8llx\n", value); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate #endif 324*5189Sab196087 if (do_reloc_krtld(rtype, (unsigned char *)off, (Xword *)&value, 3250Sstevel@tonic-gate (const char *)mp->strings + symref->st_name, 326*5189Sab196087 mp->filename) == 0) 3270Sstevel@tonic-gate err = 1; 3280Sstevel@tonic-gate } /* end of while loop */ 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (err) 3310Sstevel@tonic-gate return (-1); 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate if (tnf_splice_probes(mp->flags & KOBJ_PRIM, probelist, taglist)) 3340Sstevel@tonic-gate mp->flags |= KOBJ_TNF_PROBE; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate return (0); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate int 3400Sstevel@tonic-gate do_relocations(struct module *mp) 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate uint_t shn; 3430Sstevel@tonic-gate Shdr *shp, *rshp; 3440Sstevel@tonic-gate uint_t nreloc; 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate /* do the relocations */ 3470Sstevel@tonic-gate for (shn = 1; shn < mp->hdr.e_shnum; shn++) { 3480Sstevel@tonic-gate rshp = (Shdr *) 349*5189Sab196087 (mp->shdrs + shn * mp->hdr.e_shentsize); 3500Sstevel@tonic-gate if (rshp->sh_type == SHT_REL) { 3510Sstevel@tonic-gate _kobj_printf(ops, "%s can't process type SHT_REL\n", 3520Sstevel@tonic-gate mp->filename); 3530Sstevel@tonic-gate return (-1); 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate if (rshp->sh_type != SHT_RELA) 3560Sstevel@tonic-gate continue; 3570Sstevel@tonic-gate if (rshp->sh_link != mp->symtbl_section) { 3580Sstevel@tonic-gate _kobj_printf(ops, "%s reloc for non-default symtab\n", 3590Sstevel@tonic-gate mp->filename); 3600Sstevel@tonic-gate return (-1); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate if (rshp->sh_info >= mp->hdr.e_shnum) { 3630Sstevel@tonic-gate _kobj_printf(ops, "do_relocations: %s ", mp->filename); 3640Sstevel@tonic-gate _kobj_printf(ops, " sh_info out of range %lld\n", shn); 3650Sstevel@tonic-gate goto bad; 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate nreloc = rshp->sh_size / rshp->sh_entsize; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* get the section header that this reloc table refers to */ 3700Sstevel@tonic-gate shp = (Shdr *) 3710Sstevel@tonic-gate (mp->shdrs + rshp->sh_info * mp->hdr.e_shentsize); 3720Sstevel@tonic-gate /* 3730Sstevel@tonic-gate * Do not relocate any section that isn't loaded into memory. 3740Sstevel@tonic-gate * Most commonly this will skip over the .rela.stab* sections 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate if (!(shp->sh_flags & SHF_ALLOC)) 3770Sstevel@tonic-gate continue; 3780Sstevel@tonic-gate #ifdef KOBJ_DEBUG 3790Sstevel@tonic-gate if (kobj_debug & D_RELOCATIONS) { 3800Sstevel@tonic-gate _kobj_printf(ops, "krtld: relocating: file=%s ", 381*5189Sab196087 mp->filename); 3820Sstevel@tonic-gate _kobj_printf(ops, " section=%d\n", shn); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate #endif 3850Sstevel@tonic-gate if (do_relocate(mp, (char *)rshp->sh_addr, rshp->sh_type, 3860Sstevel@tonic-gate nreloc, rshp->sh_entsize, shp->sh_addr) < 0) { 3870Sstevel@tonic-gate _kobj_printf(ops, 3880Sstevel@tonic-gate "do_relocations: %s do_relocate failed\n", 3890Sstevel@tonic-gate mp->filename); 3900Sstevel@tonic-gate goto bad; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate kobj_free((void *)rshp->sh_addr, rshp->sh_size); 3930Sstevel@tonic-gate rshp->sh_addr = 0; 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate mp->flags |= KOBJ_RELOCATED; 3960Sstevel@tonic-gate return (0); 3970Sstevel@tonic-gate bad: 3980Sstevel@tonic-gate kobj_free((void *)rshp->sh_addr, rshp->sh_size); 3990Sstevel@tonic-gate rshp->sh_addr = 0; 4000Sstevel@tonic-gate return (-1); 4010Sstevel@tonic-gate } 402