4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * x86 relocation code.
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/sysmacros.h>
36 #include <sys/systm.h>
38 #include <sys/bootconf.h>
39 #include <sys/modctl.h>
42 #include <sys/kobj_impl.h>
44 #include <sys/tnf_probe.h>
46 #include <krtld/reloc.h>
53 #define PROBE_MARKER_SYMBOL "__tnf_probe_version_1"
54 #define TAG_MARKER_SYMBOL "__tnf_tag_version_1"
56 extern int tnf_splice_probes(int, tnf_probe_control_t
*, tnf_tag_data_t
*);
59 * The kernel run-time linker calls this to try to resolve a reference
60 * it can't otherwise resolve. We see if it's marking a probe control
61 * block; if so, we do the resolution and return 0. If not, we return
62 * 1 to show that we can't resolve it, either.
65 tnf_reloc_resolve(char *symname
,
68 tnf_probe_control_t
**probelist
,
69 tnf_tag_data_t
**taglist
)
71 if (strcmp(symname
, PROBE_MARKER_SYMBOL
) == 0) {
72 ((tnf_probe_control_t
*)offset
)->next
= *probelist
;
73 *probelist
= (tnf_probe_control_t
*)offset
;
76 if (strcmp(symname
, TAG_MARKER_SYMBOL
) == 0) {
77 *value_p
= (Addr
)*taglist
;
78 *taglist
= (tnf_tag_data_t
*)offset
;
88 sdt_reloc_resolve(struct module
*mp
, char *symname
, uint8_t *instr
)
94 * The "statically defined tracing" (SDT) provider for DTrace uses
95 * a mechanism similar to TNF, but somewhat simpler. (Surprise,
96 * surprise.) The SDT mechanism works by replacing calls to the
97 * undefined routine __dtrace_probe_[name] with nop instructions.
98 * The relocations are logged, and SDT itself will later patch the
99 * running binary appropriately.
101 if (strncmp(symname
, sdt_prefix
, strlen(sdt_prefix
)) != 0)
104 symname
+= strlen(sdt_prefix
);
106 sdp
= kobj_alloc(sizeof (sdt_probedesc_t
), KM_WAIT
);
107 sdp
->sdpd_name
= kobj_alloc(strlen(symname
) + 1, KM_WAIT
);
108 bcopy(symname
, sdp
->sdpd_name
, strlen(symname
) + 1);
110 sdp
->sdpd_offset
= (uintptr_t)instr
;
111 sdp
->sdpd_next
= mp
->sdt_probes
;
112 mp
->sdt_probes
= sdp
;
114 for (i
= 0; i
< SDT_NOPS
; i
++)
115 instr
[i
- 1] = SDT_NOP
;
122 do_relocate(struct module
*mp
, char *reltbl
, Word relshtype
, int nreloc
,
123 int relocsize
, Addr baseaddr
)
126 unsigned long off
; /* can't be register for tnf_reloc_resolve() */
127 register unsigned long reladdr
, rend
;
128 register unsigned int rtype
;
132 tnf_probe_control_t
*probelist
= NULL
;
133 tnf_tag_data_t
*taglist
= NULL
;
136 reladdr
= (unsigned long)reltbl
;
137 rend
= reladdr
+ nreloc
* relocsize
;
140 if (kobj_debug
& D_RELOCATIONS
) {
141 _kobj_printf(ops
, "krtld:\ttype\t\t\toffset symbol\n");
142 _kobj_printf(ops
, "krtld:\t\t\t\t\t value\n");
147 /* loop through relocations */
148 while (reladdr
< rend
) {
150 rtype
= ELF32_R_TYPE(((Rel
*)reladdr
)->r_info
);
151 off
= ((Rel
*)reladdr
)->r_offset
;
152 stndx
= ELF32_R_SYM(((Rel
*)reladdr
)->r_info
);
153 if (stndx
>= mp
->nsyms
) {
154 _kobj_printf(ops
, "do_relocate: bad strndx %d\n",
158 if ((rtype
> R_386_NUM
) || IS_TLS_INS(rtype
)) {
159 _kobj_printf(ops
, "krtld: invalid relocation type %d",
161 _kobj_printf(ops
, " at 0x%llx:", off
);
162 _kobj_printf(ops
, " file=%s\n", mp
->filename
);
168 reladdr
+= relocsize
;
171 if (rtype
== R_386_NONE
)
175 if (kobj_debug
& D_RELOCATIONS
) {
178 (mp
->symtbl
+(stndx
* mp
->symhdr
->sh_entsize
));
179 _kobj_printf(ops
, "krtld:\t%s",
180 conv_reloc_386_type(rtype
));
181 _kobj_printf(ops
, "\t0x%8x", off
);
182 _kobj_printf(ops
, " %s\n",
183 (const char *)mp
->strings
+ symp
->st_name
);
187 if (!(mp
->flags
& KOBJ_EXEC
))
191 * if R_386_RELATIVE, simply add base addr
195 if (rtype
== R_386_RELATIVE
) {
199 * get symbol table entry - if symbol is local
200 * value is base address of this object
203 (mp
->symtbl
+(stndx
* mp
->symhdr
->sh_entsize
));
205 if (ELF32_ST_BIND(symref
->st_info
) == STB_LOCAL
) {
206 /* *** this is different for .o and .so */
207 value
= symref
->st_value
;
210 * It's global. Allow weak references. If
211 * the symbol is undefined, give TNF (the
212 * kernel probes facility) a chance to see
213 * if it's a probe site, and fix it up if so.
215 if (symref
->st_shndx
== SHN_UNDEF
&&
216 sdt_reloc_resolve(mp
, mp
->strings
+
217 symref
->st_name
, (uint8_t *)off
) == 0)
220 if (symref
->st_shndx
== SHN_UNDEF
&&
221 tnf_reloc_resolve(mp
->strings
+
222 symref
->st_name
, &symref
->st_value
,
223 off
, &probelist
, &taglist
) != 0) {
224 if (ELF32_ST_BIND(symref
->st_info
)
233 } else { /* symbol found - relocate */
235 * calculate location of definition
236 * - symbol value plus base address of
237 * containing shared object
239 value
= symref
->st_value
;
241 } /* end else symbol found */
242 } /* end global or weak */
243 } /* end not R_386_RELATIVE */
246 * calculate final value -
247 * if PC-relative, subtract ref addr
249 if (IS_PC_RELATIVE(rtype
))
253 if (kobj_debug
& D_RELOCATIONS
) {
254 _kobj_printf(ops
, "krtld:\t\t\t\t0x%8x", off
);
255 _kobj_printf(ops
, " 0x%8x\n", value
);
259 if (do_reloc_krtld(rtype
, (unsigned char *)off
, (Word
*)&value
,
260 (const char *)mp
->strings
+ symref
->st_name
,
264 } /* end of while loop */
268 if (tnf_splice_probes(mp
->flags
& KOBJ_PRIM
, probelist
, taglist
))
269 mp
->flags
|= KOBJ_TNF_PROBE
;
275 do_relocations(struct module
*mp
)
281 /* do the relocations */
282 for (shn
= 1; shn
< mp
->hdr
.e_shnum
; shn
++) {
284 (mp
->shdrs
+ shn
* mp
->hdr
.e_shentsize
);
285 if (rshp
->sh_type
== SHT_RELA
) {
286 _kobj_printf(ops
, "%s can't process type SHT_RELA\n",
290 if (rshp
->sh_type
!= SHT_REL
)
292 if (rshp
->sh_link
!= mp
->symtbl_section
) {
293 _kobj_printf(ops
, "%s reloc for non-default symtab\n",
297 if (rshp
->sh_info
>= mp
->hdr
.e_shnum
) {
298 _kobj_printf(ops
, "do_relocations: %s sh_info ",
300 _kobj_printf(ops
, "out of range %d\n", shn
);
303 nreloc
= rshp
->sh_size
/ rshp
->sh_entsize
;
305 /* get the section header that this reloc table refers to */
307 (mp
->shdrs
+ rshp
->sh_info
* mp
->hdr
.e_shentsize
);
310 * Do not relocate any section that isn't loaded into memory.
311 * Most commonly this will skip over the .rela.stab* sections
313 if (!(shp
->sh_flags
& SHF_ALLOC
))
316 if (kobj_debug
& D_RELOCATIONS
) {
317 _kobj_printf(ops
, "krtld: relocating: file=%s ",
319 _kobj_printf(ops
, "section=%d\n", shn
);
323 if (do_relocate(mp
, (char *)rshp
->sh_addr
, rshp
->sh_type
,
324 nreloc
, rshp
->sh_entsize
, shp
->sh_addr
) < 0) {
326 "do_relocations: %s do_relocate failed\n",
330 kobj_free((void *)rshp
->sh_addr
, rshp
->sh_size
);
333 mp
->flags
|= KOBJ_RELOCATED
;
336 kobj_free((void *)rshp
->sh_addr
, rshp
->sh_size
);