Changeset 742fc98e in mainline for uspace/lib/c/generic/elf/elf_mod.c


Ignore:
Timestamp:
2018-05-01T19:03:38Z (7 years ago)
Author:
GitHub <noreply@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6e33c2f, 924786bf
Parents:
009c485
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2018-05-01 19:03:38)
git-committer:
GitHub <noreply@…> (2018-05-01 19:03:38)
Message:

Make some effort to allocate the memory area for shared objects. (#33)

File:
1 edited

Legend:

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

    r009c485 r742fc98e  
    5858#include <str_error.h>
    5959#include <stdlib.h>
     60#include <macros.h>
    6061
    6162#include <elf/elf_load.h>
     
    7374};
    7475
    75 static unsigned int elf_load_module(elf_ld_t *elf, size_t so_bias);
     76static unsigned int elf_load_module(elf_ld_t *elf);
    7677static int segment_header(elf_ld_t *elf, elf_segment_header_t *entry);
    7778static int load_segment(elf_ld_t *elf, elf_segment_header_t *entry);
     
    8687 *
    8788 * @param file      ELF file.
    88  * @param so_bias   Bias to use if the file is a shared object.
    8989 * @param info      Pointer to a structure for storing information
    9090 *                  extracted from the binary.
     
    9393 *
    9494 */
    95 int elf_load_file(int file, size_t so_bias, eld_flags_t flags, elf_finfo_t *info)
     95int elf_load_file(int file, eld_flags_t flags, elf_finfo_t *info)
    9696{
    9797        elf_ld_t elf;
     
    110110        elf.flags = flags;
    111111
    112         int ret = elf_load_module(&elf, so_bias);
     112        int ret = elf_load_module(&elf);
    113113
    114114        vfs_put(ofile);
     
    116116}
    117117
    118 int elf_load_file_name(const char *path, size_t so_bias, eld_flags_t flags,
    119     elf_finfo_t *info)
     118int elf_load_file_name(const char *path, eld_flags_t flags, elf_finfo_t *info)
    120119{
    121120        int file;
    122121        errno_t rc = vfs_lookup(path, 0, &file);
    123122        if (rc == EOK) {
    124                 int ret = elf_load_file(file, so_bias, flags, info);
     123                int ret = elf_load_file(file, flags, info);
    125124                vfs_put(file);
    126125                return ret;
     
    137136 *
    138137 * @param elf           Pointer to loader state buffer.
    139  * @param so_bias       Bias to use if the file is a shared object.
    140138 * @return EE_OK on success or EE_xx error code.
    141139 */
    142 static unsigned int elf_load_module(elf_ld_t *elf, size_t so_bias)
     140static unsigned int elf_load_module(elf_ld_t *elf)
    143141{
    144142        elf_header_t header_buf;
     
    154152                return EE_IO;
    155153        }
    156 
    157         elf->header = header;
    158154
    159155        /* Identify ELF */
     
    188184        }
    189185
     186        if (header->e_phoff == 0) {
     187                DPRINTF("Program header table is not present!\n");
     188                return EE_UNSUPPORTED;
     189        }
     190
     191        /* Read program header table.
     192         * Normally, there are very few program headers, so don't bother
     193         * with allocating memory dynamically.
     194         */
     195        const int phdr_cap = 16;
     196        elf_segment_header_t phdr[phdr_cap];
     197        size_t phdr_len = header->e_phnum * header->e_phentsize;
     198
     199        if (phdr_len > sizeof(phdr)) {
     200                DPRINTF("more than %d program headers\n", phdr_cap);
     201                return EE_UNSUPPORTED;
     202        }
     203
     204        pos = header->e_phoff;
     205        rc = vfs_read(elf->fd, &pos, phdr, phdr_len, &nr);
     206        if (rc != EOK || nr != phdr_len) {
     207                DPRINTF("Read error.\n");
     208                return EE_IO;
     209        }
     210
     211        uintptr_t module_base = UINTPTR_MAX;
     212        uintptr_t module_top = 0;
     213        uintptr_t base_offset = UINTPTR_MAX;
     214
     215        /* Walk through PT_LOAD headers, to find out the size of the module. */
     216        for (i = 0; i < header->e_phnum; i++) {
     217                if (phdr[i].p_type != PT_LOAD)
     218                        continue;
     219
     220                if (module_base > phdr[i].p_vaddr) {
     221                        module_base = phdr[i].p_vaddr;
     222                        base_offset = phdr[i].p_offset;
     223                }
     224                module_top = max(module_top, phdr[i].p_vaddr + phdr[i].p_memsz);
     225        }
     226
     227        if (base_offset != 0) {
     228                DPRINTF("ELF headers not present in the text segment.\n");
     229                return EE_INVALID;
     230        }
     231
    190232        /* Shared objects can be loaded with a bias */
    191         if (header->e_type == ET_DYN)
    192                 elf->bias = so_bias;
    193         else
     233        if (header->e_type != ET_DYN) {
    194234                elf->bias = 0;
     235        } else {
     236                if (module_base != 0) {
     237                        DPRINTF("Unexpected shared object format.\n");
     238                        return EE_INVALID;
     239                }
     240
     241                /* Attempt to allocate a span of memory large enough for the
     242                 * shared object.
     243                 */
     244                // FIXME: This is not reliable when we're running
     245                //        multi-threaded. Even if this part succeeds, later
     246                //        allocation can fail because another thread took the
     247                //        space in the meantime. This is only relevant for
     248                //        dlopen() though.
     249                void *area = as_area_create(AS_AREA_ANY, module_top,
     250                    AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE |
     251                    AS_AREA_LATE_RESERVE, AS_AREA_UNPAGED);
     252
     253                if (area == AS_MAP_FAILED) {
     254                        DPRINTF("Can't find suitable memory area.\n");
     255                        return EE_MEMORY;
     256                }
     257
     258                elf->bias = (uintptr_t) area;
     259                as_area_destroy(area);
     260        }
     261
     262        /* Load all loadable segments. */
     263        for (i = 0; i < header->e_phnum; i++) {
     264                if (phdr[i].p_type != PT_LOAD)
     265                        continue;
     266
     267                ret = load_segment(elf, &phdr[i]);
     268                if (ret != EE_OK)
     269                        return ret;
     270        }
     271
     272        void *base = (void *) module_base + elf->bias;
     273        elf->info->base = base;
    195274
    196275        /* Ensure valid TLS info even if there is no TLS header. */
     
    205284        /* Walk through all segment headers and process them. */
    206285        for (i = 0; i < header->e_phnum; i++) {
    207                 elf_segment_header_t segment_hdr;
    208 
    209                 pos = header->e_phoff + i * sizeof(elf_segment_header_t);
    210                 rc = vfs_read(elf->fd, &pos, &segment_hdr,
    211                     sizeof(elf_segment_header_t), &nr);
    212                 if (rc != EOK || nr != sizeof(elf_segment_header_t)) {
    213                         DPRINTF("Read error.\n");
    214                         return EE_IO;
    215                 }
    216 
    217                 ret = segment_header(elf, &segment_hdr);
     286                if (phdr[i].p_type == PT_LOAD)
     287                        continue;
     288
     289                ret = segment_header(elf, &phdr[i]);
    218290                if (ret != EE_OK)
    219291                        return ret;
     
    270342        case PT_NOTE:
    271343                break;
    272         case PT_LOAD:
    273                 return load_segment(elf, entry);
    274                 break;
    275344        case PT_INTERP:
    276345                elf->info->interp =
    277346                    (void *)((uint8_t *)entry->p_vaddr + elf->bias);
    278347
    279                 // FIXME: This actually won't work, because the text segment is
    280                 // not loaded yet.
    281 #if 0
    282348                if (elf->info->interp[entry->p_filesz - 1] != '\0') {
    283349                        DPRINTF("Unterminated ELF interp string.\n");
     
    285351                }
    286352                DPRINTF("interpreter: \"%s\"\n", elf->info->interp);
    287 #endif
    288353                break;
    289354        case PT_DYNAMIC:
Note: See TracChangeset for help on using the changeset viewer.