Home | History | Annotate | Line # | Download | only in ld.elf_so
map_object.c revision 1.1
      1  1.1  cgd /*	$NetBSD: map_object.c,v 1.1 1996/12/16 20:38:01 cgd 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.1  cgd  * All rights reserved.
      7  1.1  cgd  *
      8  1.1  cgd  * Redistribution and use in source and binary forms, with or without
      9  1.1  cgd  * modification, are permitted provided that the following conditions
     10  1.1  cgd  * are met:
     11  1.1  cgd  * 1. Redistributions of source code must retain the above copyright
     12  1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     13  1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     15  1.1  cgd  *    documentation and/or other materials provided with the distribution.
     16  1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     17  1.1  cgd  *    must display the following acknowledgement:
     18  1.1  cgd  *      This product includes software developed by John Polstra.
     19  1.1  cgd  * 4. The name of the author may not be used to endorse or promote products
     20  1.1  cgd  *    derived from this software without specific prior written permission.
     21  1.1  cgd  *
     22  1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  1.1  cgd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  1.1  cgd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  1.1  cgd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  1.1  cgd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  1.1  cgd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  1.1  cgd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  1.1  cgd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  1.1  cgd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  1.1  cgd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  1.1  cgd  */
     33  1.1  cgd 
     34  1.1  cgd #include <errno.h>
     35  1.1  cgd #include <stddef.h>
     36  1.1  cgd #include <string.h>
     37  1.1  cgd #include <unistd.h>
     38  1.1  cgd #include <sys/types.h>
     39  1.1  cgd #include <sys/mman.h>
     40  1.1  cgd 
     41  1.1  cgd #include "rtld.h"
     42  1.1  cgd 
     43  1.1  cgd #define CONCAT(x,y)     __CONCAT(x,y)
     44  1.1  cgd #define ELFNAME(x)      CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
     45  1.1  cgd #define ELFNAME2(x,y)   CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
     46  1.1  cgd #define ELFNAMEEND(x)   CONCAT(x,CONCAT(_elf,ELFSIZE))
     47  1.1  cgd #define ELFDEFNNAME(x)  CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
     48  1.1  cgd 
     49  1.1  cgd static int protflags(int);	/* Elf flags -> mmap protection */
     50  1.1  cgd 
     51  1.1  cgd /*
     52  1.1  cgd  * Map a shared object into memory.  The argument is a file descriptor,
     53  1.1  cgd  * which must be open on the object and positioned at its beginning.
     54  1.1  cgd  *
     55  1.1  cgd  * The return value is a pointer to a newly-allocated Obj_Entry structure
     56  1.1  cgd  * for the shared object.  Returns NULL on failure.
     57  1.1  cgd  */
     58  1.1  cgd Obj_Entry *
     59  1.1  cgd _rtld_map_object(
     60  1.1  cgd     const char *path,
     61  1.1  cgd     int fd)
     62  1.1  cgd {
     63  1.1  cgd     Obj_Entry *obj;
     64  1.1  cgd     union {
     65  1.1  cgd 	Elf_Ehdr hdr;
     66  1.1  cgd 	char buf[PAGESIZE];
     67  1.1  cgd     } u;
     68  1.1  cgd     int nbytes;
     69  1.1  cgd     Elf_Phdr *phdr;
     70  1.1  cgd     Elf_Phdr *phlimit;
     71  1.1  cgd     Elf_Phdr *segs[2];
     72  1.1  cgd     int nsegs;
     73  1.1  cgd     Elf_Phdr *phdyn;
     74  1.1  cgd     Elf_Phdr *phphdr;
     75  1.1  cgd     caddr_t mapbase;
     76  1.1  cgd     size_t mapsize;
     77  1.1  cgd     Elf_Off base_offset;
     78  1.1  cgd     Elf_Addr base_vaddr;
     79  1.1  cgd     Elf_Addr base_vlimit;
     80  1.1  cgd     caddr_t base_addr;
     81  1.1  cgd     Elf_Off data_offset;
     82  1.1  cgd     Elf_Addr data_vaddr;
     83  1.1  cgd     Elf_Addr data_vlimit;
     84  1.1  cgd     caddr_t data_addr;
     85  1.1  cgd #ifdef RTLD_LOADER
     86  1.1  cgd     Elf_Addr clear_vaddr;
     87  1.1  cgd     caddr_t clear_addr;
     88  1.1  cgd     size_t nclear;
     89  1.1  cgd     Elf_Addr bss_vaddr;
     90  1.1  cgd     Elf_Addr bss_vlimit;
     91  1.1  cgd     caddr_t bss_addr;
     92  1.1  cgd #endif
     93  1.1  cgd 
     94  1.1  cgd     if ((nbytes = read(fd, u.buf, PAGESIZE)) == -1) {
     95  1.1  cgd 	_rtld_error("%s: read error: %s", path, xstrerror(errno));
     96  1.1  cgd 	return NULL;
     97  1.1  cgd     }
     98  1.1  cgd 
     99  1.1  cgd     /* Make sure the file is valid */
    100  1.1  cgd     if (nbytes < sizeof(Elf_Ehdr)
    101  1.1  cgd        || memcmp(Elf_e_ident, u.hdr.e_ident, Elf_e_siz) != 0) {
    102  1.1  cgd 	_rtld_error("%s: unrecognized file format", path);
    103  1.1  cgd 	return NULL;
    104  1.1  cgd     }
    105  1.1  cgd     /* Elf_e_ident includes class */
    106  1.1  cgd     if (u.hdr.e_ident[Elf_ei_version] != Elf_ev_current
    107  1.1  cgd     || u.hdr.e_version != Elf_ev_current
    108  1.1  cgd     || u.hdr.e_ident[Elf_ei_data] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
    109  1.1  cgd 	_rtld_error("%s: Unsupported file version", path);
    110  1.1  cgd 	return NULL;
    111  1.1  cgd     }
    112  1.1  cgd     if (u.hdr.e_type != Elf_et_exec && u.hdr.e_type != Elf_et_dyn) {
    113  1.1  cgd 	_rtld_error("%s: Unsupported file type", path);
    114  1.1  cgd 	return NULL;
    115  1.1  cgd     }
    116  1.1  cgd     switch (u.hdr.e_machine) {
    117  1.1  cgd     ELFDEFNNAME(MACHDEP_ID_CASES)
    118  1.1  cgd 
    119  1.1  cgd     default:
    120  1.1  cgd 	_rtld_error("%s: Unsupported machine", path);
    121  1.1  cgd 	return NULL;
    122  1.1  cgd     }
    123  1.1  cgd 
    124  1.1  cgd     /*
    125  1.1  cgd      * We rely on the program header being in the first page.  This is
    126  1.1  cgd      * not strictly required by the ABI specification, but it seems to
    127  1.1  cgd      * always true in practice.  And, it simplifies things considerably.
    128  1.1  cgd      */
    129  1.1  cgd     assert(u.hdr.e_phentsize == sizeof(Elf_Phdr));
    130  1.1  cgd     assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= PAGESIZE);
    131  1.1  cgd     assert(u.hdr.e_phoff + u.hdr.e_phnum*sizeof(Elf_Phdr) <= nbytes);
    132  1.1  cgd 
    133  1.1  cgd     /*
    134  1.1  cgd      * Scan the program header entries, and save key information.
    135  1.1  cgd      *
    136  1.1  cgd      * We rely on there being exactly two load segments, text and data,
    137  1.1  cgd      * in that order.
    138  1.1  cgd      */
    139  1.1  cgd     phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
    140  1.1  cgd     phlimit = phdr + u.hdr.e_phnum;
    141  1.1  cgd     nsegs = 0;
    142  1.1  cgd     phdyn = NULL;
    143  1.1  cgd     phphdr = NULL;
    144  1.1  cgd     while(phdr < phlimit) {
    145  1.1  cgd 	switch(phdr->p_type) {
    146  1.1  cgd 
    147  1.1  cgd 	case Elf_pt_load:
    148  1.1  cgd 	    assert(nsegs < 2);
    149  1.1  cgd 	    segs[nsegs] = phdr;
    150  1.1  cgd 	    ++nsegs;
    151  1.1  cgd 	    break;
    152  1.1  cgd 
    153  1.1  cgd 	case Elf_pt_phdr:
    154  1.1  cgd 	    phphdr = phdr;
    155  1.1  cgd 	    break;
    156  1.1  cgd 
    157  1.1  cgd 	case Elf_pt_dynamic:
    158  1.1  cgd 	    phdyn = phdr;
    159  1.1  cgd 	    break;
    160  1.1  cgd 	}
    161  1.1  cgd 
    162  1.1  cgd 	++phdr;
    163  1.1  cgd     }
    164  1.1  cgd     if (phdyn == NULL) {
    165  1.1  cgd 	_rtld_error("%s: not dynamically-linked", path);
    166  1.1  cgd 	return NULL;
    167  1.1  cgd     }
    168  1.1  cgd 
    169  1.1  cgd     assert(nsegs == 2);
    170  1.1  cgd #ifdef __i386__
    171  1.1  cgd     assert(segs[0]->p_align <= PAGESIZE);
    172  1.1  cgd     assert(segs[1]->p_align <= PAGESIZE);
    173  1.1  cgd #endif
    174  1.1  cgd 
    175  1.1  cgd     /*
    176  1.1  cgd      * Map the entire address space of the object, to stake out our
    177  1.1  cgd      * contiguous region, and to establish the base address for relocation.
    178  1.1  cgd      */
    179  1.1  cgd     base_offset = round_down(segs[0]->p_offset);
    180  1.1  cgd     base_vaddr = round_down(segs[0]->p_vaddr);
    181  1.1  cgd     base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
    182  1.1  cgd     mapsize = base_vlimit - base_vaddr;
    183  1.1  cgd #ifdef RTLD_LOADER
    184  1.1  cgd     base_addr = u.hdr.e_type == Elf_et_exec ? (caddr_t) base_vaddr : NULL;
    185  1.1  cgd #else
    186  1.1  cgd     base_addr = NULL;
    187  1.1  cgd #endif
    188  1.1  cgd 
    189  1.1  cgd     mapbase = mmap(base_addr, mapsize, protflags(segs[0]->p_flags),
    190  1.1  cgd 	MAP_PRIVATE, fd, base_offset);
    191  1.1  cgd     if (mapbase == (caddr_t) -1) {
    192  1.1  cgd 	_rtld_error("mmap of entire address space failed: %s", xstrerror(errno));
    193  1.1  cgd 	return NULL;
    194  1.1  cgd     }
    195  1.1  cgd     if (base_addr != NULL && mapbase != base_addr) {
    196  1.1  cgd 	_rtld_error("mmap returned wrong address: wanted %p, got %p", base_addr,
    197  1.1  cgd 	    mapbase);
    198  1.1  cgd 	munmap(mapbase, mapsize);
    199  1.1  cgd 	return NULL;
    200  1.1  cgd     }
    201  1.1  cgd 
    202  1.1  cgd     /* Overlay the data segment onto the proper region. */
    203  1.1  cgd     data_offset = round_down(segs[1]->p_offset);
    204  1.1  cgd     data_vaddr = round_down(segs[1]->p_vaddr);
    205  1.1  cgd     data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz);
    206  1.1  cgd     data_addr = mapbase + (data_vaddr - base_vaddr);
    207  1.1  cgd     if (mmap(data_addr, data_vlimit - data_vaddr, protflags(segs[1]->p_flags),
    208  1.1  cgd 	    MAP_PRIVATE|MAP_FIXED, fd, data_offset) == (caddr_t) -1) {
    209  1.1  cgd 	_rtld_error("mmap of data failed: %s", xstrerror(errno));
    210  1.1  cgd 	return NULL;
    211  1.1  cgd     }
    212  1.1  cgd 
    213  1.1  cgd #ifdef RTLD_LOADER
    214  1.1  cgd     /* Clear any BSS in the last page of the data segment. */
    215  1.1  cgd     clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
    216  1.1  cgd     clear_addr = mapbase + (clear_vaddr - base_vaddr);
    217  1.1  cgd     if ((nclear = data_vlimit - clear_vaddr) > 0)
    218  1.1  cgd 	memset(clear_addr, 0, nclear);
    219  1.1  cgd 
    220  1.1  cgd     /* Overlay the BSS segment onto the proper region. */
    221  1.1  cgd     bss_vaddr = data_vlimit;
    222  1.1  cgd     bss_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
    223  1.1  cgd     bss_addr = mapbase +  (bss_vaddr - base_vaddr);
    224  1.1  cgd     if (bss_vlimit > bss_vaddr) {	/* There is something to do */
    225  1.1  cgd 	if (mmap(bss_addr, bss_vlimit - bss_vaddr, protflags(segs[1]->p_flags),
    226  1.1  cgd 		MAP_PRIVATE|MAP_FIXED|MAP_ANON, -1, 0) == (caddr_t) -1) {
    227  1.1  cgd 	    _rtld_error("mmap of bss failed: %s", xstrerror(errno));
    228  1.1  cgd 	    return NULL;
    229  1.1  cgd 	}
    230  1.1  cgd     }
    231  1.1  cgd #endif
    232  1.1  cgd 
    233  1.1  cgd     obj = CNEW(Obj_Entry);
    234  1.1  cgd     obj->mapbase = mapbase;
    235  1.1  cgd     obj->mapsize = mapsize;
    236  1.1  cgd     obj->textsize = round_up(segs[0]->p_vaddr + segs[0]->p_memsz) - base_vaddr;
    237  1.1  cgd     obj->vaddrbase = base_vaddr;
    238  1.1  cgd     obj->relocbase = mapbase - base_vaddr;
    239  1.1  cgd     obj->dynamic = (Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr);
    240  1.1  cgd     if (u.hdr.e_entry != 0)
    241  1.1  cgd 	obj->entry = (caddr_t) (obj->relocbase + u.hdr.e_entry);
    242  1.1  cgd     if (phphdr != NULL) {
    243  1.1  cgd 	obj->phdr = (const Elf_Phdr *) (obj->relocbase + phphdr->p_vaddr);
    244  1.1  cgd 	obj->phsize = phphdr->p_memsz;
    245  1.1  cgd     }
    246  1.1  cgd 
    247  1.1  cgd     return obj;
    248  1.1  cgd }
    249  1.1  cgd 
    250  1.1  cgd /*
    251  1.1  cgd  * Given a set of ELF protection flags, return the corresponding protection
    252  1.1  cgd  * flags for MMAP.
    253  1.1  cgd  */
    254  1.1  cgd static int
    255  1.1  cgd protflags(int elfflags)
    256  1.1  cgd {
    257  1.1  cgd     int prot = 0;
    258  1.1  cgd     if (elfflags & Elf_pf_r) prot |= PROT_READ;
    259  1.1  cgd #ifdef RTLD_LOADER
    260  1.1  cgd     if (elfflags & Elf_pf_w) prot |= PROT_WRITE;
    261  1.1  cgd #endif
    262  1.1  cgd     if (elfflags & Elf_pf_x) prot |= PROT_EXEC;
    263  1.1  cgd     return prot;
    264  1.1  cgd }
    265