1 1.69 riastrad /* $NetBSD: map_object.c,v 1.69 2024/08/03 21:59:57 riastradh 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.69 riastrad __RCSID("$NetBSD: map_object.c,v 1.69 2024/08/03 21:59:57 riastradh 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.65 christos size_t phdr_memsz, phsize; 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.65 christos size_t nclear; 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.66 riastrad dbg(("%s: tls index %zu size %zu align %zu initsize %zu", 314 1.66 riastrad obj->path, obj->tlsindex, obj->tlssize, obj->tlsalign, 315 1.66 riastrad obj->tlsinitsize)); 316 1.42 joerg } 317 1.42 joerg #endif 318 1.42 joerg 319 1.27 matt /* 320 1.27 matt * Calculate log2 of the base section alignment. 321 1.27 matt */ 322 1.63 christos mapflags = MAP_PRIVATE | MAP_ANON; 323 1.27 matt if (base_alignment > _rtld_pagesz) { 324 1.27 matt unsigned int log2 = 0; 325 1.27 matt for (; base_alignment > 1; base_alignment >>= 1) 326 1.27 matt log2++; 327 1.63 christos mapflags |= MAP_ALIGNED(log2); 328 1.27 matt } 329 1.27 matt 330 1.60 joerg base_addr = NULL; 331 1.1 cgd #ifdef RTLD_LOADER 332 1.60 joerg if (!obj->isdynamic) { 333 1.60 joerg mapflags |= MAP_TRYFIXED; 334 1.60 joerg base_addr = (void *)(uintptr_t)base_vaddr; 335 1.60 joerg } 336 1.1 cgd #endif 337 1.22 mycroft mapsize = base_vlimit - base_vaddr; 338 1.63 christos mapbase = mmap(base_addr, mapsize, PROT_NONE, mapflags, -1, 0); 339 1.5 thorpej if (mapbase == MAP_FAILED) { 340 1.4 christos _rtld_error("mmap of entire address space failed: %s", 341 1.4 christos xstrerror(errno)); 342 1.63 christos goto error; 343 1.4 christos } 344 1.60 joerg #ifdef RTLD_LOADER 345 1.60 joerg if (!obj->isdynamic && mapbase != base_addr) { 346 1.60 joerg _rtld_error("mmap of executable at correct address failed"); 347 1.63 christos goto error; 348 1.60 joerg } 349 1.60 joerg #endif 350 1.11 chs 351 1.64 christos obj->phdr_loaded = false; 352 1.63 christos for (i = 0; i <= nsegs; i++) { 353 1.63 christos /* Overlay the segment onto the proper region. */ 354 1.63 christos data_offset = round_down(segs[i]->p_offset); 355 1.63 christos data_vaddr = round_down(segs[i]->p_vaddr); 356 1.63 christos data_vlimit = round_up(segs[i]->p_vaddr 357 1.63 christos + segs[i]->p_filesz); 358 1.63 christos data_addr = mapbase + (data_vaddr - base_vaddr); 359 1.63 christos data_prot = convert_prot(segs[i]->p_flags); 360 1.63 christos data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; 361 1.63 christos if (data_vlimit != data_vaddr && 362 1.69 riastrad mmap(data_addr, data_vlimit - data_vaddr, data_prot, 363 1.63 christos data_flags, fd, data_offset) == MAP_FAILED) { 364 1.63 christos _rtld_error("%s: mmap of data failed: %s", path, 365 1.63 christos xstrerror(errno)); 366 1.63 christos goto error; 367 1.62 hannken } 368 1.5 thorpej 369 1.63 christos /* Do BSS setup */ 370 1.63 christos if (segs[i]->p_filesz != segs[i]->p_memsz) { 371 1.1 cgd #ifdef RTLD_LOADER 372 1.63 christos /* Clear any BSS in the last page of the segment. */ 373 1.63 christos clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz; 374 1.63 christos clear_addr = mapbase + (clear_vaddr - base_vaddr); 375 1.63 christos clear_page = mapbase + (round_down(clear_vaddr) 376 1.63 christos - base_vaddr); 377 1.63 christos 378 1.63 christos if ((nclear = data_vlimit - clear_vaddr) > 0) { 379 1.68 skrll /* 380 1.68 skrll * Make sure the end of the segment is 381 1.68 skrll * writable. 382 1.63 christos */ 383 1.63 christos if ((data_prot & PROT_WRITE) == 0 && -1 == 384 1.63 christos mprotect(clear_page, _rtld_pagesz, 385 1.63 christos data_prot|PROT_WRITE)) { 386 1.63 christos _rtld_error("%s: mprotect failed: %s", 387 1.63 christos path, xstrerror(errno)); 388 1.63 christos goto error; 389 1.63 christos } 390 1.63 christos 391 1.63 christos memset(clear_addr, 0, nclear); 392 1.63 christos 393 1.63 christos /* Reset the data protection back */ 394 1.63 christos if ((data_prot & PROT_WRITE) == 0) 395 1.63 christos mprotect(clear_page, _rtld_pagesz, 396 1.63 christos data_prot); 397 1.63 christos } 398 1.63 christos #endif 399 1.63 christos 400 1.63 christos /* Overlay the BSS segment onto the proper region. */ 401 1.63 christos bss_vaddr = data_vlimit; 402 1.63 christos bss_vlimit = round_up(segs[i]->p_vaddr + 403 1.63 christos segs[i]->p_memsz); 404 1.63 christos bss_addr = mapbase + (bss_vaddr - base_vaddr); 405 1.63 christos if (bss_vlimit > bss_vaddr) { 406 1.63 christos /* There is something to do */ 407 1.63 christos if (mmap(bss_addr, bss_vlimit - bss_vaddr, 408 1.63 christos data_prot, data_flags | MAP_ANON, -1, 0) 409 1.63 christos == MAP_FAILED) { 410 1.63 christos _rtld_error( 411 1.63 christos "%s: mmap of bss failed: %s", 412 1.63 christos path, xstrerror(errno)); 413 1.63 christos goto error; 414 1.63 christos } 415 1.63 christos } 416 1.63 christos } 417 1.4 christos 418 1.64 christos if (phdr_vaddr != EA_UNDEF && 419 1.64 christos segs[i]->p_vaddr <= phdr_vaddr && 420 1.64 christos segs[i]->p_memsz >= phdr_memsz) { 421 1.64 christos obj->phdr_loaded = true; 422 1.63 christos } 423 1.64 christos if (segs[i]->p_offset <= ehdr->e_phoff && 424 1.64 christos segs[i]->p_memsz >= phsize) { 425 1.64 christos phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff; 426 1.64 christos phdr_memsz = phsize; 427 1.64 christos obj->phdr_loaded = true; 428 1.64 christos } 429 1.64 christos } 430 1.64 christos if (obj->phdr_loaded) { 431 1.64 christos obj->phdr = (void *)(uintptr_t)phdr_vaddr; 432 1.64 christos obj->phsize = phdr_memsz; 433 1.64 christos } else { 434 1.64 christos Elf_Phdr *buf = xmalloc(phsize); 435 1.64 christos if (buf == NULL) { 436 1.64 christos _rtld_error("%s: cannot allocate program header", path); 437 1.64 christos goto error; 438 1.64 christos } 439 1.64 christos memcpy(buf, phdr, phsize); 440 1.64 christos obj->phdr = buf; 441 1.64 christos obj->phsize = phsize; 442 1.63 christos } 443 1.1 cgd 444 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 445 1.66 riastrad if (phtls != NULL) { 446 1.42 joerg obj->tlsinit = mapbase + tls_vaddr; 447 1.66 riastrad dbg(("%s: tls init = %p + %"PRImemsz" = %p", obj->path, 448 1.66 riastrad mapbase, tls_vaddr, obj->tlsinit)); 449 1.66 riastrad } 450 1.42 joerg #endif 451 1.42 joerg 452 1.4 christos obj->mapbase = mapbase; 453 1.4 christos obj->mapsize = mapsize; 454 1.4 christos obj->relocbase = mapbase - base_vaddr; 455 1.10 mycroft 456 1.55 christos #ifdef GNU_RELRO 457 1.61 thorpej /* rounding happens later. */ 458 1.61 thorpej obj->relro_page = obj->relocbase + relro_page; 459 1.61 thorpej obj->relro_size = relro_size; 460 1.55 christos #endif 461 1.55 christos 462 1.22 mycroft if (obj->dynamic) 463 1.37 mrg obj->dynamic = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->dynamic); 464 1.22 mycroft if (obj->entry) 465 1.37 mrg obj->entry = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->entry); 466 1.22 mycroft if (obj->interp) 467 1.37 mrg obj->interp = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->interp); 468 1.41 skrll if (obj->phdr_loaded) 469 1.41 skrll obj->phdr = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->phdr); 470 1.47 skrll #ifdef __ARM_EABI__ 471 1.47 skrll if (obj->exidx_start) 472 1.47 skrll obj->exidx_start = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->exidx_start); 473 1.47 skrll #endif 474 1.63 christos xfree(segs); 475 1.22 mycroft 476 1.10 mycroft return obj; 477 1.16 mycroft 478 1.63 christos error: 479 1.63 christos if (mapbase != MAP_FAILED) 480 1.63 christos munmap(mapbase, mapsize); 481 1.36 ad if (obj->ehdr != MAP_FAILED) 482 1.36 ad munmap(obj->ehdr, _rtld_pagesz); 483 1.22 mycroft _rtld_obj_free(obj); 484 1.63 christos xfree(segs); 485 1.16 mycroft return NULL; 486 1.10 mycroft } 487 1.10 mycroft 488 1.10 mycroft void 489 1.30 skrll _rtld_obj_free(Obj_Entry *obj) 490 1.10 mycroft { 491 1.10 mycroft Objlist_Entry *elm; 492 1.51 christos Name_Entry *entry; 493 1.10 mycroft 494 1.42 joerg #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II) 495 1.67 joerg if (obj->tls_static) 496 1.42 joerg _rtld_tls_offset_free(obj); 497 1.42 joerg #endif 498 1.35 ad xfree(obj->path); 499 1.10 mycroft while (obj->needed != NULL) { 500 1.10 mycroft Needed_Entry *needed = obj->needed; 501 1.10 mycroft obj->needed = needed->next; 502 1.35 ad xfree(needed); 503 1.10 mycroft } 504 1.51 christos while ((entry = SIMPLEQ_FIRST(&obj->names)) != NULL) { 505 1.51 christos SIMPLEQ_REMOVE_HEAD(&obj->names, link); 506 1.50 christos xfree(entry); 507 1.49 christos } 508 1.13 lukem while ((elm = SIMPLEQ_FIRST(&obj->dldags)) != NULL) { 509 1.13 lukem SIMPLEQ_REMOVE_HEAD(&obj->dldags, link); 510 1.35 ad xfree(elm); 511 1.10 mycroft } 512 1.13 lukem while ((elm = SIMPLEQ_FIRST(&obj->dagmembers)) != NULL) { 513 1.13 lukem SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, link); 514 1.35 ad xfree(elm); 515 1.10 mycroft } 516 1.41 skrll if (!obj->phdr_loaded) 517 1.41 skrll xfree((void *)(uintptr_t)obj->phdr); 518 1.53 martin xfree(obj); 519 1.10 mycroft } 520 1.10 mycroft 521 1.10 mycroft Obj_Entry * 522 1.10 mycroft _rtld_obj_new(void) 523 1.10 mycroft { 524 1.10 mycroft Obj_Entry *obj; 525 1.10 mycroft 526 1.10 mycroft obj = CNEW(Obj_Entry); 527 1.51 christos SIMPLEQ_INIT(&obj->names); 528 1.10 mycroft SIMPLEQ_INIT(&obj->dldags); 529 1.10 mycroft SIMPLEQ_INIT(&obj->dagmembers); 530 1.4 christos return obj; 531 1.1 cgd } 532 1.1 cgd 533 1.1 cgd /* 534 1.1 cgd * Given a set of ELF protection flags, return the corresponding protection 535 1.1 cgd * flags for MMAP. 536 1.1 cgd */ 537 1.1 cgd static int 538 1.63 christos convert_prot(int elfflags) 539 1.1 cgd { 540 1.4 christos int prot = 0; 541 1.29 simonb 542 1.8 kleink if (elfflags & PF_R) 543 1.4 christos prot |= PROT_READ; 544 1.1 cgd #ifdef RTLD_LOADER 545 1.8 kleink if (elfflags & PF_W) 546 1.4 christos prot |= PROT_WRITE; 547 1.1 cgd #endif 548 1.8 kleink if (elfflags & PF_X) 549 1.4 christos prot |= PROT_EXEC; 550 1.4 christos return prot; 551 1.1 cgd } 552 1.63 christos 553 1.63 christos static int 554 1.63 christos convert_flags(int elfflags __unused) 555 1.63 christos { 556 1.63 christos int flags = MAP_PRIVATE; /* All mappings are private */ 557 1.63 christos 558 1.63 christos #ifdef MAP_NOCORE 559 1.63 christos /* 560 1.63 christos * Readonly mappings are marked "MAP_NOCORE", because they can be 561 1.63 christos * reconstructed by a debugger. 562 1.63 christos */ 563 1.63 christos if (!(elfflags & PF_W)) 564 1.63 christos flags |= MAP_NOCORE; 565 1.63 christos #endif 566 1.63 christos return flags; 567 1.63 christos } 568