[BACK]Return to map_object.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / ld.elf_so

Annotation of src/libexec/ld.elf_so/map_object.c, Revision 1.11

1.11    ! chs         1: /*     $NetBSD: map_object.c,v 1.10 1999/11/07 00:21:13 mycroft Exp $   */
1.1       cgd         2:
                      3: /*
                      4:  * Copyright 1996 John D. Polstra.
                      5:  * Copyright 1996 Matt Thomas <matt@3am-software.com>
                      6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *      This product includes software developed by John Polstra.
                     19:  * 4. The name of the author may not be used to endorse or promote products
                     20:  *    derived from this software without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     32:  */
                     33:
                     34: #include <errno.h>
                     35: #include <stddef.h>
1.10      mycroft    36: #include <stdlib.h>
1.1       cgd        37: #include <string.h>
                     38: #include <unistd.h>
1.10      mycroft    39: #include <sys/stat.h>
1.1       cgd        40: #include <sys/types.h>
                     41: #include <sys/mman.h>
                     42:
                     43: #include "rtld.h"
1.7       hannken    44:
1.4       christos   45: static int protflags __P((int));       /* Elf flags -> mmap protection */
1.1       cgd        46:
                     47: /*
                     48:  * Map a shared object into memory.  The argument is a file descriptor,
                     49:  * which must be open on the object and positioned at its beginning.
                     50:  *
                     51:  * The return value is a pointer to a newly-allocated Obj_Entry structure
                     52:  * for the shared object.  Returns NULL on failure.
                     53:  */
                     54: Obj_Entry *
1.10      mycroft    55: _rtld_map_object(path, fd, sb)
1.4       christos   56:        const char *path;
                     57:        int fd;
1.10      mycroft    58:        const struct stat *sb;
1.1       cgd        59: {
1.4       christos   60:        Obj_Entry      *obj;
                     61:        union {
                     62:                Elf_Ehdr hdr;
                     63:                char     buf[PAGESIZE];
                     64:        } u;
                     65:        int             nbytes;
                     66:        Elf_Phdr       *phdr;
                     67:        Elf_Phdr       *phlimit;
                     68:        Elf_Phdr       *segs[2];
                     69:        int             nsegs;
                     70:        Elf_Phdr       *phdyn;
                     71:        Elf_Phdr       *phphdr;
1.10      mycroft    72:        Elf_Phdr       *phinterp;
1.4       christos   73:        caddr_t         mapbase;
                     74:        size_t          mapsize;
                     75:        Elf_Off         base_offset;
                     76:        Elf_Addr        base_vaddr;
                     77:        Elf_Addr        base_vlimit;
1.5       thorpej    78:        Elf_Addr        text_vlimit;
1.4       christos   79:        caddr_t         base_addr;
                     80:        Elf_Off         data_offset;
                     81:        Elf_Addr        data_vaddr;
                     82:        Elf_Addr        data_vlimit;
                     83:        caddr_t         data_addr;
1.5       thorpej    84:        caddr_t         gap_addr;
                     85:        size_t          gap_size;
1.1       cgd        86: #ifdef RTLD_LOADER
1.4       christos   87:        Elf_Addr        clear_vaddr;
                     88:        caddr_t         clear_addr;
                     89:        size_t          nclear;
1.1       cgd        90: #endif
                     91:
1.4       christos   92:        if ((nbytes = read(fd, u.buf, PAGESIZE)) == -1) {
                     93:                _rtld_error("%s: read error: %s", path, xstrerror(errno));
                     94:                return NULL;
                     95:        }
                     96:        /* Make sure the file is valid */
                     97:        if (nbytes < sizeof(Elf_Ehdr) ||
1.8       kleink     98:            memcmp(ELFMAG, u.hdr.e_ident, SELFMAG) != 0 ||
                     99:            u.hdr.e_ident[EI_CLASS] != ELFCLASS) {
1.4       christos  100:                _rtld_error("%s: unrecognized file format", path);
                    101:                return NULL;
                    102:        }
                    103:        /* Elf_e_ident includes class */
1.8       kleink    104:        if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT ||
                    105:            u.hdr.e_version != EV_CURRENT ||
                    106:            u.hdr.e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
1.4       christos  107:                _rtld_error("%s: Unsupported file version", path);
                    108:                return NULL;
                    109:        }
1.8       kleink    110:        if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) {
1.4       christos  111:                _rtld_error("%s: Unsupported file type", path);
                    112:                return NULL;
                    113:        }
                    114:        switch (u.hdr.e_machine) {
                    115:                ELFDEFNNAME(MACHDEP_ID_CASES)
                    116:        default:
                    117:                _rtld_error("%s: Unsupported machine", path);
                    118:                return NULL;
                    119:        }
                    120:
                    121:        /*
                    122:          * We rely on the program header being in the first page.  This is
                    123:          * not strictly required by the ABI specification, but it seems to
                    124:          * always true in practice.  And, it simplifies things considerably.
                    125:          */
                    126:        assert(u.hdr.e_phentsize == sizeof(Elf_Phdr));
                    127:        assert(u.hdr.e_phoff + u.hdr.e_phnum * sizeof(Elf_Phdr) <= PAGESIZE);
                    128:        assert(u.hdr.e_phoff + u.hdr.e_phnum * sizeof(Elf_Phdr) <= nbytes);
                    129:
                    130:        /*
                    131:          * Scan the program header entries, and save key information.
                    132:          *
                    133:          * We rely on there being exactly two load segments, text and data,
                    134:          * in that order.
                    135:          */
                    136:        phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
                    137:        phlimit = phdr + u.hdr.e_phnum;
                    138:        nsegs = 0;
