1 /* $NetBSD: headers.c,v 1.27 2009/01/06 04:01:46 mrg Exp $ */
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt@3am-software.com>
6 * Copyright 2002 Charles M. Hannum <root@ihack.net>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by John Polstra.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * Dynamic linker for ELF.
38 * John Polstra <jdp@polstra.com>.
41 #include <sys/cdefs.h>
43 __RCSID("$NetBSD: headers.c,v 1.27 2009/01/06 04:01:46 mrg Exp $");
54 #include <sys/types.h>
62 * Process a shared object's DYNAMIC section, and save the important
63 * information in its Obj_Entry structure.
66 _rtld_digest_dynamic(const char *execname
, Obj_Entry
*obj
)
69 Needed_Entry
**needed_tail
= &obj
->needed
;
70 const Elf_Dyn
*dyn_rpath
= NULL
;
71 Elf_Sword plttype
= DT_NULL
;
72 Elf_Addr relsz
= 0, relasz
= 0;
73 Elf_Addr pltrel
= 0, pltrelsz
= 0;
74 Elf_Addr init
= 0, fini
= 0;
76 for (dynp
= obj
->dynamic
; dynp
->d_tag
!= DT_NULL
; ++dynp
) {
77 switch (dynp
->d_tag
) {
80 obj
->rel
= (const Elf_Rel
*)
81 (obj
->relocbase
+ dynp
->d_un
.d_ptr
);
85 relsz
= dynp
->d_un
.d_val
;
89 assert(dynp
->d_un
.d_val
== sizeof(Elf_Rel
));
93 pltrel
= dynp
->d_un
.d_ptr
;
97 pltrelsz
= dynp
->d_un
.d_val
;
101 obj
->rela
= (const Elf_Rela
*)
102 (obj
->relocbase
+ dynp
->d_un
.d_ptr
);
106 relasz
= dynp
->d_un
.d_val
;
110 assert(dynp
->d_un
.d_val
== sizeof(Elf_Rela
));
114 plttype
= dynp
->d_un
.d_val
;
115 assert(plttype
== DT_REL
|| plttype
== DT_RELA
);
119 obj
->symtab
= (const Elf_Sym
*)
120 (obj
->relocbase
+ dynp
->d_un
.d_ptr
);
124 assert(dynp
->d_un
.d_val
== sizeof(Elf_Sym
));
128 obj
->strtab
= (const char *)
129 (obj
->relocbase
+ dynp
->d_un
.d_ptr
);
133 obj
->strsize
= dynp
->d_un
.d_val
;
138 const Elf_Word
*hashtab
= (const Elf_Word
*)
139 (obj
->relocbase
+ dynp
->d_un
.d_ptr
);
141 obj
->nbuckets
= hashtab
[0];
142 obj
->nchains
= hashtab
[1];
143 obj
->buckets
= hashtab
+ 2;
144 obj
->chains
= obj
->buckets
+ obj
->nbuckets
;
150 Needed_Entry
*nep
= NEW(Needed_Entry
);
152 nep
->name
= dynp
->d_un
.d_val
;
157 needed_tail
= &nep
->next
;
162 obj
->pltgot
= (Elf_Addr
*)
163 (obj
->relocbase
+ dynp
->d_un
.d_ptr
);
171 obj
->symbolic
= true;
176 * We have to wait until later to process this, because
177 * we might not have gotten the address of the string
184 /* Not used by the dynamic linker. */
188 init
= dynp
->d_un
.d_ptr
;
192 fini
= dynp
->d_un
.d_ptr
;
196 * Don't process DT_DEBUG on MIPS as the dynamic section
197 * is mapped read-only. DT_MIPS_RLD_MAP is used instead.
198 * XXX: n32/n64 may use DT_DEBUG, not sure yet.
203 dynp
->d_un
.d_ptr
= (Elf_Addr
)&_rtld_debug
;
209 case DT_MIPS_LOCAL_GOTNO
:
210 obj
->local_gotno
= dynp
->d_un
.d_val
;
213 case DT_MIPS_SYMTABNO
:
214 obj
->symtabno
= dynp
->d_un
.d_val
;
218 obj
->gotsym
= dynp
->d_un
.d_val
;
221 case DT_MIPS_RLD_MAP
:
223 *((Elf_Addr
*)(dynp
->d_un
.d_ptr
)) = (Elf_Addr
)
230 ((dynp
->d_un
.d_val
& DF_1_INITFIRST
) != 0);
235 obj
->rellim
= (const Elf_Rel
*)((const uint8_t *)obj
->rel
+ relsz
);
236 obj
->relalim
= (const Elf_Rela
*)((const uint8_t *)obj
->rela
+ relasz
);
237 if (plttype
== DT_REL
) {
238 obj
->pltrel
= (const Elf_Rel
*)(obj
->relocbase
+ pltrel
);
239 obj
->pltrellim
= (const Elf_Rel
*)(obj
->relocbase
+ pltrel
+ pltrelsz
);
241 /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
242 Trim rel(a)lim to save time later. */
243 if (obj
->rellim
&& obj
->pltrel
&&
244 obj
->rellim
> obj
->pltrel
&&
245 obj
->rellim
<= obj
->pltrellim
)
246 obj
->rellim
= obj
->pltrel
;
247 } else if (plttype
== DT_RELA
) {
248 obj
->pltrela
= (const Elf_Rela
*)(obj
->relocbase
+ pltrel
);
250 obj
->pltrelalim
= (const Elf_Rela
*)(obj
->relocbase
+ pltrel
+ pltrelsz
);
251 /* On PPC and SPARC, at least, REL(A)SZ may include JMPREL.
252 Trim rel(a)lim to save time later. */
253 if (obj
->relalim
&& obj
->pltrela
&&
254 obj
->relalim
> obj
->pltrela
&&
255 obj
->relalim
<= obj
->pltrelalim
)
256 obj
->relalim
= obj
->pltrela
;
259 #if defined(RTLD_LOADER) && defined(__HAVE_FUNCTION_DESCRIPTORS)
261 obj
->init
= (void (*)(void))
262 _rtld_function_descriptor_alloc(obj
, NULL
, init
);
264 obj
->fini
= (void (*)(void))
265 _rtld_function_descriptor_alloc(obj
, NULL
, fini
);
268 obj
->init
= (void (*)(void))
269 (obj
->relocbase
+ init
);
271 obj
->fini
= (void (*)(void))
272 (obj
->relocbase
+ fini
);
275 if (dyn_rpath
!= NULL
) {
276 _rtld_add_paths(execname
, &obj
->rpaths
, obj
->strtab
+
277 dyn_rpath
->d_un
.d_val
);
282 * Process a shared object's program header. This is used only for the
283 * main program, when the kernel has already loaded the main program
284 * into memory before calling the dynamic linker. It creates and
285 * returns an Obj_Entry structure.
288 _rtld_digest_phdr(const Elf_Phdr
*phdr
, int phnum
, caddr_t entry
)
291 const Elf_Phdr
*phlimit
= phdr
+ phnum
;
294 ptrdiff_t relocoffs
= 0;
297 obj
= _rtld_obj_new();
298 for (ph
= phdr
; ph
< phlimit
; ++ph
) {
299 vaddr
= ph
->p_vaddr
+ relocoffs
;
300 dbg(("headers: relocoffs = %lx\n", (long)relocoffs
));
301 switch (ph
->p_type
) {
304 relocoffs
= (uintptr_t)phdr
- (uintptr_t)ph
->p_vaddr
;
308 obj
->interp
= (const char *)(uintptr_t)vaddr
;
313 if (nsegs
== 0) { /* First load segment */
314 obj
->vaddrbase
= round_down(vaddr
);
315 obj
->mapbase
= (caddr_t
)(uintptr_t)obj
->vaddrbase
;
316 obj
->relocbase
= (void *)relocoffs
;
317 obj
->textsize
= round_up(vaddr
+ ph
->p_memsz
) -
319 } else { /* Last load segment */
320 obj
->mapsize
= round_up(vaddr
+ ph
->p_memsz
) -
327 obj
->dynamic
= (Elf_Dyn
*)(uintptr_t)vaddr
;