13124c3e0SJohn Polstra /*- 23124c3e0SJohn Polstra * Copyright 1996-1998 John D. Polstra. 33124c3e0SJohn Polstra * All rights reserved. 43124c3e0SJohn Polstra * 53124c3e0SJohn Polstra * Redistribution and use in source and binary forms, with or without 63124c3e0SJohn Polstra * modification, are permitted provided that the following conditions 73124c3e0SJohn Polstra * are met: 83124c3e0SJohn Polstra * 1. Redistributions of source code must retain the above copyright 93124c3e0SJohn Polstra * notice, this list of conditions and the following disclaimer. 103124c3e0SJohn Polstra * 2. Redistributions in binary form must reproduce the above copyright 113124c3e0SJohn Polstra * notice, this list of conditions and the following disclaimer in the 123124c3e0SJohn Polstra * documentation and/or other materials provided with the distribution. 133124c3e0SJohn Polstra * 143124c3e0SJohn Polstra * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 153124c3e0SJohn Polstra * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 163124c3e0SJohn Polstra * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 173124c3e0SJohn Polstra * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 183124c3e0SJohn Polstra * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 193124c3e0SJohn Polstra * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 203124c3e0SJohn Polstra * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 213124c3e0SJohn Polstra * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 223124c3e0SJohn Polstra * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 233124c3e0SJohn Polstra * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 243124c3e0SJohn Polstra * 257f3dea24SPeter Wemm * $FreeBSD$ 263124c3e0SJohn Polstra */ 273124c3e0SJohn Polstra 283124c3e0SJohn Polstra #include <sys/param.h> 293124c3e0SJohn Polstra #include <sys/mman.h> 307360ae0fSJohn Polstra #include <sys/stat.h> 313124c3e0SJohn Polstra 323124c3e0SJohn Polstra #include <errno.h> 333124c3e0SJohn Polstra #include <stddef.h> 34926ea445SJohn Polstra #include <stdlib.h> 353124c3e0SJohn Polstra #include <string.h> 363124c3e0SJohn Polstra #include <unistd.h> 373124c3e0SJohn Polstra 38b5393d9fSDoug Rabson #include "debug.h" 393124c3e0SJohn Polstra #include "rtld.h" 403124c3e0SJohn Polstra 41341b3de6SMatthew N. Dodd static Elf_Ehdr *get_elf_header (int, const char *); 42fa7dd9c5SMatthew Dillon static int convert_prot(int); /* Elf flags -> mmap protection */ 43fa7dd9c5SMatthew Dillon static int convert_flags(int); /* Elf flags -> mmap flags */ 443124c3e0SJohn Polstra 453124c3e0SJohn Polstra /* 46bfb1ef60SJohn Polstra * Map a shared object into memory. The "fd" argument is a file descriptor, 473124c3e0SJohn Polstra * which must be open on the object and positioned at its beginning. 48bfb1ef60SJohn Polstra * The "path" argument is a pathname that is used only for error messages. 493124c3e0SJohn Polstra * 503124c3e0SJohn Polstra * The return value is a pointer to a newly-allocated Obj_Entry structure 513124c3e0SJohn Polstra * for the shared object. Returns NULL on failure. 523124c3e0SJohn Polstra */ 533124c3e0SJohn Polstra Obj_Entry * 547360ae0fSJohn Polstra map_object(int fd, const char *path, const struct stat *sb) 553124c3e0SJohn Polstra { 563124c3e0SJohn Polstra Obj_Entry *obj; 57341b3de6SMatthew N. Dodd Elf_Ehdr *hdr; 5878af18bdSDavid E. O'Brien int i; 5913575fc4SDoug Rabson Elf_Phdr *phdr; 6013575fc4SDoug Rabson Elf_Phdr *phlimit; 618b7f25d4SAlexander Kabaev Elf_Phdr **segs; 623124c3e0SJohn Polstra int nsegs; 6313575fc4SDoug Rabson Elf_Phdr *phdyn; 64a607e5d7SJohn Polstra Elf_Phdr *phinterp; 65017246d0SDoug Rabson Elf_Phdr *phtls; 663124c3e0SJohn Polstra caddr_t mapbase; 673124c3e0SJohn Polstra size_t mapsize; 6813575fc4SDoug Rabson Elf_Off base_offset; 6913575fc4SDoug Rabson Elf_Addr base_vaddr; 7013575fc4SDoug Rabson Elf_Addr base_vlimit; 713124c3e0SJohn Polstra caddr_t base_addr; 7213575fc4SDoug Rabson Elf_Off data_offset; 7313575fc4SDoug Rabson Elf_Addr data_vaddr; 7413575fc4SDoug Rabson Elf_Addr data_vlimit; 753124c3e0SJohn Polstra caddr_t data_addr; 768b7f25d4SAlexander Kabaev int data_prot; 77fa7dd9c5SMatthew Dillon int data_flags; 7813575fc4SDoug Rabson Elf_Addr clear_vaddr; 793124c3e0SJohn Polstra caddr_t clear_addr; 808b7f25d4SAlexander Kabaev caddr_t clear_page; 8149f90ad2SAlexander Kabaev Elf_Addr phdr_vaddr; 8249f90ad2SAlexander Kabaev size_t nclear, phsize; 8313575fc4SDoug Rabson Elf_Addr bss_vaddr; 8413575fc4SDoug Rabson Elf_Addr bss_vlimit; 853124c3e0SJohn Polstra caddr_t bss_addr; 86212f264cSKonstantin Belousov Elf_Word stack_flags; 87*6d7610d7SKonstantin Belousov Elf_Addr relro_page; 88*6d7610d7SKonstantin Belousov size_t relro_size; 893124c3e0SJohn Polstra 90341b3de6SMatthew N. Dodd hdr = get_elf_header(fd, path); 91341b3de6SMatthew N. Dodd if (hdr == NULL) 92341b3de6SMatthew N. Dodd return (NULL); 933124c3e0SJohn Polstra 943124c3e0SJohn Polstra /* 953124c3e0SJohn Polstra * Scan the program header entries, and save key information. 963124c3e0SJohn Polstra * 9711e0093fSKonstantin Belousov * We expect that the loadable segments are ordered by load address. 983124c3e0SJohn Polstra */ 99341b3de6SMatthew N. Dodd phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff); 10049f90ad2SAlexander Kabaev phsize = hdr->e_phnum * sizeof (phdr[0]); 101341b3de6SMatthew N. Dodd phlimit = phdr + hdr->e_phnum; 1028b7f25d4SAlexander Kabaev nsegs = -1; 10349f90ad2SAlexander Kabaev phdyn = phinterp = phtls = NULL; 10449f90ad2SAlexander Kabaev phdr_vaddr = 0; 105*6d7610d7SKonstantin Belousov relro_page = 0; 106*6d7610d7SKonstantin Belousov relro_size = 0; 107341b3de6SMatthew N. Dodd segs = alloca(sizeof(segs[0]) * hdr->e_phnum); 108cb38d494SKonstantin Belousov stack_flags = RTLD_DEFAULT_STACK_PF_EXEC | PF_R | PF_W; 1093124c3e0SJohn Polstra while (phdr < phlimit) { 1103124c3e0SJohn Polstra switch (phdr->p_type) { 1113124c3e0SJohn Polstra 112a607e5d7SJohn Polstra case PT_INTERP: 113a607e5d7SJohn Polstra phinterp = phdr; 114a607e5d7SJohn Polstra break; 115a607e5d7SJohn Polstra 1163124c3e0SJohn Polstra case PT_LOAD: 1178b7f25d4SAlexander Kabaev segs[++nsegs] = phdr; 11849f90ad2SAlexander Kabaev if ((segs[nsegs]->p_align & (PAGE_SIZE - 1)) != 0) { 1198b7f25d4SAlexander Kabaev _rtld_error("%s: PT_LOAD segment %d not page-aligned", 1208b7f25d4SAlexander Kabaev path, nsegs); 121bfb1ef60SJohn Polstra return NULL; 122bfb1ef60SJohn Polstra } 1233124c3e0SJohn Polstra break; 1243124c3e0SJohn Polstra 1253124c3e0SJohn Polstra case PT_PHDR: 12649f90ad2SAlexander Kabaev phdr_vaddr = phdr->p_vaddr; 12749f90ad2SAlexander Kabaev phsize = phdr->p_memsz; 1283124c3e0SJohn Polstra break; 1293124c3e0SJohn Polstra 1303124c3e0SJohn Polstra case PT_DYNAMIC: 1313124c3e0SJohn Polstra phdyn = phdr; 1323124c3e0SJohn Polstra break; 133017246d0SDoug Rabson 134017246d0SDoug Rabson case PT_TLS: 135017246d0SDoug Rabson phtls = phdr; 136017246d0SDoug Rabson break; 137212f264cSKonstantin Belousov 138212f264cSKonstantin Belousov case PT_GNU_STACK: 139212f264cSKonstantin Belousov stack_flags = phdr->p_flags; 140212f264cSKonstantin Belousov break; 141*6d7610d7SKonstantin Belousov 142*6d7610d7SKonstantin Belousov case PT_GNU_RELRO: 143*6d7610d7SKonstantin Belousov relro_page = phdr->p_vaddr; 144*6d7610d7SKonstantin Belousov relro_size = phdr->p_memsz; 145*6d7610d7SKonstantin Belousov break; 1463124c3e0SJohn Polstra } 1473124c3e0SJohn Polstra 1483124c3e0SJohn Polstra ++phdr; 1493124c3e0SJohn Polstra } 1503124c3e0SJohn Polstra if (phdyn == NULL) { 151bfb1ef60SJohn Polstra _rtld_error("%s: object is not dynamically-linked", path); 1523124c3e0SJohn Polstra return NULL; 1533124c3e0SJohn Polstra } 1543124c3e0SJohn Polstra 1558b7f25d4SAlexander Kabaev if (nsegs < 0) { 156bfb1ef60SJohn Polstra _rtld_error("%s: too few PT_LOAD segments", path); 157bfb1ef60SJohn Polstra return NULL; 158bfb1ef60SJohn Polstra } 1593124c3e0SJohn Polstra 1603124c3e0SJohn Polstra /* 1613124c3e0SJohn Polstra * Map the entire address space of the object, to stake out our 1623124c3e0SJohn Polstra * contiguous region, and to establish the base address for relocation. 1633124c3e0SJohn Polstra */ 1643124c3e0SJohn Polstra base_offset = trunc_page(segs[0]->p_offset); 1653124c3e0SJohn Polstra base_vaddr = trunc_page(segs[0]->p_vaddr); 1668b7f25d4SAlexander Kabaev base_vlimit = round_page(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz); 1673124c3e0SJohn Polstra mapsize = base_vlimit - base_vaddr; 168341b3de6SMatthew N. Dodd base_addr = hdr->e_type == ET_EXEC ? (caddr_t) base_vaddr : NULL; 1693124c3e0SJohn Polstra 170a3c8e04eSKonstantin Belousov mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE | 171a3c8e04eSKonstantin Belousov MAP_NOCORE, -1, 0); 1723124c3e0SJohn Polstra if (mapbase == (caddr_t) -1) { 173bfb1ef60SJohn Polstra _rtld_error("%s: mmap of entire address space failed: %s", 174bfb1ef60SJohn Polstra path, strerror(errno)); 1753124c3e0SJohn Polstra return NULL; 1763124c3e0SJohn Polstra } 1773124c3e0SJohn Polstra if (base_addr != NULL && mapbase != base_addr) { 178bfb1ef60SJohn Polstra _rtld_error("%s: mmap returned wrong address: wanted %p, got %p", 179bfb1ef60SJohn Polstra path, base_addr, mapbase); 1803124c3e0SJohn Polstra munmap(mapbase, mapsize); 1813124c3e0SJohn Polstra return NULL; 1823124c3e0SJohn Polstra } 1833124c3e0SJohn Polstra 1848b7f25d4SAlexander Kabaev for (i = 0; i <= nsegs; i++) { 1858b7f25d4SAlexander Kabaev /* Overlay the segment onto the proper region. */ 1868b7f25d4SAlexander Kabaev data_offset = trunc_page(segs[i]->p_offset); 1878b7f25d4SAlexander Kabaev data_vaddr = trunc_page(segs[i]->p_vaddr); 1888b7f25d4SAlexander Kabaev data_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_filesz); 1893124c3e0SJohn Polstra data_addr = mapbase + (data_vaddr - base_vaddr); 190fa7dd9c5SMatthew Dillon data_prot = convert_prot(segs[i]->p_flags); 191fa7dd9c5SMatthew Dillon data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; 192a3c8e04eSKonstantin Belousov if (mmap(data_addr, data_vlimit - data_vaddr, data_prot, 193fa7dd9c5SMatthew Dillon data_flags, fd, data_offset) == (caddr_t) -1) { 194bfb1ef60SJohn Polstra _rtld_error("%s: mmap of data failed: %s", path, strerror(errno)); 1953124c3e0SJohn Polstra return NULL; 1963124c3e0SJohn Polstra } 1973124c3e0SJohn Polstra 19869ca61baSKonstantin Belousov /* Do BSS setup */ 19969ca61baSKonstantin Belousov if (segs[i]->p_filesz != segs[i]->p_memsz) { 20069ca61baSKonstantin Belousov 2018b7f25d4SAlexander Kabaev /* Clear any BSS in the last page of the segment. */ 2028b7f25d4SAlexander Kabaev clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz; 2033124c3e0SJohn Polstra clear_addr = mapbase + (clear_vaddr - base_vaddr); 2048b7f25d4SAlexander Kabaev clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr); 20569ca61baSKonstantin Belousov 2068b7f25d4SAlexander Kabaev if ((nclear = data_vlimit - clear_vaddr) > 0) { 2078b7f25d4SAlexander Kabaev /* Make sure the end of the segment is writable */ 20869ca61baSKonstantin Belousov if ((data_prot & PROT_WRITE) == 0 && -1 == 20969ca61baSKonstantin Belousov mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) { 2108b7f25d4SAlexander Kabaev _rtld_error("%s: mprotect failed: %s", path, 2118b7f25d4SAlexander Kabaev strerror(errno)); 2128b7f25d4SAlexander Kabaev return NULL; 2138b7f25d4SAlexander Kabaev } 2148b7f25d4SAlexander Kabaev 2153124c3e0SJohn Polstra memset(clear_addr, 0, nclear); 2163124c3e0SJohn Polstra 2178b7f25d4SAlexander Kabaev /* Reset the data protection back */ 2188b7f25d4SAlexander Kabaev if ((data_prot & PROT_WRITE) == 0) 2198b7f25d4SAlexander Kabaev mprotect(clear_page, PAGE_SIZE, data_prot); 2208b7f25d4SAlexander Kabaev } 2218b7f25d4SAlexander Kabaev 2223124c3e0SJohn Polstra /* Overlay the BSS segment onto the proper region. */ 2233124c3e0SJohn Polstra bss_vaddr = data_vlimit; 2248b7f25d4SAlexander Kabaev bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz); 2253124c3e0SJohn Polstra bss_addr = mapbase + (bss_vaddr - base_vaddr); 2263124c3e0SJohn Polstra if (bss_vlimit > bss_vaddr) { /* There is something to do */ 227750b5e31SKonstantin Belousov if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot, 228750b5e31SKonstantin Belousov data_flags | MAP_ANON, -1, 0) == (caddr_t)-1) { 229750b5e31SKonstantin Belousov _rtld_error("%s: mmap of bss failed: %s", path, 2308b7f25d4SAlexander Kabaev strerror(errno)); 2313124c3e0SJohn Polstra return NULL; 2323124c3e0SJohn Polstra } 2333124c3e0SJohn Polstra } 23469ca61baSKonstantin Belousov } 23569ca61baSKonstantin Belousov 23649f90ad2SAlexander Kabaev if (phdr_vaddr == 0 && data_offset <= hdr->e_phoff && 23749f90ad2SAlexander Kabaev (data_vlimit - data_vaddr + data_offset) >= 23849f90ad2SAlexander Kabaev (hdr->e_phoff + hdr->e_phnum * sizeof (Elf_Phdr))) { 23949f90ad2SAlexander Kabaev phdr_vaddr = data_vaddr + hdr->e_phoff - data_offset; 24049f90ad2SAlexander Kabaev } 2418b7f25d4SAlexander Kabaev } 2423124c3e0SJohn Polstra 243926ea445SJohn Polstra obj = obj_new(); 2447360ae0fSJohn Polstra if (sb != NULL) { 2457360ae0fSJohn Polstra obj->dev = sb->st_dev; 2467360ae0fSJohn Polstra obj->ino = sb->st_ino; 2477360ae0fSJohn Polstra } 2483124c3e0SJohn Polstra obj->mapbase = mapbase; 2493124c3e0SJohn Polstra obj->mapsize = mapsize; 2503124c3e0SJohn Polstra obj->textsize = round_page(segs[0]->p_vaddr + segs[0]->p_memsz) - 2513124c3e0SJohn Polstra base_vaddr; 2523124c3e0SJohn Polstra obj->vaddrbase = base_vaddr; 2533124c3e0SJohn Polstra obj->relocbase = mapbase - base_vaddr; 254a607e5d7SJohn Polstra obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr); 255341b3de6SMatthew N. Dodd if (hdr->e_entry != 0) 256341b3de6SMatthew N. Dodd obj->entry = (caddr_t) (obj->relocbase + hdr->e_entry); 25749f90ad2SAlexander Kabaev if (phdr_vaddr != 0) { 25849f90ad2SAlexander Kabaev obj->phdr = (const Elf_Phdr *) (obj->relocbase + phdr_vaddr); 25949f90ad2SAlexander Kabaev } else { 26049f90ad2SAlexander Kabaev obj->phdr = malloc(phsize); 26149f90ad2SAlexander Kabaev if (obj->phdr == NULL) { 26249f90ad2SAlexander Kabaev obj_free(obj); 26349f90ad2SAlexander Kabaev _rtld_error("%s: cannot allocate program header", path); 26449f90ad2SAlexander Kabaev return NULL; 2653124c3e0SJohn Polstra } 26649f90ad2SAlexander Kabaev memcpy((char *)obj->phdr, (char *)hdr + hdr->e_phoff, phsize); 26749f90ad2SAlexander Kabaev obj->phdr_alloc = true; 26849f90ad2SAlexander Kabaev } 26949f90ad2SAlexander Kabaev obj->phsize = phsize; 270a607e5d7SJohn Polstra if (phinterp != NULL) 271a607e5d7SJohn Polstra obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr); 272017246d0SDoug Rabson if (phtls != NULL) { 273017246d0SDoug Rabson tls_dtv_generation++; 274017246d0SDoug Rabson obj->tlsindex = ++tls_max_index; 275017246d0SDoug Rabson obj->tlssize = phtls->p_memsz; 276017246d0SDoug Rabson obj->tlsalign = phtls->p_align; 277017246d0SDoug Rabson obj->tlsinitsize = phtls->p_filesz; 278017246d0SDoug Rabson obj->tlsinit = mapbase + phtls->p_vaddr; 279017246d0SDoug Rabson } 280212f264cSKonstantin Belousov obj->stack_flags = stack_flags; 281*6d7610d7SKonstantin Belousov obj->relro_page = obj->relocbase + trunc_page(relro_page); 282*6d7610d7SKonstantin Belousov obj->relro_size = round_page(relro_size); 283*6d7610d7SKonstantin Belousov 2843124c3e0SJohn Polstra return obj; 2853124c3e0SJohn Polstra } 2863124c3e0SJohn Polstra 287341b3de6SMatthew N. Dodd static Elf_Ehdr * 288341b3de6SMatthew N. Dodd get_elf_header (int fd, const char *path) 289341b3de6SMatthew N. Dodd { 290341b3de6SMatthew N. Dodd static union { 291341b3de6SMatthew N. Dodd Elf_Ehdr hdr; 292341b3de6SMatthew N. Dodd char buf[PAGE_SIZE]; 293341b3de6SMatthew N. Dodd } u; 294341b3de6SMatthew N. Dodd ssize_t nbytes; 295341b3de6SMatthew N. Dodd 2961c232cd5SRobert Watson if ((nbytes = pread(fd, u.buf, PAGE_SIZE, 0)) == -1) { 297341b3de6SMatthew N. Dodd _rtld_error("%s: read error: %s", path, strerror(errno)); 298341b3de6SMatthew N. Dodd return NULL; 299341b3de6SMatthew N. Dodd } 300341b3de6SMatthew N. Dodd 301341b3de6SMatthew N. Dodd /* Make sure the file is valid */ 302341b3de6SMatthew N. Dodd if (nbytes < (ssize_t)sizeof(Elf_Ehdr) || !IS_ELF(u.hdr)) { 303341b3de6SMatthew N. Dodd _rtld_error("%s: invalid file format", path); 304341b3de6SMatthew N. Dodd return NULL; 305341b3de6SMatthew N. Dodd } 306341b3de6SMatthew N. Dodd if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS 307341b3de6SMatthew N. Dodd || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) { 308341b3de6SMatthew N. Dodd _rtld_error("%s: unsupported file layout", path); 309341b3de6SMatthew N. Dodd return NULL; 310341b3de6SMatthew N. Dodd } 311341b3de6SMatthew N. Dodd if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT 312341b3de6SMatthew N. Dodd || u.hdr.e_version != EV_CURRENT) { 313341b3de6SMatthew N. Dodd _rtld_error("%s: unsupported file version", path); 314341b3de6SMatthew N. Dodd return NULL; 315341b3de6SMatthew N. Dodd } 316341b3de6SMatthew N. Dodd if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) { 317341b3de6SMatthew N. Dodd _rtld_error("%s: unsupported file type", path); 318341b3de6SMatthew N. Dodd return NULL; 319341b3de6SMatthew N. Dodd } 320341b3de6SMatthew N. Dodd if (u.hdr.e_machine != ELF_TARG_MACH) { 321341b3de6SMatthew N. Dodd _rtld_error("%s: unsupported machine", path); 322341b3de6SMatthew N. Dodd return NULL; 323341b3de6SMatthew N. Dodd } 324341b3de6SMatthew N. Dodd 325341b3de6SMatthew N. Dodd /* 326341b3de6SMatthew N. Dodd * We rely on the program header being in the first page. This is 327341b3de6SMatthew N. Dodd * not strictly required by the ABI specification, but it seems to 328341b3de6SMatthew N. Dodd * always true in practice. And, it simplifies things considerably. 329341b3de6SMatthew N. Dodd */ 330341b3de6SMatthew N. Dodd if (u.hdr.e_phentsize != sizeof(Elf_Phdr)) { 331341b3de6SMatthew N. Dodd _rtld_error( 332341b3de6SMatthew N. Dodd "%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path); 333341b3de6SMatthew N. Dodd return NULL; 334341b3de6SMatthew N. Dodd } 335341b3de6SMatthew N. Dodd if (u.hdr.e_phoff + u.hdr.e_phnum * sizeof(Elf_Phdr) > (size_t)nbytes) { 336341b3de6SMatthew N. Dodd _rtld_error("%s: program header too large", path); 337341b3de6SMatthew N. Dodd return NULL; 338341b3de6SMatthew N. Dodd } 339341b3de6SMatthew N. Dodd 340341b3de6SMatthew N. Dodd return (&u.hdr); 341341b3de6SMatthew N. Dodd } 342341b3de6SMatthew N. Dodd 343926ea445SJohn Polstra void 344926ea445SJohn Polstra obj_free(Obj_Entry *obj) 345926ea445SJohn Polstra { 346926ea445SJohn Polstra Objlist_Entry *elm; 347926ea445SJohn Polstra 3480eb88f20SAlexander Kabaev if (obj->tls_done) 349ddab7ee8SDoug Rabson free_tls_offset(obj); 350926ea445SJohn Polstra while (obj->needed != NULL) { 351926ea445SJohn Polstra Needed_Entry *needed = obj->needed; 352926ea445SJohn Polstra obj->needed = needed->next; 353926ea445SJohn Polstra free(needed); 354926ea445SJohn Polstra } 3550eb88f20SAlexander Kabaev while (!STAILQ_EMPTY(&obj->names)) { 3560eb88f20SAlexander Kabaev Name_Entry *entry = STAILQ_FIRST(&obj->names); 3570eb88f20SAlexander Kabaev STAILQ_REMOVE_HEAD(&obj->names, link); 3580eb88f20SAlexander Kabaev free(entry); 3590eb88f20SAlexander Kabaev } 360926ea445SJohn Polstra while (!STAILQ_EMPTY(&obj->dldags)) { 361926ea445SJohn Polstra elm = STAILQ_FIRST(&obj->dldags); 362926ea445SJohn Polstra STAILQ_REMOVE_HEAD(&obj->dldags, link); 363926ea445SJohn Polstra free(elm); 364926ea445SJohn Polstra } 365926ea445SJohn Polstra while (!STAILQ_EMPTY(&obj->dagmembers)) { 366926ea445SJohn Polstra elm = STAILQ_FIRST(&obj->dagmembers); 367926ea445SJohn Polstra STAILQ_REMOVE_HEAD(&obj->dagmembers, link); 368926ea445SJohn Polstra free(elm); 369926ea445SJohn Polstra } 37049f90ad2SAlexander Kabaev if (obj->vertab) 3710eb88f20SAlexander Kabaev free(obj->vertab); 37249f90ad2SAlexander Kabaev if (obj->origin_path) 373da9f2454SMatthew N. Dodd free(obj->origin_path); 37428551690SKonstantin Belousov if (obj->z_origin) 37528551690SKonstantin Belousov free(obj->rpath); 37649f90ad2SAlexander Kabaev if (obj->priv) 37763c1e7cbSAlexander Kabaev free(obj->priv); 37849f90ad2SAlexander Kabaev if (obj->path) 37949f90ad2SAlexander Kabaev free(obj->path); 38049f90ad2SAlexander Kabaev if (obj->phdr_alloc) 38149f90ad2SAlexander Kabaev free((void *)obj->phdr); 382926ea445SJohn Polstra free(obj); 383926ea445SJohn Polstra } 384926ea445SJohn Polstra 385926ea445SJohn Polstra Obj_Entry * 386926ea445SJohn Polstra obj_new(void) 387926ea445SJohn Polstra { 388926ea445SJohn Polstra Obj_Entry *obj; 389926ea445SJohn Polstra 390926ea445SJohn Polstra obj = CNEW(Obj_Entry); 391926ea445SJohn Polstra STAILQ_INIT(&obj->dldags); 392926ea445SJohn Polstra STAILQ_INIT(&obj->dagmembers); 3930eb88f20SAlexander Kabaev STAILQ_INIT(&obj->names); 394926ea445SJohn Polstra return obj; 395926ea445SJohn Polstra } 396926ea445SJohn Polstra 3973124c3e0SJohn Polstra /* 3983124c3e0SJohn Polstra * Given a set of ELF protection flags, return the corresponding protection 3993124c3e0SJohn Polstra * flags for MMAP. 4003124c3e0SJohn Polstra */ 4013124c3e0SJohn Polstra static int 402fa7dd9c5SMatthew Dillon convert_prot(int elfflags) 4033124c3e0SJohn Polstra { 4043124c3e0SJohn Polstra int prot = 0; 4053124c3e0SJohn Polstra if (elfflags & PF_R) 4063124c3e0SJohn Polstra prot |= PROT_READ; 4073124c3e0SJohn Polstra if (elfflags & PF_W) 4083124c3e0SJohn Polstra prot |= PROT_WRITE; 4093124c3e0SJohn Polstra if (elfflags & PF_X) 4103124c3e0SJohn Polstra prot |= PROT_EXEC; 4113124c3e0SJohn Polstra return prot; 4123124c3e0SJohn Polstra } 413fa7dd9c5SMatthew Dillon 414fa7dd9c5SMatthew Dillon static int 415fa7dd9c5SMatthew Dillon convert_flags(int elfflags) 416fa7dd9c5SMatthew Dillon { 417fa7dd9c5SMatthew Dillon int flags = MAP_PRIVATE; /* All mappings are private */ 418fa7dd9c5SMatthew Dillon 419fa7dd9c5SMatthew Dillon /* 420fa7dd9c5SMatthew Dillon * Readonly mappings are marked "MAP_NOCORE", because they can be 421fa7dd9c5SMatthew Dillon * reconstructed by a debugger. 422fa7dd9c5SMatthew Dillon */ 423fa7dd9c5SMatthew Dillon if (!(elfflags & PF_W)) 424fa7dd9c5SMatthew Dillon flags |= MAP_NOCORE; 425fa7dd9c5SMatthew Dillon return flags; 426fa7dd9c5SMatthew Dillon } 427