1.10      mycroft   139:        phdyn = phphdr = phinterp = NULL;
1.4       christos  140:        while (phdr < phlimit) {
                    141:                switch (phdr->p_type) {
1.10      mycroft   142:                case PT_INTERP:
                    143:                        phinterp = phdr;
                    144:                        break;
1.1       cgd       145:
1.8       kleink    146:                case PT_LOAD:
1.2       jonathan  147: #ifdef __mips__
1.4       christos  148:                        /* NetBSD/pmax 1.1 elf toolchain peculiarity */
                    149:                        if (nsegs >= 2) {
                    150:                                _rtld_error("%s: too many sections\n", path);
                    151:                                return NULL;
                    152:                        }
1.2       jonathan  153: #endif
1.4       christos  154:                        assert(nsegs < 2);
                    155:                        segs[nsegs] = phdr;
                    156:                        ++nsegs;
                    157:                        break;
                    158:
1.8       kleink    159:                case PT_PHDR:
1.4       christos  160:                        phphdr = phdr;
                    161:                        break;
                    162:
1.8       kleink    163:                case PT_DYNAMIC:
1.4       christos  164:                        phdyn = phdr;
                    165:                        break;
                    166:                }
1.1       cgd       167:
1.4       christos  168:                ++phdr;
                    169:        }
                    170:        if (phdyn == NULL) {
                    171:                _rtld_error("%s: not dynamically-linked", path);
                    172:                return NULL;
                    173:        }
                    174:        assert(nsegs == 2);
1.1       cgd       175: #ifdef __i386__
1.4       christos  176:        assert(segs[0]->p_align <= PAGESIZE);
                    177:        assert(segs[1]->p_align <= PAGESIZE);
1.1       cgd       178: #endif
                    179:
1.4       christos  180:        /*
1.11    ! chs       181:         * Map the entire address space of the object as a file
1.5       thorpej   182:         * region to stake out our contiguous region and establish a
1.11    ! chs       183:         * base for relocation.  We use a file mapping so that
        !           184:         * the kernel will give us whatever alignment is appropriate
        !           185:         * for the platform we're running on.
1.5       thorpej   186:         *
1.11    ! chs       187:         * We map it using the text protection, map the data segment
        !           188:         * into the right place, then map an anon segment for the bss
        !           189:         * and unmap the gaps left by padding to alignment.
1.5       thorpej   190:         */
1.11    ! chs       191:
1.4       christos  192:        base_offset = round_down(segs[0]->p_offset);
                    193:        base_vaddr = round_down(segs[0]->p_vaddr);
                    194:        base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
1.11    ! chs       195:        text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
1.4       christos  196:        mapsize = base_vlimit - base_vaddr;
1.11    ! chs       197:
1.1       cgd       198: #ifdef RTLD_LOADER
1.8       kleink    199:        base_addr = u.hdr.e_type == ET_EXEC ? (caddr_t) base_vaddr : NULL;
1.1       cgd       200: #else
1.4       christos  201:        base_addr = NULL;
1.1       cgd       202: #endif
                    203:
1.11    ! chs       204:        mapbase = mmap(base_addr, mapsize, protflags(segs[0]->p_flags),
        !           205:                       MAP_FILE | MAP_PRIVATE, fd, base_offset);
1.5       thorpej   206:        if (mapbase == MAP_FAILED) {
1.4       christos  207:                _rtld_error("mmap of entire address space failed: %s",
                    208:                    xstrerror(errno));
                    209:                return NULL;
                    210:        }
1.11    ! chs       211:
1.5       thorpej   212:        base_addr = mapbase;
                    213:
1.4       christos  214:        /* Overlay the data segment onto the proper region. */
                    215:        data_offset = round_down(segs[1]->p_offset);
                    216:        data_vaddr = round_down(segs[1]->p_vaddr);
                    217:        data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz);
                    218:        data_addr = mapbase + (data_vaddr - base_vaddr);
                    219:        if (mmap(data_addr, data_vlimit - data_vaddr,
1.11    ! chs       220:                 protflags(segs[1]->p_flags),
        !           221:                 MAP_FILE | MAP_PRIVATE | MAP_FIXED, fd, data_offset)
        !           222:            == MAP_FAILED) {
1.4       christos  223:                _rtld_error("mmap of data failed: %s", xstrerror(errno));
1.11    ! chs       224:                munmap(mapbase, mapsize);
        !           225:                return NULL;
        !           226:        }
        !           227:
        !           228:        /* Overlay the bss segment onto the proper region. */
        !           229:        if (mmap(mapbase + data_vlimit - base_vaddr, base_vlimit - data_vlimit,
        !           230:                 protflags(segs[1]->p_flags),
        !           231:                 MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0)
        !           232:            == MAP_FAILED) {
        !           233:                _rtld_error("mmap of bss failed: %s", xstrerror(errno));
        !           234:                munmap(mapbase, mapsize);
1.4       christos  235:                return NULL;
                    236:        }
