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 (c) 1988 AT&T
26 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
30 * SPARC machine dependent and a.out format file class dependent functions.
31 * Contains routines for performing function binding and symbol relocations.
35 #include <sys/types.h>
43 #include "_inline_gen.h"
46 extern void iflush_range(caddr_t
, size_t);
49 * Function binding routine - invoked on the first call to a function through
50 * the procedure linkage table;
51 * passes first through an assembly language interface.
53 * Takes the address of the PLT entry where the call originated,
54 * the offset into the relocation table of the associated
55 * relocation entry and the address of the link map (rt_private_map struct)
58 * Returns the address of the function referenced after re-writing the PLT
59 * entry to invoke the function directly.
61 * On error, causes process to terminate with a signal.
66 Rt_map
*lmp
, *nlmp
, *llmp
;
67 struct relocation_info
*rp
;
79 * For compatibility with libthread (TI_VERSION 1) we track the entry
80 * value. A zero value indicates we have recursed into ld.so.1 to
81 * further process a locking request (see comments in completion()).
82 * Under this recursion we disable tsort and cleanup activities.
86 for (lmp
= lml_main
.lm_head
; lmp
; lmp
= NEXT_RT_MAP(lmp
)) {
87 if (THIS_IS_AOUT(lmp
)) {
88 if (pc
> (caddr_t
)(LM2LP(lmp
)->lp_plt
) &&
89 pc
< (caddr_t
)((int)LM2LP(lmp
)->lp_plt
+
90 AOUTDYN(lmp
)->v2
->ld_plt_sz
)) {
96 #define LAST22BITS 0x3fffff
99 rndx
= *(int *)(pc
+ (sizeof (ulong_t
*) * 2)) & LAST22BITS
;
100 rp
= &LM2LP(lmp
)->lp_rp
[rndx
];
101 sp
= &LM2LP(lmp
)->lp_symtab
[rp
->r_symbolnum
];
102 name
= &LM2LP(lmp
)->lp_symstr
[sp
->n_un
.n_strx
];
105 * Determine the last link-map of this list, this'll be the starting
106 * point for any tsort() processing.
112 * Find definition for symbol. Initialize the symbol lookup data
115 SLOOKUP_INIT(sl
, name
, lmp
, lml
->lm_head
, ld_entry_cnt
, 0, 0, 0, 0,
117 SRESULT_INIT(sr
, name
);
119 if (aout_lookup_sym(&sl
, &sr
, &binfo
, NULL
) == 0) {
120 eprintf(lml
, ERR_FATAL
, MSG_INTL(MSG_REL_NOSYM
), NAME(lmp
),
125 name
= (char *)sr
.sr_name
;
129 symval
= sym
->st_value
;
131 if (!(FLAGS(nlmp
) & FLG_RT_FIXED
) &&
132 (sym
->st_shndx
!= SHN_ABS
))
133 symval
+= (int)(ADDR(nlmp
));
134 if ((lmp
!= nlmp
) && ((FLAGS1(nlmp
) & FL1_RT_NOINIFIN
) == 0)) {
136 * Record that this new link map is now bound to the caller.
138 if (bind_one(lmp
, nlmp
, BND_REFER
) == 0)
143 * Print binding information and rebuild PLT entry.
145 DBG_CALL(Dbg_bind_global(lmp
, (Addr
)(ADDR(lmp
) + rp
->r_address
),
146 (Off
)rp
->r_address
, (Xword
)(-1), PLT_T_NONE
, nlmp
,
147 (Addr
)symval
, sym
->st_value
, name
, binfo
));
149 if (!(rtld_flags
& RT_FL_NOBIND
))
150 aout_plt_write((caddr_t
)(ADDR(lmp
) + rp
->r_address
), symval
);
153 * Complete any processing for newly loaded objects. Note we don't
154 * know exactly where any new objects are loaded (we know the object
155 * that supplied the symbol, but others may have been loaded lazily as
156 * we searched for the symbol), so sorting starts from the last
157 * link-map know on entry to this routine.
160 load_completion(llmp
);
163 * Make sure the object to which we've bound has had it's .init fired.
164 * Cleanup before return to user code.
167 is_dep_init(nlmp
, lmp
);
175 #define IS_PC_RELATIVE(X) (pc_rel_type[(X)] == 1)
177 static const uchar_t pc_rel_type
[] = {
182 1, /* RELOC_DISP16 */
183 1, /* RELOC_DISP32 */
184 1, /* RELOC_WDISP30 */
185 1, /* RELOC_WDISP22 */
190 0, /* RELOC_SFA_BASE */
191 0, /* RELOC_SFA_OFF13 */
192 0, /* RELOC_BASE10 */
193 0, /* RELOC_BASE13 */
194 0, /* RELOC_BASE22 */
197 0, /* RELOC_JMP_TBL */
198 0, /* RELOC_SEGOFF16 */
199 0, /* RELOC_GLOB_DAT */
200 0, /* RELOC_JMP_SLOT */
201 0 /* RELOC_RELATIVE */
205 aout_reloc(Rt_map
*lmp
, uint_t plt
, int *in_nfavl
, APlist
**textrel
)
207 int k
; /* loop temporary */
208 int nr
; /* number of relocations */
209 char *name
; /* symbol being searched for */
210 long value
; /* relocation temporary */
211 long *ra
; /* cached relocation address */
212 struct relocation_info
*rp
; /* current relocation */
213 struct nlist
*sp
; /* symbol table of "symbol" */
214 Rt_map
* _lmp
; /* lm which holds symbol definition */
215 Sym
* sym
; /* symbol definition */
217 APlist
*bound
= NULL
;
218 Lm_list
*lml
= LIST(lmp
);
220 DBG_CALL(Dbg_reloc_run(lmp
, SHT_RELA
, plt
, DBG_REL_START
));
223 * If we've been called upon to promote an RTLD_LAZY object to an
224 * RTLD_NOW don't bother to do anything - a.out's are bound as if
225 * RTLD_NOW regardless.
230 rp
= LM2LP(lmp
)->lp_rp
;
231 nr
= GETRELSZ(AOUTDYN(lmp
)) / sizeof (struct relocation_info
);
234 * Initialize _PLT_, if any.
236 if (AOUTDYN(lmp
)->v2
->ld_plt_sz
)
237 aout_plt_write((caddr_t
)LM2LP(lmp
)->lp_plt
->jb_inst
,
238 (ulong_t
)aout_rtbndr
);
241 * Loop through relocations.
243 for (k
= 0; k
< nr
; k
++, rp
++) {
244 mmapobj_result_t
*mpp
;
247 ra
= (long *)&((char *)ADDR(lmp
))[rp
->r_address
];
250 * Make sure the segment is writable.
252 if (((mpp
= find_segment((caddr_t
)ra
, lmp
)) != NULL
) &&
253 ((mpp
->mr_prot
& PROT_WRITE
) == 0)) {
254 if ((set_prot(lmp
, mpp
, 1) == 0) ||
255 (aplist_append(textrel
, mpp
,
256 AL_CNT_TEXTREL
) == NULL
)) {
263 * Perform the relocation.
265 if (rp
->r_extern
== 0) {
273 if (rp
->r_type
== RELOC_JMP_SLOT
)
275 sp
= &LM2LP(lmp
)->lp_symtab
[rp
->r_symbolnum
];
276 name
= &LM2LP(lmp
)->lp_symstr
[sp
->n_un
.n_strx
];
279 * Locate symbol. Initialize the symbol lookup data
282 SLOOKUP_INIT(sl
, name
, lmp
, 0, ld_entry_cnt
,
283 0, 0, 0, 0, LKUP_STDRELOC
);
284 SRESULT_INIT(sr
, name
);
286 if (aout_lookup_sym(&sl
, &sr
, &binfo
, in_nfavl
) == 0) {
287 if (lml
->lm_flags
& LML_FLG_TRC_WARN
) {
289 printf(MSG_INTL(MSG_LDD_SYM_NFOUND
),
290 demangle(name
), NAME(lmp
));
293 eprintf(lml
, ERR_FATAL
,
294 MSG_INTL(MSG_REL_NOSYM
), NAME(lmp
),
302 * If symbol was found in an object other than the
303 * referencing object then record the binding.
305 name
= (char *)sr
.sr_name
;
310 ((FLAGS1(_lmp
) & FL1_RT_NOINIFIN
) == 0)) {
311 if (aplist_test(&bound
, _lmp
,
312 AL_CNT_RELBIND
) == 0) {
318 value
= sym
->st_value
+ rp
->r_addend
;
319 if (!(FLAGS(_lmp
) & FLG_RT_FIXED
) &&
320 (sym
->st_shndx
!= SHN_COMMON
) &&
321 (sym
->st_shndx
!= SHN_ABS
))
324 if (IS_PC_RELATIVE(rp
->r_type
))
325 value
-= (long)ADDR(lmp
);
327 DBG_CALL(Dbg_bind_global(lmp
, (Addr
)ra
,
328 (Off
)(ra
- ADDR(lmp
)), (Xword
)(-1), PLT_T_NONE
,
329 _lmp
, (Addr
)value
, sym
->st_value
, name
, binfo
));
333 * Perform a specific relocation operation.
335 switch (rp
->r_type
) {
337 value
+= *ra
<< (32-22);
338 *(long *)ra
= (*(long *)ra
& ~S_MASK(22)) |
339 ((value
>> (32 - 22)) & S_MASK(22));
341 value
+= (*ra
& S_MASK(10));
342 *(long *)ra
= (*(long *)ra
& ~S_MASK(10)) |
343 (value
& S_MASK(10));
347 value
+= *ra
& S_MASK(8);
348 if (!S_INRANGE(value
, 8)) {
349 eprintf(lml
, ERR_FATAL
,
350 MSG_INTL(MSG_REL_OVERFLOW
), NAME(lmp
),
351 (name
? demangle(name
) :
352 MSG_INTL(MSG_STR_UNKNOWN
)), (int)value
, 8,
359 value
+= *ra
& S_MASK(10);
360 *(long *)ra
= (*(long *)ra
& ~S_MASK(10)) |
361 (value
& S_MASK(10));
365 value
+= *ra
& S_MASK(13);
366 *(long *)ra
= (*(long *)ra
& ~S_MASK(13)) |
367 (value
& S_MASK(13));
371 value
+= *ra
& S_MASK(16);
372 if (!S_INRANGE(value
, 16)) {
373 eprintf(lml
, ERR_FATAL
,
374 MSG_INTL(MSG_REL_OVERFLOW
), NAME(lmp
),
375 (name
? demangle(name
) :
376 MSG_INTL(MSG_STR_UNKNOWN
)), (int)value
, 16,
379 *(short *)ra
= value
;
383 value
+= *ra
& S_MASK(22);
384 if (!S_INRANGE(value
, 22)) {
385 eprintf(lml
, ERR_FATAL
,
386 MSG_INTL(MSG_REL_OVERFLOW
), NAME(lmp
),
387 (name
? demangle(name
) :
388 MSG_INTL(MSG_STR_UNKNOWN
)), (int)value
, 22,
391 *(long *)ra
= (*(long *)ra
& ~S_MASK(22)) |
392 (value
& S_MASK(22));
395 value
+= (*ra
& S_MASK(22)) << (32 - 22);
396 *(long *)ra
= (*(long *)ra
& ~S_MASK(22)) |
397 ((value
>> (32 - 22)) & S_MASK(22));
400 value
+= *ra
& S_MASK(22);
402 if (!S_INRANGE(value
, 22)) {
403 eprintf(lml
, ERR_FATAL
,
404 MSG_INTL(MSG_REL_OVERFLOW
), NAME(lmp
),
405 (name
? demangle(name
) :
406 MSG_INTL(MSG_STR_UNKNOWN
)), (int)value
, 22,
409 *(long *)ra
= (*(long *)ra
& ~S_MASK(22)) |
410 (value
& S_MASK(22));
413 value
+= *ra
& S_MASK(30);
415 *(long *)ra
= (*(long *)ra
& ~S_MASK(30)) |
416 (value
& S_MASK(30));
425 eprintf(lml
, ERR_FATAL
, MSG_INTL(MSG_REL_UNIMPL
),
426 NAME(lmp
), (name
? demangle(name
) :
427 MSG_INTL(MSG_STR_UNKNOWN
)), rp
->r_type
);
433 * If this relocation is against a text segment we must make
434 * sure that the instruction cache is flushed.
437 if (rp
->r_type
== RELOC_RELATIVE
)
438 iflush_range((caddr_t
)(ra
- 1), 0x8);
440 iflush_range((caddr_t
)ra
, 0x4);
444 return (relocate_finish(lmp
, bound
, ret
));