Changeset 17341d4 in mainline for uspace/lib/c/generic/elf/elf_load.c


Ignore:
Timestamp:
2016-04-20T17:25:48Z (8 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
dc0d8b52
Parents:
13dfa3f9
Message:

Move rtld internals out of loader. Stop misusing rtld instance from current environment for loading dynamically linked executables.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/elf/elf_load.c

    r13dfa3f9 r17341d4  
    11/*
    2  * Copyright (c) 2006 Sergey Bondari
    3  * Copyright (c) 2006 Jakub Jermar
    4  * Copyright (c) 2011 Jiri Svoboda
     2 * Copyright (c) 2016 Jiri Svoboda
    53 * All rights reserved.
    64 *
     
    3634 * @file
    3735 * @brief       Userspace ELF loader.
    38  *
    39  * This module allows loading ELF binaries (both executables and
    40  * shared objects) from VFS. The current implementation allocates
    41  * anonymous memory, fills it with segment data and then adjusts
    42  * the memory areas' flags to the final value. In the future,
    43  * the segments will be mapped directly from the file.
    4436 */
    4537
     38#include <errno.h>
    4639#include <stdio.h>
    47 #include <sys/types.h>
    48 #include <align.h>
    49 #include <assert.h>
    50 #include <as.h>
    51 #include <elf/elf.h>
    52 #include <unistd.h>
    53 #include <fcntl.h>
    54 #include <smc.h>
    55 #include <loader/pcb.h>
    56 #include <entry_point.h>
     40#include <elf/elf_load.h>
     41#include <elf/elf_mod.h>
     42#include <rtld/rtld.h>
    5743
    58 #include <elf/elf_load.h>
    5944
    6045#define DPRINTF(...)
    6146
    62 static const char *error_codes[] = {
    63         "no error",
    64         "invalid image",
    65         "address space error",
    66         "incompatible image",
    67         "unsupported image type",
    68         "irrecoverable error"
    69 };
    70 
    71 static unsigned int elf_load(elf_ld_t *elf, size_t so_bias);
    72 static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry);
    73 static int section_header(elf_ld_t *elf, elf_section_header_t *entry);
    74 static int load_segment(elf_ld_t *elf, elf_segment_header_t *entry);
    75 
    76 /** Load ELF binary from a file.
     47/** Load ELF program.
    7748 *
    78  * Load an ELF binary from the specified file. If the file is
    79  * an executable program, it is loaded unbiased. If it is a shared
    80  * object, it is loaded with the bias @a so_bias. Some information
    81  * extracted from the binary is stored in a elf_info_t structure
    82  * pointed to by @a info.
    83  *
    84  * @param file_name Path to the ELF file.
    85  * @param so_bias   Bias to use if the file is a shared object.
    86  * @param info      Pointer to a structure for storing information
    87  *                  extracted from the binary.
    88  *
    89  * @return EOK on success or negative error code.
    90  *
     49 * @param file_name File name
     50 * @param info Place to store ELF program information
     51 * @return EOK on success or non-zero error code
    9152 */
    92 int elf_load_file(const char *file_name, size_t so_bias, eld_flags_t flags,
    93     elf_info_t *info)
     53int elf_load(const char *file_name, elf_info_t *info)
    9454{
    95         elf_ld_t elf;
    96 
    97         int fd;
     55#ifdef CONFIG_RTLD
     56        rtld_t *env;
     57#endif
    9858        int rc;
    9959
    100         fd = open(file_name, O_RDONLY);
    101         if (fd < 0) {
    102                 DPRINTF("failed opening file\n");
    103                 return -1;
     60        rc = elf_load_file(file_name, 0, 0, &info->finfo);
     61        if (rc != EE_OK) {
     62                DPRINTF("Failed to load executable '%s'.\n", file_name);
     63                return rc;
    10464        }
    10565
    106         elf.fd = fd;
    107         elf.info = info;
    108         elf.flags = flags;
     66        if (info->finfo.interp == NULL) {
     67                /* Statically linked program */
     68                DPRINTF("Binary is statically linked.\n");
     69                info->env = NULL;
     70                return EE_OK;
     71        }
    10972
    110         rc = elf_load(&elf, so_bias);
     73        DPRINTF("Binary is dynamically linked.\n");
     74#ifdef CONFIG_RTLD
     75        DPRINTF( "- prog dynamic: %p\n", info->finfo.dynamic);
    11176
    112         close(fd);
    113 
     77        rc = rtld_prog_process(&info->finfo, &env);
     78        info->env = env;
     79#else
     80        rc = EE_UNSUPPORTED;
     81#endif
    11482        return rc;
    11583}
    11684
    117 /** Create the program control block (PCB).
     85/** Set ELF-related PCB entries.
    11886 *
    11987 * Fills the program control block @a pcb with information from
     
    12189 *
    12290 * @param info  Program info structure
    123  * @return EOK on success or negative error code
     91 * @param pcb PCB
    12492 */
    125 void elf_create_pcb(elf_info_t *info, pcb_t *pcb)
     93void elf_set_pcb(elf_info_t *info, pcb_t *pcb)
    12694{
    127         pcb->entry = info->entry;
    128         pcb->dynamic = info->dynamic;
    129         pcb->rtld_runtime = NULL;
    130 }
    131 
    132 
    133 /** Load an ELF binary.
    134  *
    135  * The @a elf structure contains the loader state, including
    136  * an open file, from which the binary will be loaded,
    137  * a pointer to the @c info structure etc.
    138  *
    139  * @param elf           Pointer to loader state buffer.
    140  * @param so_bias       Bias to use if the file is a shared object.
    141  * @return EE_OK on success or EE_xx error code.
    142  */
    143 static unsigned int elf_load(elf_ld_t *elf, size_t so_bias)
    144 {
    145         elf_header_t header_buf;
    146         elf_header_t *header = &header_buf;
    147         int i, rc;
    148 
    149         rc = read(elf->fd, header, sizeof(elf_header_t));
    150         if (rc != sizeof(elf_header_t)) {
    151                 DPRINTF("Read error.\n");
    152                 return EE_INVALID;
    153         }
    154 
    155         elf->header = header;
    156 
    157         /* Identify ELF */
    158         if (header->e_ident[EI_MAG0] != ELFMAG0 ||
    159             header->e_ident[EI_MAG1] != ELFMAG1 ||
    160             header->e_ident[EI_MAG2] != ELFMAG2 ||
    161             header->e_ident[EI_MAG3] != ELFMAG3) {
    162                 DPRINTF("Invalid header.\n");
    163                 return EE_INVALID;
    164         }
    165        
    166         /* Identify ELF compatibility */
    167         if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
    168             header->e_machine != ELF_MACHINE ||
    169             header->e_ident[EI_VERSION] != EV_CURRENT ||
    170             header->e_version != EV_CURRENT ||
    171             header->e_ident[EI_CLASS] != ELF_CLASS) {
    172                 DPRINTF("Incompatible data/version/class.\n");
    173                 return EE_INCOMPATIBLE;
    174         }
    175 
    176         if (header->e_phentsize != sizeof(elf_segment_header_t)) {
    177                 DPRINTF("e_phentsize: %u != %zu\n", header->e_phentsize,
    178                     sizeof(elf_segment_header_t));
    179                 return EE_INCOMPATIBLE;
    180         }
    181 
    182         if (header->e_shentsize != sizeof(elf_section_header_t)) {
    183                 DPRINTF("e_shentsize: %u != %zu\n", header->e_shentsize,
    184                     sizeof(elf_section_header_t));
    185                 return EE_INCOMPATIBLE;
    186         }
    187 
    188         /* Check if the object type is supported. */
    189         if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
    190                 DPRINTF("Object type %d is not supported\n", header->e_type);
    191                 return EE_UNSUPPORTED;
    192         }
    193 
    194         /* Shared objects can be loaded with a bias */
    195         if (header->e_type == ET_DYN)
    196                 elf->bias = so_bias;
    197         else
    198                 elf->bias = 0;
    199 
    200         elf->info->interp = NULL;
    201         elf->info->dynamic = NULL;
    202 
    203         /* Walk through all segment headers and process them. */
    204         for (i = 0; i < header->e_phnum; i++) {
    205                 elf_segment_header_t segment_hdr;
    206 
    207                 /* Seek to start of segment header */
    208                 lseek(elf->fd, header->e_phoff
    209                         + i * sizeof(elf_segment_header_t), SEEK_SET);
    210 
    211                 rc = read(elf->fd, &segment_hdr,
    212                     sizeof(elf_segment_header_t));
    213                 if (rc != sizeof(elf_segment_header_t)) {
    214                         DPRINTF("Read error.\n");
    215                         return EE_INVALID;
    216                 }
    217 
    218                 rc = segment_header(elf, &segment_hdr);
    219                 if (rc != EE_OK)
    220                         return rc;
    221         }
    222 
    223         DPRINTF("Parse sections.\n");
    224 
    225         /* Inspect all section headers and proccess them. */
    226         for (i = 0; i < header->e_shnum; i++) {
    227                 elf_section_header_t section_hdr;
    228 
    229                 /* Seek to start of section header */
    230                 lseek(elf->fd, header->e_shoff
    231                     + i * sizeof(elf_section_header_t), SEEK_SET);
    232 
    233                 rc = read(elf->fd, &section_hdr,
    234                     sizeof(elf_section_header_t));
    235                 if (rc != sizeof(elf_section_header_t)) {
    236                         DPRINTF("Read error.\n");
    237                         return EE_INVALID;
    238                 }
    239 
    240                 rc = section_header(elf, &section_hdr);
    241                 if (rc != EE_OK)
    242                         return rc;
    243         }
    244 
    245         elf->info->entry =
    246             (entry_point_t)((uint8_t *)header->e_entry + elf->bias);
    247 
    248         DPRINTF("Done.\n");
    249 
    250         return EE_OK;
    251 }
    252 
    253 /** Print error message according to error code.
    254  *
    255  * @param rc Return code returned by elf_load().
    256  *
    257  * @return NULL terminated description of error.
    258  */
    259 const char *elf_error(unsigned int rc)
    260 {
    261         assert(rc < sizeof(error_codes) / sizeof(char *));
    262 
    263         return error_codes[rc];
    264 }
    265 
    266 /** Process segment header.
    267  *
    268  * @param entry Segment header.
    269  *
    270  * @return EE_OK on success, error code otherwise.
    271  */
    272 static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry)
    273 {
    274         switch (entry->p_type) {
    275         case PT_NULL:
    276         case PT_PHDR:
    277         case PT_NOTE:
    278                 break;
    279         case PT_LOAD:
    280                 return load_segment(elf, entry);
    281                 break;
    282         case PT_INTERP:
    283                 /* Assume silently interp == "/app/dload" */
    284                 elf->info->interp = "/app/dload";
    285                 break;
    286         case PT_DYNAMIC:
    287                 /* Record pointer to dynamic section into info structure */
    288                 elf->info->dynamic =
    289                     (void *)((uint8_t *)entry->p_vaddr + elf->bias);
    290                 DPRINTF("dynamic section found at %p\n",
    291                         (void *)elf->info->dynamic);
    292                 break;
    293         case 0x70000000:
    294                 /* FIXME: MIPS reginfo */
    295                 break;
    296         case PT_SHLIB:
    297 //      case PT_LOPROC:
    298 //      case PT_HIPROC:
    299         default:
    300                 DPRINTF("Segment p_type %d unknown.\n", entry->p_type);
    301                 return EE_UNSUPPORTED;
    302                 break;
    303         }
    304         return EE_OK;
    305 }
    306 
    307 /** Load segment described by program header entry.
    308  *
    309  * @param elf   Loader state.
    310  * @param entry Program header entry describing segment to be loaded.
    311  *
    312  * @return EE_OK on success, error code otherwise.
    313  */
    314 int load_segment(elf_ld_t *elf, elf_segment_header_t *entry)
    315 {
    316         void *a;
    317         int flags = 0;
    318         uintptr_t bias;
    319         uintptr_t base;
    320         void *seg_ptr;
    321         uintptr_t seg_addr;
    322         size_t mem_sz;
    323         ssize_t rc;
    324 
    325         bias = elf->bias;
    326 
    327         seg_addr = entry->p_vaddr + bias;
    328         seg_ptr = (void *) seg_addr;
    329 
    330         DPRINTF("Load segment at addr %p, size 0x%zx\n", (void *) seg_addr,
    331                 entry->p_memsz);
    332 
    333         if (entry->p_align > 1) {
    334                 if ((entry->p_offset % entry->p_align) !=
    335                     (seg_addr % entry->p_align)) {
    336                         DPRINTF("Align check 1 failed offset%%align=0x%zx, "
    337                             "vaddr%%align=0x%zx\n",
    338                             entry->p_offset % entry->p_align,
    339                             seg_addr % entry->p_align);
    340                         return EE_INVALID;
    341                 }
    342         }
    343 
    344         /* Final flags that will be set for the memory area */
    345 
    346         if (entry->p_flags & PF_X)
    347                 flags |= AS_AREA_EXEC;
    348         if (entry->p_flags & PF_W)
    349                 flags |= AS_AREA_WRITE;
    350         if (entry->p_flags & PF_R)
    351                 flags |= AS_AREA_READ;
    352         flags |= AS_AREA_CACHEABLE;
    353        
    354         base = ALIGN_DOWN(entry->p_vaddr, PAGE_SIZE);
    355         mem_sz = entry->p_memsz + (entry->p_vaddr - base);
    356 
    357         DPRINTF("Map to seg_addr=%p-%p.\n", (void *) seg_addr,
    358             (void *) (entry->p_vaddr + bias +
    359             ALIGN_UP(entry->p_memsz, PAGE_SIZE)));
    360 
    361         /*
    362          * For the course of loading, the area needs to be readable
    363          * and writeable.
    364          */
    365         a = as_area_create((uint8_t *) base + bias, mem_sz,
    366             AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
    367         if (a == AS_MAP_FAILED) {
    368                 DPRINTF("memory mapping failed (%p, %zu)\n",
    369                     (void *) (base + bias), mem_sz);
    370                 return EE_MEMORY;
    371         }
    372 
    373         DPRINTF("as_area_create(%p, %#zx, %d) -> %p\n",
    374             (void *) (base + bias), mem_sz, flags, (void *) a);
    375 
    376         /*
    377          * Load segment data
    378          */
    379         rc = lseek(elf->fd, entry->p_offset, SEEK_SET);
    380         if (rc < 0) {
    381                 printf("seek error\n");
    382                 return EE_INVALID;
    383         }
    384 
    385 /*      rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
    386         if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
    387 
    388         /* Long reads are not possible yet. Load segment piecewise. */
    389 
    390         unsigned left, now;
    391         uint8_t *dp;
    392 
    393         left = entry->p_filesz;
    394         dp = seg_ptr;
    395 
    396         while (left > 0) {
    397                 now = 16384;
    398                 if (now > left) now = left;
    399 
    400                 rc = read(elf->fd, dp, now);
    401 
    402                 if (rc != (ssize_t) now) {
    403                         DPRINTF("Read error.\n");
    404                         return EE_INVALID;
    405                 }
    406 
    407                 left -= now;
    408                 dp += now;
    409         }
    410 
    411         /*
    412          * The caller wants to modify the segments first. He will then
    413          * need to set the right access mode and ensure SMC coherence.
    414          */
    415         if ((elf->flags & ELDF_RW) != 0) return EE_OK;
    416 
    417 //      printf("set area flags to %d\n", flags);
    418         rc = as_area_change_flags(seg_ptr, flags);
    419         if (rc != 0) {
    420                 DPRINTF("Failed to set memory area flags.\n");
    421                 return EE_MEMORY;
    422         }
    423 
    424         if (flags & AS_AREA_EXEC) {
    425                 /* Enforce SMC coherence for the segment */
    426                 if (smc_coherence(seg_ptr, entry->p_filesz))
    427                         return EE_MEMORY;
    428         }
    429 
    430         return EE_OK;
    431 }
    432 
    433 /** Process section header.
    434  *
    435  * @param elf   Loader state.
    436  * @param entry Segment header.
    437  *
    438  * @return EE_OK on success, error code otherwise.
    439  */
    440 static int section_header(elf_ld_t *elf, elf_section_header_t *entry)
    441 {
    442         switch (entry->sh_type) {
    443         case SHT_PROGBITS:
    444                 if (entry->sh_flags & SHF_TLS) {
    445                         /* .tdata */
    446                 }
    447                 break;
    448         case SHT_NOBITS:
    449                 if (entry->sh_flags & SHF_TLS) {
    450                         /* .tbss */
    451                 }
    452                 break;
    453         case SHT_DYNAMIC:
    454                 /* Record pointer to dynamic section into info structure */
    455                 elf->info->dynamic =
    456                     (void *)((uint8_t *)entry->sh_addr + elf->bias);
    457                 DPRINTF("Dynamic section found at %p.\n",
    458                     (void *) elf->info->dynamic);
    459                 break;
    460         default:
    461                 break;
    462         }
    463        
    464         return EE_OK;
     95        pcb->entry = info->finfo.entry;
     96        pcb->dynamic = info->finfo.dynamic;
     97        pcb->rtld_runtime = info->env;
    46598}
    46699
Note: See TracChangeset for help on using the changeset viewer.