1.5       thorpej   237:
                    238:        /* Unmap the gap between the text and data. */
                    239:        gap_addr = base_addr + round_up(text_vlimit - base_vaddr);
                    240:        gap_size = data_addr - gap_addr;
                    241:        if (gap_size != 0 && munmap(gap_addr, gap_size) == -1) {
                    242:                _rtld_error("munmap of text -> data gap failed: %s",
                    243:                    xstrerror(errno));
1.11    ! chs       244:                munmap(mapbase, mapsize);
1.5       thorpej   245:                return NULL;
                    246:        }
                    247:
1.1       cgd       248: #ifdef RTLD_LOADER
1.4       christos  249:        /* Clear any BSS in the last page of the data segment. */
                    250:        clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
                    251:        clear_addr = mapbase + (clear_vaddr - base_vaddr);
                    252:        if ((nclear = data_vlimit - clear_vaddr) > 0)
                    253:                memset(clear_addr, 0, nclear);
                    254:
1.5       thorpej   255:        /* Non-file portion of BSS mapped above. */
1.1       cgd       256: #endif
                    257:
1.10      mycroft   258:        obj = _rtld_obj_new();
                    259:        if (sb != NULL) {
                    260:                obj->dev = sb->st_dev;
                    261:                obj->ino = sb->st_ino;
                    262:        }
1.4       christos  263:        obj->mapbase = mapbase;
                    264:        obj->mapsize = mapsize;
                    265:        obj->textsize = round_up(segs[0]->p_vaddr + segs[0]->p_memsz) -
                    266:            base_vaddr;
                    267:        obj->vaddrbase = base_vaddr;
                    268:        obj->relocbase = mapbase - base_vaddr;
                    269:        obj->dynamic = (Elf_Dyn *)(obj->relocbase + phdyn->p_vaddr);
                    270:        if (u.hdr.e_entry != 0)
                    271:                obj->entry = (caddr_t)(obj->relocbase + u.hdr.e_entry);
                    272:        if (phphdr != NULL) {
                    273:                obj->phdr = (const Elf_Phdr *)
                    274:                    (obj->relocbase + phphdr->p_vaddr);
                    275:                obj->phsize = phphdr->p_memsz;
                    276:        }
1.10      mycroft   277:        if (phinterp != NULL)
                    278:                obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
                    279:
                    280:        return obj;
                    281: }
                    282:
                    283: void
                    284: _rtld_obj_free(obj)
                    285:        Obj_Entry *obj;
                    286: {
                    287:        Objlist_Entry *elm;
                    288:
                    289:        free(obj->path);
                    290:        while (obj->needed != NULL) {
                    291:                Needed_Entry *needed = obj->needed;
                    292:                obj->needed = needed->next;
                    293:                free(needed);
                    294:        }
                    295:        while (SIMPLEQ_FIRST(&obj->dldags) != NULL) {
                    296:                elm = SIMPLEQ_FIRST(&obj->dldags);
                    297:                SIMPLEQ_REMOVE_HEAD(&obj->dldags, elm, link);
                    298:                free(elm);
                    299:        }
                    300:        while (SIMPLEQ_FIRST(&obj->dagmembers) != NULL) {
                    301:                elm = SIMPLEQ_FIRST(&obj->dagmembers);
                    302:                SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, elm, link);
                    303:                free(elm);
                    304:        }
                    305:        free(obj);
                    306: }
                    307:
                    308: Obj_Entry *
                    309: _rtld_obj_new(void)
                    310: {
                    311:        Obj_Entry *obj;
                    312:
                    313:        obj = CNEW(Obj_Entry);
                    314:        SIMPLEQ_INIT(&obj->dldags);
                    315:        SIMPLEQ_INIT(&obj->dagmembers);
1.4       christos  316:        return obj;
1.1       cgd       317: }
                    318:
                    319: /*
                    320:  * Given a set of ELF protection flags, return the corresponding protection
                    321:  * flags for MMAP.
                    322:  */
                    323: static int
1.4       christos  324: protflags(elfflags)
                    325:        int elfflags;
1.1       cgd       326: {
1.4       christos  327:        int prot = 0;
1.8       kleink    328:        if (elfflags & PF_R)
1.4       christos  329:                prot |= PROT_READ;
1.1       cgd       330: #ifdef RTLD_LOADER
1.8       kleink    331:        if (elfflags & PF_W)
1.4       christos  332:                prot |= PROT_WRITE;
1.1       cgd       333: #endif
1.8       kleink    334:        if (elfflags & PF_X)
1.4       christos  335:                prot |= PROT_EXEC;
                    336:        return prot;
1.1       cgd       337: }

CVSweb <webmaster@jp.NetBSD.org>