map_object.c revision 1.64 1 1.64 christos /* $NetBSD: map_object.c,v 1.64 2023/01/12 18:52: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.64 christos __RCSID("$NetBSD: map_object.c,v 1.64 2023/01/12 18:52: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.64 christos size_t phdr_memsz;
99 1.41 skrll int i;
100 1.1 cgd #ifdef RTLD_LOADER
101 1.18 junyoung Elf_Addr clear_vaddr;
102 1.63 christos caddr_t clear_page;
103 1.18 junyoung caddr_t clear_addr;
104 1.64 christos size_t nclear, phsize;
105 1.1 cgd #endif
106 1.54 christos #ifdef GNU_RELRO
107 1.54 christos Elf_Addr relro_page;
108 1.54 christos size_t relro_size;
109 1.54 christos #endif
110 1.63 christos #ifdef notyet
111 1.63 christos int stack_flags;
112 1.63 christos #endif
113 1.26 fvdl
114 1.38 christos if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
115 1.45 dholland _rtld_error("%s: not ELF file (too short)", path);
116 1.26 fvdl return NULL;
117 1.26 fvdl }
118 1.1 cgd
119 1.22 mycroft obj = _rtld_obj_new();
120 1.34 christos obj->path = xstrdup(path);
121 1.25 junyoung obj->pathlen = strlen(path);
122 1.22 mycroft if (sb != NULL) {
123 1.22 mycroft obj->dev = sb->st_dev;
124 1.22 mycroft obj->ino = sb->st_ino;
125 1.22 mycroft }
126 1.22 mycroft
127 1.20 mycroft ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd,
128 1.16 mycroft (off_t)0);
129 1.36 ad obj->ehdr = ehdr;
130 1.20 mycroft if (ehdr == MAP_FAILED) {
131 1.4 christos _rtld_error("%s: read error: %s", path, xstrerror(errno));
132 1.63 christos goto error;
133 1.4 christos }
134 1.4 christos /* Make sure the file is valid */
135 1.45 dholland if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0) {
136 1.45 dholland _rtld_error("%s: not ELF file (magic number bad)", path);
137 1.63 christos goto error;
138 1.45 dholland }
139 1.45 dholland if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
140 1.45 dholland _rtld_error("%s: invalid ELF class %x; expected %x", path,
141 1.40 skrll ehdr->e_ident[EI_CLASS], ELFCLASS);
142 1.63 christos goto error;
143 1.4 christos }
144 1.4 christos /* Elf_e_ident includes class */
145 1.17 junyoung if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
146 1.17 junyoung ehdr->e_version != EV_CURRENT ||
147 1.17 junyoung ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
148 1.16 mycroft _rtld_error("%s: unsupported file version", path);
149 1.63 christos goto error;
150 1.16 mycroft }
151 1.17 junyoung if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
152 1.16 mycroft _rtld_error("%s: unsupported file type", path);
153 1.63 christos goto error;
154 1.4 christos }
155 1.17 junyoung switch (ehdr->e_machine) {
156 1.4 christos ELFDEFNNAME(MACHDEP_ID_CASES)
157 1.4 christos default:
158 1.16 mycroft _rtld_error("%s: unsupported machine", path);
159 1.63 christos goto error;
160 1.4 christos }
161 1.4 christos
162 1.4 christos /*
163 1.4 christos * We rely on the program header being in the first page. This is
164 1.4 christos * not strictly required by the ABI specification, but it seems to
165 1.4 christos * always true in practice. And, it simplifies things considerably.
166 1.4 christos */
167 1.17 junyoung assert(ehdr->e_phentsize == sizeof(Elf_Phdr));
168 1.19 junyoung assert(ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf_Phdr) <=
169 1.19 junyoung _rtld_pagesz);
170 1.4 christos
171 1.4 christos /*
172 1.4 christos * Scan the program header entries, and save key information.
173 1.4 christos *
174 1.4 christos * We rely on there being exactly two load segments, text and data,
175 1.4 christos * in that order.
176 1.4 christos */
177 1.17 junyoung phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
178 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
179 1.42 joerg phtls = NULL;
180 1.42 joerg #endif
181 1.64 christos phsize = ehdr->e_phnum * sizeof(phdr[0]);
182 1.41 skrll obj->phdr = NULL;
183 1.54 christos #ifdef GNU_RELRO
184 1.54 christos relro_page = 0;
185 1.54 christos relro_size = 0;
186 1.54 christos #endif
187 1.41 skrll phdr_vaddr = EA_UNDEF;
188 1.64 christos phdr_memsz = 0;
189 1.17 junyoung phlimit = phdr + ehdr->e_phnum;
190 1.63 christos segs = xmalloc(sizeof(segs[0]) * ehdr->e_phnum);
191 1.63 christos if (segs == NULL) {
192 1.63 christos _rtld_error("No memory for segs");
193 1.63 christos goto error;
194 1.63 christos }
195 1.63 christos #ifdef notyet
196 1.63 christos stack_flags = PF_R | PF_W;
197 1.63 christos #endif
198 1.63 christos nsegs = -1;
199 1.4 christos while (phdr < phlimit) {
200 1.4 christos switch (phdr->p_type) {
201 1.10 mycroft case PT_INTERP:
202 1.37 mrg obj->interp = (void *)(uintptr_t)phdr->p_vaddr;
203 1.41 skrll dbg(("%s: PT_INTERP %p", obj->path, obj->interp));
204 1.10 mycroft break;
205 1.1 cgd
206 1.8 kleink case PT_LOAD:
207 1.63 christos segs[++nsegs] = phdr;
208 1.63 christos if ((segs[nsegs]->p_align & (_rtld_pagesz - 1)) != 0) {
209 1.63 christos _rtld_error(
210 1.63 christos "%s: PT_LOAD segment %d not page-aligned",
211 1.63 christos path, nsegs);
212 1.63 christos goto error;
213 1.63 christos }
214 1.63 christos if ((segs[nsegs]->p_flags & PF_X) == PF_X) {
215 1.63 christos text_end = MAX(text_end,
216 1.63 christos round_up(segs[nsegs]->p_vaddr +
217 1.63 christos segs[nsegs]->p_memsz));
218 1.63 christos }
219 1.44 martin
220 1.63 christos dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
221 1.63 christos "PT_LOAD",
222 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
223 1.4 christos break;
224 1.4 christos
225 1.41 skrll case PT_PHDR:
226 1.41 skrll phdr_vaddr = phdr->p_vaddr;
227 1.64 christos phdr_memsz = phdr->p_memsz;
228 1.63 christos dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
229 1.63 christos "PT_PHDR",
230 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
231 1.41 skrll break;
232 1.48 skrll
233 1.63 christos #ifdef notyet
234 1.63 christos case PT_GNU_STACK:
235 1.63 christos stack_flags = phdr->p_flags;
236 1.63 christos break;
237 1.63 christos #endif
238 1.63 christos
239 1.54 christos #ifdef GNU_RELRO
240 1.54 christos case PT_GNU_RELRO:
241 1.54 christos relro_page = phdr->p_vaddr;
242 1.54 christos relro_size = phdr->p_memsz;
243 1.54 christos break;
244 1.54 christos #endif
245 1.54 christos
246 1.8 kleink case PT_DYNAMIC:
247 1.37 mrg obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
248 1.63 christos dbg(("%s: %s %p phsize %" PRImemsz, obj->path,
249 1.63 christos "PT_DYNAMIC",
250 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
251 1.4 christos break;
252 1.42 joerg
253 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
254 1.42 joerg case PT_TLS:
255 1.42 joerg phtls = phdr;
256 1.44 martin dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_TLS",
257 1.43 christos (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
258 1.42 joerg break;
259 1.42 joerg #endif
260 1.46 skrll #ifdef __ARM_EABI__
261 1.46 skrll case PT_ARM_EXIDX:
262 1.46 skrll obj->exidx_start = (void *)(uintptr_t)phdr->p_vaddr;
263 1.46 skrll obj->exidx_sz = phdr->p_memsz;
264 1.46 skrll break;
265 1.46 skrll #endif
266 1.4 christos }
267 1.1 cgd
268 1.4 christos ++phdr;
269 1.4 christos }
270 1.41 skrll phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
271 1.37 mrg obj->entry = (void *)(uintptr_t)ehdr->e_entry;
272 1.22 mycroft if (!obj->dynamic) {
273 1.12 mycroft _rtld_error("%s: not dynamically linked", path);
274 1.63 christos goto error;
275 1.4 christos }
276 1.1 cgd
277 1.4 christos /*
278 1.11 chs * Map the entire address space of the object as a file
279 1.5 thorpej * region to stake out our contiguous region and establish a
280 1.11 chs * base for relocation. We use a file mapping so that
281 1.11 chs * the kernel will give us whatever alignment is appropriate
282 1.11 chs * for the platform we're running on.
283 1.5 thorpej *
284 1.11 chs * We map it using the text protection, map the data segment
285 1.11 chs * into the right place, then map an anon segment for the bss
286 1.11 chs * and unmap the gaps left by padding to alignment.
287 1.5 thorpej */
288 1.11 chs
289 1.27 matt base_alignment = segs[0]->p_align;
290 1.4 christos base_vaddr = round_down(segs[0]->p_vaddr);
291 1.63 christos base_vlimit = round_up(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz);
292 1.11 chs text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
293 1.63 christos data_offset = round_down(segs[nsegs]->p_offset);
294 1.63 christos data_vaddr = round_down(segs[nsegs]->p_vaddr);
295 1.63 christos data_vlimit = round_up(segs[nsegs]->p_vaddr + segs[nsegs]->p_filesz);
296 1.63 christos data_flags = convert_prot(segs[nsegs]->p_flags);
297 1.23 mycroft #ifdef RTLD_LOADER
298 1.63 christos clear_vaddr = segs[nsegs]->p_vaddr + segs[nsegs]->p_filesz;
299 1.23 mycroft #endif
300 1.22 mycroft
301 1.22 mycroft obj->textsize = text_vlimit - base_vaddr;
302 1.22 mycroft obj->vaddrbase = base_vaddr;
303 1.22 mycroft obj->isdynamic = ehdr->e_type == ET_DYN;
304 1.22 mycroft
305 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
306 1.42 joerg if (phtls != NULL) {
307 1.42 joerg ++_rtld_tls_dtv_generation;
308 1.42 joerg obj->tlsindex = ++_rtld_tls_max_index;
309 1.42 joerg obj->tlssize = phtls->p_memsz;
310 1.42 joerg obj->tlsalign = phtls->p_align;
311 1.42 joerg obj->tlsinitsize = phtls->p_filesz;
312 1.42 joerg tls_vaddr = phtls->p_vaddr;
313 1.42 joerg }
314 1.42 joerg #endif
315 1.42 joerg
316 1.27 matt /*
317 1.27 matt * Calculate log2 of the base section alignment.
318 1.27 matt */
319 1.63 christos mapflags = MAP_PRIVATE | MAP_ANON;
320 1.27 matt if (base_alignment > _rtld_pagesz) {
321 1.27 matt unsigned int log2 = 0;
322 1.27 matt for (; base_alignment > 1; base_alignment >>= 1)
323 1.27 matt log2++;
324 1.63 christos mapflags |= MAP_ALIGNED(log2);
325 1.27 matt }
326 1.27 matt
327 1.60 joerg base_addr = NULL;
328 1.1 cgd #ifdef RTLD_LOADER
329 1.60 joerg if (!obj->isdynamic) {
330 1.60 joerg mapflags |= MAP_TRYFIXED;
331 1.60 joerg base_addr = (void *)(uintptr_t)base_vaddr;
332 1.60 joerg }
333 1.1 cgd #endif
334 1.22 mycroft mapsize = base_vlimit - base_vaddr;
335 1.63 christos mapbase = mmap(base_addr, mapsize, PROT_NONE, mapflags, -1, 0);
336 1.5 thorpej if (mapbase == MAP_FAILED) {
337 1.4 christos _rtld_error("mmap of entire address space failed: %s",
338 1.4 christos xstrerror(errno));
339 1.63 christos goto error;
340 1.4 christos }
341 1.60 joerg #ifdef RTLD_LOADER
342 1.60 joerg if (!obj->isdynamic && mapbase != base_addr) {
343 1.60 joerg _rtld_error("mmap of executable at correct address failed");
344 1.63 christos goto error;
345 1.60 joerg }
346 1.60 joerg #endif
347 1.11 chs
348 1.64 christos obj->phdr_loaded = false;
349 1.63 christos for (i = 0; i <= nsegs; i++) {
350 1.63 christos /* Overlay the segment onto the proper region. */
351 1.63 christos data_offset = round_down(segs[i]->p_offset);
352 1.63 christos data_vaddr = round_down(segs[i]->p_vaddr);
353 1.63 christos data_vlimit = round_up(segs[i]->p_vaddr
354 1.63 christos + segs[i]->p_filesz);
355 1.63 christos data_addr = mapbase + (data_vaddr - base_vaddr);
356 1.63 christos data_prot = convert_prot(segs[i]->p_flags);
357 1.63 christos data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED;
358 1.63 christos if (data_vlimit != data_vaddr &&
359 1.63 christos mmap(data_addr, data_vlimit - data_vaddr, data_prot,
360 1.63 christos data_flags, fd, data_offset) == MAP_FAILED) {
361 1.63 christos _rtld_error("%s: mmap of data failed: %s", path,
362 1.63 christos xstrerror(errno));
363 1.63 christos goto error;
364 1.62 hannken }
365 1.5 thorpej
366 1.63 christos /* Do BSS setup */
367 1.63 christos if (segs[i]->p_filesz != segs[i]->p_memsz) {
368 1.1 cgd #ifdef RTLD_LOADER
369 1.63 christos /* Clear any BSS in the last page of the segment. */
370 1.63 christos clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz;
371 1.63 christos clear_addr = mapbase + (clear_vaddr - base_vaddr);
372 1.63 christos clear_page = mapbase + (round_down(clear_vaddr)
373 1.63 christos - base_vaddr);
374 1.63 christos
375 1.63 christos if ((nclear = data_vlimit - clear_vaddr) > 0) {
376 1.63 christos /* Make sure the end of the segment is writable
377 1.63 christos */
378 1.63 christos if ((data_prot & PROT_WRITE) == 0 && -1 ==
379 1.63 christos mprotect(clear_page, _rtld_pagesz,
380 1.63 christos data_prot|PROT_WRITE)) {
381 1.63 christos _rtld_error("%s: mprotect failed: %s",
382 1.63 christos path, xstrerror(errno));
383 1.63 christos goto error;
384 1.63 christos }
385 1.63 christos
386 1.63 christos memset(clear_addr, 0, nclear);
387 1.63 christos
388 1.63 christos /* Reset the data protection back */
389 1.63 christos if ((data_prot & PROT_WRITE) == 0)
390 1.63 christos mprotect(clear_page, _rtld_pagesz,
391 1.63 christos data_prot);
392 1.63 christos }
393 1.63 christos #endif
394 1.63 christos
395 1.63 christos /* Overlay the BSS segment onto the proper region. */
396 1.63 christos bss_vaddr = data_vlimit;
397 1.63 christos bss_vlimit = round_up(segs[i]->p_vaddr +
398 1.63 christos segs[i]->p_memsz);
399 1.63 christos bss_addr = mapbase + (bss_vaddr - base_vaddr);
400 1.63 christos if (bss_vlimit > bss_vaddr) {
401 1.63 christos /* There is something to do */
402 1.63 christos if (mmap(bss_addr, bss_vlimit - bss_vaddr,
403 1.63 christos data_prot, data_flags | MAP_ANON, -1, 0)
404 1.63 christos == MAP_FAILED) {
405 1.63 christos _rtld_error(
406 1.63 christos "%s: mmap of bss failed: %s",
407 1.63 christos path, xstrerror(errno));
408 1.63 christos goto error;
409 1.63 christos }
410 1.63 christos }
411 1.63 christos }
412 1.4 christos
413 1.64 christos if (phdr_vaddr != EA_UNDEF &&
414 1.64 christos segs[i]->p_vaddr <= phdr_vaddr &&
415 1.64 christos segs[i]->p_memsz >= phdr_memsz) {
416 1.64 christos obj->phdr_loaded = true;
417 1.63 christos }
418 1.64 christos if (segs[i]->p_offset <= ehdr->e_phoff &&
419 1.64 christos segs[i]->p_memsz >= phsize) {
420 1.64 christos phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff;
421 1.64 christos phdr_memsz = phsize;
422 1.64 christos obj->phdr_loaded = true;
423 1.64 christos }
424 1.64 christos }
425 1.64 christos if (obj->phdr_loaded) {
426 1.64 christos obj->phdr = (void *)(uintptr_t)phdr_vaddr;
427 1.64 christos obj->phsize = phdr_memsz;
428 1.64 christos } else {
429 1.64 christos Elf_Phdr *buf = xmalloc(phsize);
430 1.64 christos if (buf == NULL) {
431 1.64 christos _rtld_error("%s: cannot allocate program header", path);
432 1.64 christos goto error;
433 1.64 christos }
434 1.64 christos memcpy(buf, phdr, phsize);
435 1.64 christos obj->phdr = buf;
436 1.64 christos obj->phsize = phsize;
437 1.63 christos }
438 1.1 cgd
439 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
440 1.42 joerg if (phtls != NULL)
441 1.42 joerg obj->tlsinit = mapbase + tls_vaddr;
442 1.42 joerg #endif
443 1.42 joerg
444 1.4 christos obj->mapbase = mapbase;
445 1.4 christos obj->mapsize = mapsize;
446 1.4 christos obj->relocbase = mapbase - base_vaddr;
447 1.10 mycroft
448 1.55 christos #ifdef GNU_RELRO
449 1.61 thorpej /* rounding happens later. */
450 1.61 thorpej obj->relro_page = obj->relocbase + relro_page;
451 1.61 thorpej obj->relro_size = relro_size;
452 1.55 christos #endif
453 1.55 christos
454 1.22 mycroft if (obj->dynamic)
455 1.37 mrg obj->dynamic = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->dynamic);
456 1.22 mycroft if (obj->entry)
457 1.37 mrg obj->entry = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->entry);
458 1.22 mycroft if (obj->interp)
459 1.37 mrg obj->interp = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->interp);
460 1.41 skrll if (obj->phdr_loaded)
461 1.41 skrll obj->phdr = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->phdr);
462 1.47 skrll #ifdef __ARM_EABI__
463 1.47 skrll if (obj->exidx_start)
464 1.47 skrll obj->exidx_start = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->exidx_start);
465 1.47 skrll #endif
466 1.63 christos xfree(segs);
467 1.22 mycroft
468 1.10 mycroft return obj;
469 1.16 mycroft
470 1.63 christos error:
471 1.63 christos if (mapbase != MAP_FAILED)
472 1.63 christos munmap(mapbase, mapsize);
473 1.36 ad if (obj->ehdr != MAP_FAILED)
474 1.36 ad munmap(obj->ehdr, _rtld_pagesz);
475 1.22 mycroft _rtld_obj_free(obj);
476 1.63 christos xfree(segs);
477 1.16 mycroft return NULL;
478 1.10 mycroft }
479 1.10 mycroft
480 1.10 mycroft void
481 1.30 skrll _rtld_obj_free(Obj_Entry *obj)
482 1.10 mycroft {
483 1.10 mycroft Objlist_Entry *elm;
484 1.51 christos Name_Entry *entry;
485 1.10 mycroft
486 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
487 1.42 joerg if (obj->tls_done)
488 1.42 joerg _rtld_tls_offset_free(obj);
489 1.42 joerg #endif
490 1.35 ad xfree(obj->path);
491 1.10 mycroft while (obj->needed != NULL) {
492 1.10 mycroft Needed_Entry *needed = obj->needed;
493 1.10 mycroft obj->needed = needed->next;
494 1.35 ad xfree(needed);
495 1.10 mycroft }
496 1.51 christos while ((entry = SIMPLEQ_FIRST(&obj->names)) != NULL) {
497 1.51 christos SIMPLEQ_REMOVE_HEAD(&obj->names, link);
498 1.50 christos xfree(entry);
499 1.49 christos }
500 1.13 lukem while ((elm = SIMPLEQ_FIRST(&obj->dldags)) != NULL) {
501 1.13 lukem SIMPLEQ_REMOVE_HEAD(&obj->dldags, link);
502 1.35 ad xfree(elm);
503 1.10 mycroft }
504 1.13 lukem while ((elm = SIMPLEQ_FIRST(&obj->dagmembers)) != NULL) {
505 1.13 lukem SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, link);
506 1.35 ad xfree(elm);
507 1.10 mycroft }
508 1.41 skrll if (!obj->phdr_loaded)
509 1.41 skrll xfree((void *)(uintptr_t)obj->phdr);
510 1.53 martin xfree(obj);
511 1.10 mycroft }
512 1.10 mycroft
513 1.10 mycroft Obj_Entry *
514 1.10 mycroft _rtld_obj_new(void)
515 1.10 mycroft {
516 1.10 mycroft Obj_Entry *obj;
517 1.10 mycroft
518 1.10 mycroft obj = CNEW(Obj_Entry);
519 1.51 christos SIMPLEQ_INIT(&obj->names);
520 1.10 mycroft SIMPLEQ_INIT(&obj->dldags);
521 1.10 mycroft SIMPLEQ_INIT(&obj->dagmembers);
522 1.4 christos return obj;
523 1.1 cgd }
524 1.1 cgd
525 1.1 cgd /*
526 1.1 cgd * Given a set of ELF protection flags, return the corresponding protection
527 1.1 cgd * flags for MMAP.
528 1.1 cgd */
529 1.1 cgd static int
530 1.63 christos convert_prot(int elfflags)
531 1.1 cgd {
532 1.4 christos int prot = 0;
533 1.29 simonb
534 1.8 kleink if (elfflags & PF_R)
535 1.4 christos prot |= PROT_READ;
536 1.1 cgd #ifdef RTLD_LOADER
537 1.8 kleink if (elfflags & PF_W)
538 1.4 christos prot |= PROT_WRITE;
539 1.1 cgd #endif
540 1.8 kleink if (elfflags & PF_X)
541 1.4 christos prot |= PROT_EXEC;
542 1.4 christos return prot;
543 1.1 cgd }
544 1.63 christos
545 1.63 christos static int
546 1.63 christos convert_flags(int elfflags __unused)
547 1.63 christos {
548 1.63 christos int flags = MAP_PRIVATE; /* All mappings are private */
549 1.63 christos
550 1.63 christos #ifdef MAP_NOCORE
551 1.63 christos /*
552 1.63 christos * Readonly mappings are marked "MAP_NOCORE", because they can be
553 1.63 christos * reconstructed by a debugger.
554 1.63 christos */
555 1.63 christos if (!(elfflags & PF_W))
556 1.63 christos flags |= MAP_NOCORE;
557 1.63 christos #endif
558 1.63 christos return flags;
559 1.63 christos }
560