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 41fa7dd9c5SMatthew Dillon static int convert_prot(int); /* Elf flags -> mmap protection */ 42fa7dd9c5SMatthew Dillon static int convert_flags(int); /* Elf flags -> mmap flags */ 433124c3e0SJohn Polstra 443124c3e0SJohn Polstra /* 45bfb1ef60SJohn Polstra * Map a shared object into memory. The "fd" argument is a file descriptor, 463124c3e0SJohn Polstra * which must be open on the object and positioned at its beginning. 47bfb1ef60SJohn Polstra * The "path" argument is a pathname that is used only for error messages. 483124c3e0SJohn Polstra * 493124c3e0SJohn Polstra * The return value is a pointer to a newly-allocated Obj_Entry structure 503124c3e0SJohn Polstra * for the shared object. Returns NULL on failure. 513124c3e0SJohn Polstra */ 523124c3e0SJohn Polstra Obj_Entry * 537360ae0fSJohn Polstra map_object(int fd, const char *path, const struct stat *sb) 543124c3e0SJohn Polstra { 553124c3e0SJohn Polstra Obj_Entry *obj; 563124c3e0SJohn Polstra union { 5713575fc4SDoug Rabson Elf_Ehdr hdr; 583124c3e0SJohn Polstra char buf[PAGE_SIZE]; 593124c3e0SJohn Polstra } u; 6078af18bdSDavid E. O'Brien int i; 6178af18bdSDavid E. O'Brien ssize_t nbytes; 6213575fc4SDoug Rabson Elf_Phdr *phdr; 6313575fc4SDoug Rabson Elf_Phdr *phlimit; 648b7f25d4SAlexander Kabaev Elf_Phdr **segs; 653124c3e0SJohn Polstra int nsegs; 6613575fc4SDoug Rabson Elf_Phdr *phdyn; 6713575fc4SDoug Rabson Elf_Phdr *phphdr; 68a607e5d7SJohn Polstra Elf_Phdr *phinterp; 693124c3e0SJohn Polstra caddr_t mapbase; 703124c3e0SJohn Polstra size_t mapsize; 7113575fc4SDoug Rabson Elf_Off base_offset; 7213575fc4SDoug Rabson Elf_Addr base_vaddr; 7313575fc4SDoug Rabson Elf_Addr base_vlimit; 743124c3e0SJohn Polstra caddr_t base_addr; 7513575fc4SDoug Rabson Elf_Off data_offset; 7613575fc4SDoug Rabson Elf_Addr data_vaddr; 7713575fc4SDoug Rabson Elf_Addr data_vlimit; 783124c3e0SJohn Polstra caddr_t data_addr; 798b7f25d4SAlexander Kabaev int data_prot; 80fa7dd9c5SMatthew Dillon int data_flags; 8113575fc4SDoug Rabson Elf_Addr clear_vaddr; 823124c3e0SJohn Polstra caddr_t clear_addr; 838b7f25d4SAlexander Kabaev caddr_t clear_page; 843124c3e0SJohn Polstra size_t nclear; 8513575fc4SDoug Rabson Elf_Addr bss_vaddr; 8613575fc4SDoug Rabson Elf_Addr bss_vlimit; 873124c3e0SJohn Polstra caddr_t bss_addr; 883124c3e0SJohn Polstra 893124c3e0SJohn Polstra if ((nbytes = read(fd, u.buf, PAGE_SIZE)) == -1) { 90bfb1ef60SJohn Polstra _rtld_error("%s: read error: %s", path, strerror(errno)); 913124c3e0SJohn Polstra return NULL; 923124c3e0SJohn Polstra } 933124c3e0SJohn Polstra 943124c3e0SJohn Polstra /* Make sure the file is valid */ 9578af18bdSDavid E. O'Brien if (nbytes < (ssize_t)sizeof(Elf_Ehdr) 963124c3e0SJohn Polstra || u.hdr.e_ident[EI_MAG0] != ELFMAG0 973124c3e0SJohn Polstra || u.hdr.e_ident[EI_MAG1] != ELFMAG1 983124c3e0SJohn Polstra || u.hdr.e_ident[EI_MAG2] != ELFMAG2 993124c3e0SJohn Polstra || u.hdr.e_ident[EI_MAG3] != ELFMAG3) { 100bfb1ef60SJohn Polstra _rtld_error("%s: invalid file format", path); 1013124c3e0SJohn Polstra return NULL; 1023124c3e0SJohn Polstra } 10313575fc4SDoug Rabson if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS 10413575fc4SDoug Rabson || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) { 105bfb1ef60SJohn Polstra _rtld_error("%s: unsupported file layout", path); 1063124c3e0SJohn Polstra return NULL; 1073124c3e0SJohn Polstra } 1083124c3e0SJohn Polstra if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT 1093124c3e0SJohn Polstra || u.hdr.e_version != EV_CURRENT) { 110bfb1ef60SJohn Polstra _rtld_error("%s: unsupported file version", path); 1113124c3e0SJohn Polstra return NULL; 1123124c3e0SJohn Polstra } 1133124c3e0SJohn Polstra if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) { 114bfb1ef60SJohn Polstra _rtld_error("%s: unsupported file type", path); 1153124c3e0SJohn Polstra return NULL; 1163124c3e0SJohn Polstra } 11713575fc4SDoug Rabson if (u.hdr.e_machine != ELF_TARG_MACH) { 118bfb1ef60SJohn Polstra _rtld_error("%s: unsupported machine", path); 1193124c3e0SJohn Polstra return NULL; 1203124c3e0SJohn Polstra } 1213124c3e0SJohn Polstra 1223124c3e0SJohn Polstra /* 1233124c3e0SJohn Polstra * We rely on the program header being in the first page. This is 1243124c3e0SJohn Polstra * not strictly required by the ABI specification, but it seems to 1253124c3e0SJohn Polstra * always true in practice. And, it simplifies things considerably. 1263124c3e0SJohn Polstra */ 127bfb1ef60SJohn Polstra if (u.hdr.e_phentsize != sizeof(Elf_Phdr)) { 128bfb1ef60SJohn Polstra _rtld_error( 129bfb1ef60SJohn Polstra "%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path); 130bfb1ef60SJohn Polstra return NULL; 131bfb1ef60SJohn Polstra } 13278af18bdSDavid E. O'Brien if (u.hdr.e_phoff + u.hdr.e_phnum * sizeof(Elf_Phdr) > (size_t)nbytes) { 133bfb1ef60SJohn Polstra _rtld_error("%s: program header too large", path); 134bfb1ef60SJohn Polstra return NULL; 135bfb1ef60SJohn Polstra } 1363124c3e0SJohn Polstra 1373124c3e0SJohn Polstra /* 1383124c3e0SJohn Polstra * Scan the program header entries, and save key information. 1393124c3e0SJohn Polstra * 1403124c3e0SJohn Polstra * We rely on there being exactly two load segments, text and data, 1413124c3e0SJohn Polstra * in that order. 1423124c3e0SJohn Polstra */ 14313575fc4SDoug Rabson phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff); 1443124c3e0SJohn Polstra phlimit = phdr + u.hdr.e_phnum; 1458b7f25d4SAlexander Kabaev nsegs = -1; 146a607e5d7SJohn Polstra phdyn = phphdr = phinterp = NULL; 1478b7f25d4SAlexander Kabaev segs = alloca(sizeof(segs[0]) * u.hdr.e_phnum); 1483124c3e0SJohn Polstra while (phdr < phlimit) { 1493124c3e0SJohn Polstra switch (phdr->p_type) { 1503124c3e0SJohn Polstra 151a607e5d7SJohn Polstra case PT_INTERP: 152a607e5d7SJohn Polstra phinterp = phdr; 153a607e5d7SJohn Polstra break; 154a607e5d7SJohn Polstra 1553124c3e0SJohn Polstra case PT_LOAD: 1568b7f25d4SAlexander Kabaev segs[++nsegs] = phdr; 1578b7f25d4SAlexander Kabaev if (segs[nsegs]->p_align < PAGE_SIZE) { 1588b7f25d4SAlexander Kabaev _rtld_error("%s: PT_LOAD segment %d not page-aligned", 1598b7f25d4SAlexander Kabaev path, nsegs); 160bfb1ef60SJohn Polstra return NULL; 161bfb1ef60SJohn Polstra } 1623124c3e0SJohn Polstra break; 1633124c3e0SJohn Polstra 1643124c3e0SJohn Polstra case PT_PHDR: 1653124c3e0SJohn Polstra phphdr = phdr; 1663124c3e0SJohn Polstra break; 1673124c3e0SJohn Polstra 1683124c3e0SJohn Polstra case PT_DYNAMIC: 1693124c3e0SJohn Polstra phdyn = phdr; 1703124c3e0SJohn Polstra break; 1713124c3e0SJohn Polstra } 1723124c3e0SJohn Polstra 1733124c3e0SJohn Polstra ++phdr; 1743124c3e0SJohn Polstra } 1753124c3e0SJohn Polstra if (phdyn == NULL) { 176bfb1ef60SJohn Polstra _rtld_error("%s: object is not dynamically-linked", path); 1773124c3e0SJohn Polstra return NULL; 1783124c3e0SJohn Polstra } 1793124c3e0SJohn Polstra 1808b7f25d4SAlexander Kabaev if (nsegs < 0) { 181bfb1ef60SJohn Polstra _rtld_error("%s: too few PT_LOAD segments", path); 182bfb1ef60SJohn Polstra return NULL; 183bfb1ef60SJohn Polstra } 1843124c3e0SJohn Polstra 1853124c3e0SJohn Polstra /* 1863124c3e0SJohn Polstra * Map the entire address space of the object, to stake out our 1873124c3e0SJohn Polstra * contiguous region, and to establish the base address for relocation. 1883124c3e0SJohn Polstra */ 1893124c3e0SJohn Polstra base_offset = trunc_page(segs[0]->p_offset); 1903124c3e0SJohn Polstra base_vaddr = trunc_page(segs[0]->p_vaddr); 1918b7f25d4SAlexander Kabaev base_vlimit = round_page(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz); 1923124c3e0SJohn Polstra mapsize = base_vlimit - base_vaddr; 1933124c3e0SJohn Polstra base_addr = u.hdr.e_type == ET_EXEC ? (caddr_t) base_vaddr : NULL; 1943124c3e0SJohn Polstra 195fa7dd9c5SMatthew Dillon mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags), 196fa7dd9c5SMatthew Dillon convert_flags(segs[0]->p_flags), fd, base_offset); 1973124c3e0SJohn Polstra if (mapbase == (caddr_t) -1) { 198bfb1ef60SJohn Polstra _rtld_error("%s: mmap of entire address space failed: %s", 199bfb1ef60SJohn Polstra path, strerror(errno)); 2003124c3e0SJohn Polstra return NULL; 2013124c3e0SJohn Polstra } 2023124c3e0SJohn Polstra if (base_addr != NULL && mapbase != base_addr) { 203bfb1ef60SJohn Polstra _rtld_error("%s: mmap returned wrong address: wanted %p, got %p", 204bfb1ef60SJohn Polstra path, base_addr, mapbase); 2053124c3e0SJohn Polstra munmap(mapbase, mapsize); 2063124c3e0SJohn Polstra return NULL; 2073124c3e0SJohn Polstra } 2083124c3e0SJohn Polstra 2098b7f25d4SAlexander Kabaev for (i = 0; i <= nsegs; i++) { 2108b7f25d4SAlexander Kabaev /* Overlay the segment onto the proper region. */ 2118b7f25d4SAlexander Kabaev data_offset = trunc_page(segs[i]->p_offset); 2128b7f25d4SAlexander Kabaev data_vaddr = trunc_page(segs[i]->p_vaddr); 2138b7f25d4SAlexander Kabaev data_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_filesz); 2143124c3e0SJohn Polstra data_addr = mapbase + (data_vaddr - base_vaddr); 215fa7dd9c5SMatthew Dillon data_prot = convert_prot(segs[i]->p_flags); 216fa7dd9c5SMatthew Dillon data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; 2178b7f25d4SAlexander Kabaev /* Do not call mmap on the first segment - this is redundant */ 2188b7f25d4SAlexander Kabaev if (i && mmap(data_addr, data_vlimit - data_vaddr, data_prot, 219fa7dd9c5SMatthew Dillon data_flags, fd, data_offset) == (caddr_t) -1) { 220bfb1ef60SJohn Polstra _rtld_error("%s: mmap of data failed: %s", path, strerror(errno)); 2213124c3e0SJohn Polstra return NULL; 2223124c3e0SJohn Polstra } 2233124c3e0SJohn Polstra 2248b7f25d4SAlexander Kabaev /* Clear any BSS in the last page of the segment. */ 2258b7f25d4SAlexander Kabaev clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz; 2263124c3e0SJohn Polstra clear_addr = mapbase + (clear_vaddr - base_vaddr); 2278b7f25d4SAlexander Kabaev clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr); 2288b7f25d4SAlexander Kabaev if ((nclear = data_vlimit - clear_vaddr) > 0) { 2298b7f25d4SAlexander Kabaev /* Make sure the end of the segment is writable */ 2308b7f25d4SAlexander Kabaev if ((data_prot & PROT_WRITE) == 0 && 2318b7f25d4SAlexander Kabaev -1 == mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) { 2328b7f25d4SAlexander Kabaev _rtld_error("%s: mprotect failed: %s", path, 2338b7f25d4SAlexander Kabaev strerror(errno)); 2348b7f25d4SAlexander Kabaev return NULL; 2358b7f25d4SAlexander Kabaev } 2368b7f25d4SAlexander Kabaev 2373124c3e0SJohn Polstra memset(clear_addr, 0, nclear); 2383124c3e0SJohn Polstra 2398b7f25d4SAlexander Kabaev /* Reset the data protection back */ 2408b7f25d4SAlexander Kabaev if ((data_prot & PROT_WRITE) == 0) 2418b7f25d4SAlexander Kabaev mprotect(clear_page, PAGE_SIZE, data_prot); 2428b7f25d4SAlexander Kabaev } 2438b7f25d4SAlexander Kabaev 2443124c3e0SJohn Polstra /* Overlay the BSS segment onto the proper region. */ 2453124c3e0SJohn Polstra bss_vaddr = data_vlimit; 2468b7f25d4SAlexander Kabaev bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz); 2473124c3e0SJohn Polstra bss_addr = mapbase + (bss_vaddr - base_vaddr); 2483124c3e0SJohn Polstra if (bss_vlimit > bss_vaddr) { /* There is something to do */ 2498b7f25d4SAlexander Kabaev if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot, 2503124c3e0SJohn Polstra MAP_PRIVATE|MAP_FIXED|MAP_ANON, -1, 0) == (caddr_t) -1) { 2518b7f25d4SAlexander Kabaev _rtld_error("%s: mmap of bss failed: %s", path, 2528b7f25d4SAlexander Kabaev strerror(errno)); 2533124c3e0SJohn Polstra return NULL; 2543124c3e0SJohn Polstra } 2553124c3e0SJohn Polstra } 2568b7f25d4SAlexander Kabaev } 2573124c3e0SJohn Polstra 258926ea445SJohn Polstra obj = obj_new(); 2597360ae0fSJohn Polstra if (sb != NULL) { 2607360ae0fSJohn Polstra obj->dev = sb->st_dev; 2617360ae0fSJohn Polstra obj->ino = sb->st_ino; 2627360ae0fSJohn Polstra } 2633124c3e0SJohn Polstra obj->mapbase = mapbase; 2643124c3e0SJohn Polstra obj->mapsize = mapsize; 2653124c3e0SJohn Polstra obj->textsize = round_page(segs[0]->p_vaddr + segs[0]->p_memsz) - 2663124c3e0SJohn Polstra base_vaddr; 2673124c3e0SJohn Polstra obj->vaddrbase = base_vaddr; 2683124c3e0SJohn Polstra obj->relocbase = mapbase - base_vaddr; 269a607e5d7SJohn Polstra obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr); 2703124c3e0SJohn Polstra if (u.hdr.e_entry != 0) 271a607e5d7SJohn Polstra obj->entry = (caddr_t) (obj->relocbase + u.hdr.e_entry); 2723124c3e0SJohn Polstra if (phphdr != NULL) { 273a607e5d7SJohn Polstra obj->phdr = (const Elf_Phdr *) (obj->relocbase + phphdr->p_vaddr); 2743124c3e0SJohn Polstra obj->phsize = phphdr->p_memsz; 2753124c3e0SJohn Polstra } 276a607e5d7SJohn Polstra if (phinterp != NULL) 277a607e5d7SJohn Polstra obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr); 2783124c3e0SJohn Polstra 2793124c3e0SJohn Polstra return obj; 2803124c3e0SJohn Polstra } 2813124c3e0SJohn Polstra 282926ea445SJohn Polstra void 283926ea445SJohn Polstra obj_free(Obj_Entry *obj) 284926ea445SJohn Polstra { 285926ea445SJohn Polstra Objlist_Entry *elm; 286926ea445SJohn Polstra 287926ea445SJohn Polstra free(obj->path); 288926ea445SJohn Polstra while (obj->needed != NULL) { 289926ea445SJohn Polstra Needed_Entry *needed = obj->needed; 290926ea445SJohn Polstra obj->needed = needed->next; 291926ea445SJohn Polstra free(needed); 292926ea445SJohn Polstra } 293926ea445SJohn Polstra while (!STAILQ_EMPTY(&obj->dldags)) { 294926ea445SJohn Polstra elm = STAILQ_FIRST(&obj->dldags); 295926ea445SJohn Polstra STAILQ_REMOVE_HEAD(&obj->dldags, link); 296926ea445SJohn Polstra free(elm); 297926ea445SJohn Polstra } 298926ea445SJohn Polstra while (!STAILQ_EMPTY(&obj->dagmembers)) { 299926ea445SJohn Polstra elm = STAILQ_FIRST(&obj->dagmembers); 300926ea445SJohn Polstra STAILQ_REMOVE_HEAD(&obj->dagmembers, link); 301926ea445SJohn Polstra free(elm); 302926ea445SJohn Polstra } 30363c1e7cbSAlexander Kabaev free(obj->priv); 304926ea445SJohn Polstra free(obj); 305926ea445SJohn Polstra } 306926ea445SJohn Polstra 307926ea445SJohn Polstra Obj_Entry * 308926ea445SJohn Polstra obj_new(void) 309926ea445SJohn Polstra { 310926ea445SJohn Polstra Obj_Entry *obj; 311926ea445SJohn Polstra 312926ea445SJohn Polstra obj = CNEW(Obj_Entry); 313926ea445SJohn Polstra STAILQ_INIT(&obj->dldags); 314926ea445SJohn Polstra STAILQ_INIT(&obj->dagmembers); 315926ea445SJohn Polstra return obj; 316926ea445SJohn Polstra } 317926ea445SJohn Polstra 3183124c3e0SJohn Polstra /* 3193124c3e0SJohn Polstra * Given a set of ELF protection flags, return the corresponding protection 3203124c3e0SJohn Polstra * flags for MMAP. 3213124c3e0SJohn Polstra */ 3223124c3e0SJohn Polstra static int 323fa7dd9c5SMatthew Dillon convert_prot(int elfflags) 3243124c3e0SJohn Polstra { 3253124c3e0SJohn Polstra int prot = 0; 3263124c3e0SJohn Polstra if (elfflags & PF_R) 3273124c3e0SJohn Polstra prot |= PROT_READ; 3283124c3e0SJohn Polstra if (elfflags & PF_W) 3293124c3e0SJohn Polstra prot |= PROT_WRITE; 3303124c3e0SJohn Polstra if (elfflags & PF_X) 3313124c3e0SJohn Polstra prot |= PROT_EXEC; 3323124c3e0SJohn Polstra return prot; 3333124c3e0SJohn Polstra } 334fa7dd9c5SMatthew Dillon 335fa7dd9c5SMatthew Dillon static int 336fa7dd9c5SMatthew Dillon convert_flags(int elfflags) 337fa7dd9c5SMatthew Dillon { 338fa7dd9c5SMatthew Dillon int flags = MAP_PRIVATE; /* All mappings are private */ 339fa7dd9c5SMatthew Dillon 340fa7dd9c5SMatthew Dillon /* 341fa7dd9c5SMatthew Dillon * Readonly mappings are marked "MAP_NOCORE", because they can be 342fa7dd9c5SMatthew Dillon * reconstructed by a debugger. 343fa7dd9c5SMatthew Dillon */ 344fa7dd9c5SMatthew Dillon if (!(elfflags & PF_W)) 345fa7dd9c5SMatthew Dillon flags |= MAP_NOCORE; 346fa7dd9c5SMatthew Dillon return flags; 347fa7dd9c5SMatthew Dillon } 348