map_object.c revision 1.63 1 1.63 christos /* $NetBSD: map_object.c,v 1.63 2023/01/06 15:33:47 christos Exp $ */
2 1.1 cgd
3 1.1 cgd /*
4 1.1 cgd * Copyright 1996 John D. Polstra.
5 1.1 cgd * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
6 1.24 mycroft * Copyright 2002 Charles M. Hannum <root (at) ihack.net>
7 1.1 cgd * All rights reserved.
8 1.1 cgd *
9 1.1 cgd * Redistribution and use in source and binary forms, with or without
10 1.1 cgd * modification, are permitted provided that the following conditions
11 1.1 cgd * are met:
12 1.1 cgd * 1. Redistributions of source code must retain the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer.
14 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 cgd * notice, this list of conditions and the following disclaimer in the
16 1.1 cgd * documentation and/or other materials provided with the distribution.
17 1.1 cgd * 3. All advertising materials mentioning features or use of this software
18 1.1 cgd * must display the following acknowledgement:
19 1.1 cgd * This product includes software developed by John Polstra.
20 1.1 cgd * 4. The name of the author may not be used to endorse or promote products
21 1.1 cgd * derived from this software without specific prior written permission.
22 1.1 cgd *
23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 1.1 cgd * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 1.1 cgd * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 1.1 cgd * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 1.1 cgd * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 1.1 cgd * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 1.1 cgd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 1.1 cgd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 1.1 cgd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 1.1 cgd * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 1.1 cgd */
34 1.1 cgd
35 1.31 skrll #include <sys/cdefs.h>
36 1.31 skrll #ifndef lint
37 1.63 christos __RCSID("$NetBSD: map_object.c,v 1.63 2023/01/06 15:33:47 christos Exp $");
38 1.31 skrll #endif /* not lint */
39 1.31 skrll
40 1.1 cgd #include <errno.h>
41 1.1 cgd #include <stddef.h>
42 1.10 mycroft #include <stdlib.h>
43 1.1 cgd #include <string.h>
44 1.1 cgd #include <unistd.h>
45 1.10 mycroft #include <sys/stat.h>
46 1.1 cgd #include <sys/types.h>
47 1.1 cgd #include <sys/mman.h>
48 1.1 cgd
49 1.41 skrll #include "debug.h"
50 1.1 cgd #include "rtld.h"
51 1.7 hannken
52 1.63 christos static int convert_prot(int); /* Elf flags -> mmap protection */
53 1.63 christos static int convert_flags(int); /* Elf flags -> mmap flags */
54 1.1 cgd
55 1.41 skrll #define EA_UNDEF (~(Elf_Addr)0)
56 1.41 skrll
57 1.1 cgd /*
58 1.1 cgd * Map a shared object into memory. The argument is a file descriptor,
59 1.1 cgd * which must be open on the object and positioned at its beginning.
60 1.1 cgd *
61 1.1 cgd * The return value is a pointer to a newly-allocated Obj_Entry structure
62 1.1 cgd * for the shared object. Returns NULL on failure.
63 1.1 cgd */
64 1.1 cgd Obj_Entry *
65 1.34 christos _rtld_map_object(const char *path, int fd, const struct stat *sb)
66 1.1 cgd {
67 1.18 junyoung Obj_Entry *obj;
68 1.18 junyoung Elf_Ehdr *ehdr;
69 1.18 junyoung Elf_Phdr *phdr;
70 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
71 1.42 joerg Elf_Phdr *phtls;
72 1.42 joerg #endif
73 1.18 junyoung Elf_Phdr *phlimit;
74 1.63 christos Elf_Phdr **segs = NULL;
75 1.18 junyoung int nsegs;
76 1.22 mycroft caddr_t mapbase = MAP_FAILED;
77 1.32 lukem size_t mapsize = 0;
78 1.27 matt int mapflags;
79 1.27 matt Elf_Addr base_alignment;
80 1.18 junyoung Elf_Addr base_vaddr;
81 1.18 junyoung Elf_Addr base_vlimit;
82 1.18 junyoung Elf_Addr text_vlimit;
83 1.63 christos Elf_Addr text_end;
84 1.60 joerg void *base_addr;
85 1.18 junyoung Elf_Off data_offset;
86 1.18 junyoung Elf_Addr data_vaddr;
87 1.18 junyoung Elf_Addr data_vlimit;
88 1.22 mycroft int data_flags;
89 1.63 christos int data_prot;
90 1.18 junyoung caddr_t data_addr;
91 1.63 christos Elf_Addr bss_vaddr;
92 1.63 christos Elf_Addr bss_vlimit;
93 1.63 christos caddr_t bss_addr;
94 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
95 1.42 joerg Elf_Addr tls_vaddr = 0; /* Noise GCC */
96 1.42 joerg #endif
97 1.41 skrll Elf_Addr phdr_vaddr;
98 1.41 skrll int i;
99 1.1 cgd #ifdef RTLD_LOADER
100 1.18 junyoung Elf_Addr clear_vaddr;
101 1.63 christos caddr_t clear_page;
102 1.18 junyoung caddr_t clear_addr;
103 1.18 junyoung size_t nclear;
104 1.1 cgd #endif
105 1.54 christos #ifdef GNU_RELRO
106 1.54 christos Elf_Addr relro_page;
107 1.54 christos size_t relro_size;
108 1.54 christos #endif
109 1.63 christos #ifdef notyet
110 1.63 christos int stack_flags;
111 1.63 christos #endif
112 1.26 fvdl
113 1.38 christos if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
114 1.45 dholland _rtld_error("%s: not ELF file (too short)", path);
115 1.26 fvdl return NULL;
116 1.26 fvdl }
117 1.1 cgd
118 1.22 mycroft obj = _rtld_obj_new();
119 1.34 christos obj->path = xstrdup(path);
120 1.25 junyoung obj->pathlen = strlen(path);
121 1.22 mycroft if (sb != NULL) {
122 1.22 mycroft obj->dev = sb->st_dev;
123 1.22 mycroft obj->ino = sb->st_ino;
124 1.22 mycroft }
125 1.22 mycroft
126 1.20 mycroft ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd,
127 1.16 mycroft (off_t)0);
128 1.36 ad obj->ehdr = ehdr;
129 1.20 mycroft if (ehdr == MAP_FAILED) {
130 1.4 christos _rtld_error("%s: read error: %s", path, xstrerror(errno));
131 1.63 christos goto error;
132 1.4 christos }
133 1.4 christos /* Make sure the file is valid */
134 1.45 dholland if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0) {
135 1.45 dholland _rtld_error("%s: not ELF file (magic number bad)", path);
136 1.63 christos goto error;
137 1.45 dholland }
138 1.45 dholland if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
139 1.45 dholland _rtld_error("%s: invalid ELF class %x; expected %x", path,
140 1.40 skrll ehdr->e_ident[EI_CLASS], ELFCLASS);
141 1.63 christos goto error;
142 1.4 christos }
143 1.4 christos /* Elf_e_ident includes class */
144 1.17 junyoung if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
145 1.17 junyoung ehdr->e_version != EV_CURRENT ||
146 1.17 junyoung ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
147 1.16 mycroft _rtld_error("%s: unsupported file version", path);
148 1.63 christos goto error;
149 1.16 mycroft }
150 1.17 junyoung if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
151 1.16 mycroft _rtld_error("%s: unsupported file type", path);
152 1.63 christos goto error;
153 1.4 christos }
154 1.17 junyoung switch (ehdr->e_machine) {
155 1.4 christos ELFDEFNNAME(MACHDEP_ID_CASES)
156 1.4 christos default:
157 1.16 mycroft _rtld_error("%s: unsupported machine", path);
158 1.63 christos goto error;
159 1.4 christos }
160 1.4 christos
161 1.4 christos /*
162 1.4 christos * We rely on the program header being in the first page. This is
163 1.4 christos * not strictly required by the ABI specification, but it seems to
164 1.4 christos * always true in practice. And, it simplifies things considerably.
165 1.4 christos */
166 1.17 junyoung assert(ehdr->e_phentsize == sizeof(Elf_Phdr));
167 1.19 junyoung assert(ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf_Phdr) <=
168 1.19 junyoung _rtld_pagesz);
169 1.4 christos
170 1.4 christos /*
171 1.4 christos * Scan the program header entries, and save key information.
172 1.4 christos *
173 1.4 christos * We rely on there being exactly two load segments, text and data,
174 1.4 christos * in that order.
175 1.4 christos */
176 1.17 junyoung phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
177 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
178 1.42 joerg phtls = NULL;
179 1.42 joerg #endif
180 1.41 skrll obj->phdr = NULL;
181 1.54 christos #ifdef GNU_RELRO
182 1.54 christos relro_page = 0;
183 1.54 christos relro_size = 0;
184 1.54 christos #endif
185 1.41 skrll phdr_vaddr = EA_UNDEF;
186 1.17 junyoung phlimit = phdr + ehdr->e_phnum;
187 1.63 christos segs = xmalloc(sizeof(segs[0]) * ehdr->e_phnum);
188 1.63 christos if (segs == NULL) {
189 1.63 christos _rtld_error("No memory for segs");
190 1.63 christos goto error;
191 1.63 christos }
192 1.63 christos #ifdef notyet
193 1.63 christos stack_flags = PF_R | PF_W;
194 1.63 christos #endif
195 1.63 christos nsegs = -1;
196 1.4 christos while (phdr < phlimit) {
197 1.4 christos switch (phdr->p_type) {
198 1.10 mycroft case PT_INTERP:
199 1.37 mrg obj->interp = (void *)(uintptr_t)phdr->p_vaddr;
200 1.41 skrll dbg(("%s: PT_INTERP %p", obj->path, obj->interp));
201 1.10 mycroft break;
202 1.1 cgd
203 1.8 kleink case PT_LOAD:
204 1.63 christos segs[++nsegs] = phdr;
205 1.63 christos if ((segs[nsegs]->p_align & (_rtld_pagesz - 1)) != 0) {
206 1.63 christos _rtld_error(
207 1.63 christos "%s: PT_LOAD segment %d not page-aligned",
208 1.63 christos path, nsegs);
209 1.63 christos goto error;
210 1.63 christos }
211 1.63 christos if ((segs[nsegs]->p_flags & PF_X) == PF_X) {
212 1.63 christos text_end = MAX(text_end,
213 1.63 christos round_up(segs[nsegs]->p_vaddr +
214 1.63 christos segs[nsegs]->p_memsz));
215 1.63 christos }
216 1.44 martin
217 1.63 christos dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
218 1.63 christos "PT_LOAD",
219 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
220 1.4 christos break;
221 1.4 christos
222 1.41 skrll case PT_PHDR:
223 1.41 skrll phdr_vaddr = phdr->p_vaddr;
224 1.63 christos dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
225 1.63 christos "PT_PHDR",
226 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
227 1.41 skrll break;
228 1.48 skrll
229 1.63 christos #ifdef notyet
230 1.63 christos case PT_GNU_STACK:
231 1.63 christos stack_flags = phdr->p_flags;
232 1.63 christos break;
233 1.63 christos #endif
234 1.63 christos
235 1.54 christos #ifdef GNU_RELRO
236 1.54 christos case PT_GNU_RELRO:
237 1.54 christos relro_page = phdr->p_vaddr;
238 1.54 christos relro_size = phdr->p_memsz;
239 1.54 christos break;
240 1.54 christos #endif
241 1.54 christos
242 1.8 kleink case PT_DYNAMIC:
243 1.37 mrg obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
244 1.63 christos dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
245 1.63 christos "PT_DYNAMIC",
246 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
247 1.4 christos break;
248 1.42 joerg
249 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
250 1.42 joerg case PT_TLS:
251 1.42 joerg phtls = phdr;
252 1.44 martin dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_TLS",
253 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
254 1.42 joerg break;
255 1.42 joerg #endif
256 1.46 skrll #ifdef __ARM_EABI__
257 1.46 skrll case PT_ARM_EXIDX:
258 1.46 skrll obj->exidx_start = (void *)(uintptr_t)phdr->p_vaddr;
259 1.46 skrll obj->exidx_sz = phdr->p_memsz;
260 1.46 skrll break;
261 1.46 skrll #endif
262 1.4 christos }
263 1.1 cgd
264 1.4 christos ++phdr;
265 1.4 christos }
266 1.41 skrll phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
267 1.37 mrg obj->entry = (void *)(uintptr_t)ehdr->e_entry;
268 1.22 mycroft if (!obj->dynamic) {
269 1.12 mycroft _rtld_error("%s: not dynamically linked", path);
270 1.63 christos goto error;
271 1.4 christos }
272 1.1 cgd
273 1.4 christos /*
274 1.11 chs * Map the entire address space of the object as a file
275 1.5 thorpej * region to stake out our contiguous region and establish a
276 1.11 chs * base for relocation. We use a file mapping so that
277 1.11 chs * the kernel will give us whatever alignment is appropriate
278 1.11 chs * for the platform we're running on.
279 1.5 thorpej *
280 1.11 chs * We map it using the text protection, map the data segment
281 1.11 chs * into the right place, then map an anon segment for the bss
282 1.11 chs * and unmap the gaps left by padding to alignment.
283 1.5 thorpej */
284 1.11 chs
285 1.27 matt base_alignment = segs[0]->p_align;
286 1.4 christos base_vaddr = round_down(segs[0]->p_vaddr);
287 1.63 christos base_vlimit = round_up(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz);
288 1.11 chs text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
289 1.63 christos data_offset = round_down(segs[nsegs]->p_offset);
290 1.63 christos data_vaddr = round_down(segs[nsegs]->p_vaddr);
291 1.63 christos data_vlimit = round_up(segs[nsegs]->p_vaddr + segs[nsegs]->p_filesz);
292 1.63 christos data_flags = convert_prot(segs[nsegs]->p_flags);
293 1.23 mycroft #ifdef RTLD_LOADER
294 1.63 christos clear_vaddr = segs[nsegs]->p_vaddr + segs[nsegs]->p_filesz;
295 1.23 mycroft #endif
296 1.22 mycroft
297 1.22 mycroft obj->textsize = text_vlimit - base_vaddr;
298 1.22 mycroft obj->vaddrbase = base_vaddr;
299 1.22 mycroft obj->isdynamic = ehdr->e_type == ET_DYN;
300 1.22 mycroft
301 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
302 1.42 joerg if (phtls != NULL) {
303 1.42 joerg ++_rtld_tls_dtv_generation;
304 1.42 joerg obj->tlsindex = ++_rtld_tls_max_index;
305 1.42 joerg obj->tlssize = phtls->p_memsz;
306 1.42 joerg obj->tlsalign = phtls->p_align;
307 1.42 joerg obj->tlsinitsize = phtls->p_filesz;
308 1.42 joerg tls_vaddr = phtls->p_vaddr;
309 1.42 joerg }
310 1.42 joerg #endif
311 1.42 joerg
312 1.27 matt /*
313 1.27 matt * Calculate log2 of the base section alignment.
314 1.27 matt */
315 1.63 christos mapflags = MAP_PRIVATE | MAP_ANON;
316 1.27 matt if (base_alignment > _rtld_pagesz) {
317 1.27 matt unsigned int log2 = 0;
318 1.27 matt for (; base_alignment > 1; base_alignment >>= 1)
319 1.27 matt log2++;
320 1.63 christos mapflags |= MAP_ALIGNED(log2);
321 1.27 matt }
322 1.27 matt
323 1.60 joerg base_addr = NULL;
324 1.1 cgd #ifdef RTLD_LOADER
325 1.60 joerg if (!obj->isdynamic) {
326 1.60 joerg mapflags |= MAP_TRYFIXED;
327 1.60 joerg base_addr = (void *)(uintptr_t)base_vaddr;
328 1.60 joerg }
329 1.1 cgd #endif
330 1.22 mycroft mapsize = base_vlimit - base_vaddr;
331 1.63 christos mapbase = mmap(base_addr, mapsize, PROT_NONE, mapflags, -1, 0);
332 1.5 thorpej if (mapbase == MAP_FAILED) {
333 1.4 christos _rtld_error("mmap of entire address space failed: %s",
334 1.4 christos xstrerror(errno));
335 1.63 christos goto error;
336 1.4 christos }
337 1.60 joerg #ifdef RTLD_LOADER
338 1.60 joerg if (!obj->isdynamic && mapbase != base_addr) {
339 1.60 joerg _rtld_error("mmap of executable at correct address failed");
340 1.63 christos goto error;
341 1.60 joerg }
342 1.60 joerg #endif
343 1.11 chs
344 1.63 christos for (i = 0; i <= nsegs; i++) {
345 1.63 christos /* Overlay the segment onto the proper region. */
346 1.63 christos data_offset = round_down(segs[i]->p_offset);
347 1.63 christos data_vaddr = round_down(segs[i]->p_vaddr);
348 1.63 christos data_vlimit = round_up(segs[i]->p_vaddr
349 1.63 christos + segs[i]->p_filesz);
350 1.63 christos data_addr = mapbase + (data_vaddr - base_vaddr);
351 1.63 christos data_prot = convert_prot(segs[i]->p_flags);
352 1.63 christos data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED;
353 1.63 christos if (data_vlimit != data_vaddr &&
354 1.63 christos mmap(data_addr, data_vlimit - data_vaddr, data_prot,
355 1.63 christos data_flags, fd, data_offset) == MAP_FAILED) {
356 1.63 christos _rtld_error("%s: mmap of data failed: %s", path,
357 1.63 christos xstrerror(errno));
358 1.63 christos goto error;
359 1.62 hannken }
360 1.5 thorpej
361 1.63 christos /* Do BSS setup */
362 1.63 christos if (segs[i]->p_filesz != segs[i]->p_memsz) {
363 1.1 cgd #ifdef RTLD_LOADER
364 1.63 christos /* Clear any BSS in the last page of the segment. */
365 1.63 christos clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz;
366 1.63 christos clear_addr = mapbase + (clear_vaddr - base_vaddr);
367 1.63 christos clear_page = mapbase + (round_down(clear_vaddr)
368 1.63 christos - base_vaddr);
369 1.63 christos
370 1.63 christos if ((nclear = data_vlimit - clear_vaddr) > 0) {
371 1.63 christos /* Make sure the end of the segment is writable
372 1.63 christos */
373 1.63 christos if ((data_prot & PROT_WRITE) == 0 && -1 ==
374 1.63 christos mprotect(clear_page, _rtld_pagesz,
375 1.63 christos data_prot|PROT_WRITE)) {
376 1.63 christos _rtld_error("%s: mprotect failed: %s",
377 1.63 christos path, xstrerror(errno));
378 1.63 christos goto error;
379 1.63 christos }
380 1.63 christos
381 1.63 christos memset(clear_addr, 0, nclear);
382 1.63 christos
383 1.63 christos /* Reset the data protection back */
384 1.63 christos if ((data_prot & PROT_WRITE) == 0)
385 1.63 christos mprotect(clear_page, _rtld_pagesz,
386 1.63 christos data_prot);
387 1.63 christos }
388 1.63 christos #endif
389 1.63 christos
390 1.63 christos /* Overlay the BSS segment onto the proper region. */
391 1.63 christos bss_vaddr = data_vlimit;
392 1.63 christos bss_vlimit = round_up(segs[i]->p_vaddr +
393 1.63 christos segs[i]->p_memsz);
394 1.63 christos bss_addr = mapbase + (bss_vaddr - base_vaddr);
395 1.63 christos if (bss_vlimit > bss_vaddr) {
396 1.63 christos /* There is something to do */
397 1.63 christos if (mmap(bss_addr, bss_vlimit - bss_vaddr,
398 1.63 christos data_prot, data_flags | MAP_ANON, -1, 0)
399 1.63 christos == MAP_FAILED) {
400 1.63 christos _rtld_error(
401 1.63 christos "%s: mmap of bss failed: %s",
402 1.63 christos path, xstrerror(errno));
403 1.63 christos goto error;
404 1.63 christos }
405 1.63 christos }
406 1.63 christos }
407 1.4 christos
408 1.63 christos if (phdr_vaddr == 0 && data_offset <= ehdr->e_phoff &&
409 1.63 christos (data_vlimit - data_vaddr + data_offset) >=
410 1.63 christos (ehdr->e_phoff + ehdr->e_phnum * sizeof (Elf_Phdr))) {
411 1.63 christos phdr_vaddr = data_vaddr + ehdr->e_phoff - data_offset;
412 1.63 christos }
413 1.63 christos }
414 1.1 cgd
415 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
416 1.42 joerg if (phtls != NULL)
417 1.42 joerg obj->tlsinit = mapbase + tls_vaddr;
418 1.42 joerg #endif
419 1.42 joerg
420 1.4 christos obj->mapbase = mapbase;
421 1.4 christos obj->mapsize = mapsize;
422 1.4 christos obj->relocbase = mapbase - base_vaddr;
423 1.10 mycroft
424 1.55 christos #ifdef GNU_RELRO
425 1.61 thorpej /* rounding happens later. */
426 1.61 thorpej obj->relro_page = obj->relocbase + relro_page;
427 1.61 thorpej obj->relro_size = relro_size;
428 1.55 christos #endif
429 1.55 christos
430 1.22 mycroft if (obj->dynamic)
431 1.37 mrg obj->dynamic = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->dynamic);
432 1.22 mycroft if (obj->entry)
433 1.37 mrg obj->entry = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->entry);
434 1.22 mycroft if (obj->interp)
435 1.37 mrg obj->interp = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->interp);
436 1.41 skrll if (obj->phdr_loaded)
437 1.41 skrll obj->phdr = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->phdr);
438 1.47 skrll #ifdef __ARM_EABI__
439 1.47 skrll if (obj->exidx_start)
440 1.47 skrll obj->exidx_start = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->exidx_start);
441 1.47 skrll #endif
442 1.63 christos xfree(segs);
443 1.22 mycroft
444 1.10 mycroft return obj;
445 1.16 mycroft
446 1.63 christos error:
447 1.63 christos if (mapbase != MAP_FAILED)
448 1.63 christos munmap(mapbase, mapsize);
449 1.36 ad if (obj->ehdr != MAP_FAILED)
450 1.36 ad munmap(obj->ehdr, _rtld_pagesz);
451 1.22 mycroft _rtld_obj_free(obj);
452 1.63 christos xfree(segs);
453 1.16 mycroft return NULL;
454 1.10 mycroft }
455 1.10 mycroft
456 1.10 mycroft void
457 1.30 skrll _rtld_obj_free(Obj_Entry *obj)
458 1.10 mycroft {
459 1.10 mycroft Objlist_Entry *elm;
460 1.51 christos Name_Entry *entry;
461 1.10 mycroft
462 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
463 1.42 joerg if (obj->tls_done)
464 1.42 joerg _rtld_tls_offset_free(obj);
465 1.42 joerg #endif
466 1.35 ad xfree(obj->path);
467 1.10 mycroft while (obj->needed != NULL) {
468 1.10 mycroft Needed_Entry *needed = obj->needed;
469 1.10 mycroft obj->needed = needed->next;
470 1.35 ad xfree(needed);
471 1.10 mycroft }
472 1.51 christos while ((entry = SIMPLEQ_FIRST(&obj->names)) != NULL) {
473 1.51 christos SIMPLEQ_REMOVE_HEAD(&obj->names, link);
474 1.50 christos xfree(entry);
475 1.49 christos }
476 1.13 lukem while ((elm = SIMPLEQ_FIRST(&obj->dldags)) != NULL) {
477 1.13 lukem SIMPLEQ_REMOVE_HEAD(&obj->dldags, link);
478 1.35 ad xfree(elm);
479 1.10 mycroft }
480 1.13 lukem while ((elm = SIMPLEQ_FIRST(&obj->dagmembers)) != NULL) {
481 1.13 lukem SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, link);
482 1.35 ad xfree(elm);
483 1.10 mycroft }
484 1.41 skrll if (!obj->phdr_loaded)
485 1.41 skrll xfree((void *)(uintptr_t)obj->phdr);
486 1.53 martin xfree(obj);
487 1.10 mycroft }
488 1.10 mycroft
489 1.10 mycroft Obj_Entry *
490 1.10 mycroft _rtld_obj_new(void)
491 1.10 mycroft {
492 1.10 mycroft Obj_Entry *obj;
493 1.10 mycroft
494 1.10 mycroft obj = CNEW(Obj_Entry);
495 1.51 christos SIMPLEQ_INIT(&obj->names);
496 1.10 mycroft SIMPLEQ_INIT(&obj->dldags);
497 1.10 mycroft SIMPLEQ_INIT(&obj->dagmembers);
498 1.4 christos return obj;
499 1.1 cgd }
500 1.1 cgd
501 1.1 cgd /*
502 1.1 cgd * Given a set of ELF protection flags, return the corresponding protection
503 1.1 cgd * flags for MMAP.
504 1.1 cgd */
505 1.1 cgd static int
506 1.63 christos convert_prot(int elfflags)
507 1.1 cgd {
508 1.4 christos int prot = 0;
509 1.29 simonb
510 1.8 kleink if (elfflags & PF_R)
511 1.4 christos prot |= PROT_READ;
512 1.1 cgd #ifdef RTLD_LOADER
513 1.8 kleink if (elfflags & PF_W)
514 1.4 christos prot |= PROT_WRITE;
515 1.1 cgd #endif
516 1.8 kleink if (elfflags & PF_X)
517 1.4 christos prot |= PROT_EXEC;
518 1.4 christos return prot;
519 1.1 cgd }
520 1.63 christos
521 1.63 christos static int
522 1.63 christos convert_flags(int elfflags __unused)
523 1.63 christos {
524 1.63 christos int flags = MAP_PRIVATE; /* All mappings are private */
525 1.63 christos
526 1.63 christos #ifdef MAP_NOCORE
527 1.63 christos /*
528 1.63 christos * Readonly mappings are marked "MAP_NOCORE", because they can be
529 1.63 christos * reconstructed by a debugger.
530 1.63 christos */
531 1.63 christos if (!(elfflags & PF_W))
532 1.63 christos flags |= MAP_NOCORE;
533 1.63 christos #endif
534 1.63 christos return flags;
535 1.63 christos }
536