Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/rtld/rtld.c

    r9d58539 r153c7a29  
    3535 */
    3636
     37#include <errno.h>
     38#include <rtld/module.h>
    3739#include <rtld/rtld.h>
    38 
    39 runtime_env_t *runtime_env;
    40 static runtime_env_t rt_env_static;
    41 
    42 /** Initialize the loder for use in a statically-linked binary. */
    43 void rtld_init_static(void)
    44 {
     40#include <rtld/rtld_debug.h>
     41#include <stdlib.h>
     42
     43rtld_t *runtime_env;
     44static rtld_t rt_env_static;
     45
     46/** Initialize the runtime linker for use in a statically-linked executable. */
     47int rtld_init_static(void)
     48{
     49        int rc;
     50
    4551        runtime_env = &rt_env_static;
    4652        list_initialize(&runtime_env->modules);
     53        list_initialize(&runtime_env->imodules);
    4754        runtime_env->next_bias = 0x2000000;
    4855        runtime_env->program = NULL;
     56        runtime_env->next_id = 1;
     57
     58        rc = module_create_static_exec(runtime_env, NULL);
     59        if (rc != EOK)
     60                return rc;
     61
     62        modules_process_tls(runtime_env);
     63
     64        return EOK;
     65}
     66
     67/** Initialize and process a dynamically linked executable.
     68 *
     69 * @param p_info Program info
     70 * @return EOK on success or non-zero error code
     71 */
     72int rtld_prog_process(elf_finfo_t *p_info, rtld_t **rre)
     73{
     74        rtld_t *env;
     75        module_t *prog;
     76
     77        DPRINTF("Load dynamically linked program.\n");
     78
     79        /* Allocate new RTLD environment to pass to the loaded program */
     80        env = calloc(1, sizeof(rtld_t));
     81        if (env == NULL)
     82                return ENOMEM;
     83
     84        env->next_id = 1;
     85
     86        prog = calloc(1, sizeof(module_t));
     87        if (prog == NULL) {
     88                free(env);
     89                return ENOMEM;
     90        }
     91
     92        /*
     93         * First we need to process dynamic sections of the executable
     94         * program and insert it into the module graph.
     95         */
     96
     97        DPRINTF("Parse program .dynamic section at %p\n", p_info->dynamic);
     98        dynamic_parse(p_info->dynamic, 0, &prog->dyn);
     99        prog->bias = 0;
     100        prog->dyn.soname = "[program]";
     101        prog->rtld = env;
     102        prog->id = rtld_get_next_id(env);
     103        prog->exec = true;
     104        prog->local = false;
     105
     106        prog->tdata = p_info->tls.tdata;
     107        prog->tdata_size = p_info->tls.tdata_size;
     108        prog->tbss_size = p_info->tls.tbss_size;
     109        prog->tls_align = p_info->tls.tls_align;
     110
     111        DPRINTF("prog tdata at %p size %zu, tbss size %zu\n",
     112            prog->tdata, prog->tdata_size, prog->tbss_size);
     113
     114        /* Initialize list of loaded modules */
     115        list_initialize(&env->modules);
     116        list_initialize(&env->imodules);
     117        list_append(&prog->modules_link, &env->modules);
     118
     119        /* Pointer to program module. Used as root of the module graph. */
     120        env->program = prog;
     121
     122        /* Work around non-existent memory space allocation. */
     123        env->next_bias = 0x1000000;
     124
     125        /*
     126         * Now we can continue with loading all other modules.
     127         */
     128
     129        DPRINTF("Load all program dependencies\n");
     130        module_load_deps(prog, 0);
     131
     132        /* Compute static TLS size */
     133        modules_process_tls(env);
     134
     135        /*
     136         * Now relocate/link all modules together.
     137         */
     138
     139        /* Process relocations in all modules */
     140        DPRINTF("Relocate all modules\n");
     141        modules_process_relocs(env, prog);
     142
     143        *rre = env;
     144        return EOK;
     145}
     146
     147/** Create TLS (Thread Local Storage) data structures.
     148 *
     149 * @return Pointer to TCB.
     150 */
     151tcb_t *rtld_tls_make(rtld_t *rtld)
     152{
     153        void *data;
     154        tcb_t *tcb;
     155        size_t offset;
     156        void **dtv;
     157        size_t nmods;
     158        size_t i;
     159
     160        tcb = tls_alloc_arch(&data, rtld->tls_size);
     161        if (tcb == NULL)
     162                return NULL;
     163
     164        /** Allocate dynamic thread vector */
     165        nmods = list_count(&rtld->imodules);
     166        dtv = malloc((nmods + 1) * sizeof(void *));
     167        if (dtv == NULL) {
     168                tls_free(tcb);
     169                return NULL;
     170        }
     171
     172        /*
     173         * We define generation number to be equal to vector length.
     174         * We start with a vector covering the initially loaded modules.
     175         */
     176        DTV_GN(dtv) = nmods;
     177
     178        /*
     179         * Copy thread local data from the initialization images of initial
     180         * modules. Zero out thread-local uninitialized data.
     181         */
     182
     183#ifdef CONFIG_TLS_VARIANT_1
     184        /*
     185         * Ascending addresses
     186         */
     187        offset = 0; i = 1;
     188        list_foreach(rtld->imodules, imodules_link, module_t, m) {
     189                assert(i == m->id);
     190                assert(offset + m->tdata_size + m->tbss_size <= rtld->tls_size);
     191                dtv[i++] = data + offset;
     192                memcpy(data + offset, m->tdata, m->tdata_size);
     193                offset += m->tdata_size;
     194                memset(data + offset, 0, m->tbss_size);
     195                offset += m->tbss_size;
     196        }
     197#else /* CONFIG_TLS_VARIANT_2 */
     198        /*
     199         * Descending addresses
     200         */
     201        offset = 0; i = 1;
     202        list_foreach(rtld->imodules, imodules_link, module_t, m) {
     203                assert(i == m->id);
     204                assert(offset + m->tdata_size + m->tbss_size <= rtld->tls_size);
     205                offset += m->tbss_size;
     206                memset(data + rtld->tls_size - offset, 0, m->tbss_size);
     207                offset += m->tdata_size;
     208                memcpy(data + rtld->tls_size - offset, m->tdata, m->tdata_size);
     209                dtv[i++] = data + rtld->tls_size - offset;
     210        }
     211#endif
     212
     213        tcb->dtv = dtv;
     214        return tcb;
     215}
     216
     217unsigned long rtld_get_next_id(rtld_t *rtld)
     218{
     219        return rtld->next_id++;
     220}
     221
     222/** Get address of thread-local variable.
     223 *
     224 * @param rtld RTLD instance
     225 * @param tcb TCB of the thread whose instance to return
     226 * @param mod_id Module ID
     227 * @param offset Offset within TLS block of the module
     228 *
     229 * @return Address of thread-local variable
     230 */
     231void *rtld_tls_get_addr(rtld_t *rtld, tcb_t *tcb, unsigned long mod_id,
     232    unsigned long offset)
     233{
     234        module_t *m;
     235        size_t dtv_len;
     236        void *tls_block;
     237
     238        dtv_len = DTV_GN(tcb->dtv);
     239        if (dtv_len < mod_id) {
     240                /* Vector is short */
     241
     242                tcb->dtv = realloc(tcb->dtv, (1 + mod_id) * sizeof(void *));
     243                /* XXX This can fail if OOM */
     244                assert(tcb->dtv != NULL);
     245                /* Zero out new part of vector */
     246                memset(tcb->dtv + (1 + dtv_len), 0, (mod_id - dtv_len) *
     247                    sizeof(void *));
     248        }
     249
     250        if (tcb->dtv[mod_id] == NULL) {
     251                /* TLS block is not allocated */
     252
     253                m = module_by_id(rtld, mod_id);
     254                assert(m != NULL);
     255                /* Should not be initial module, those have TLS pre-allocated */
     256                assert(!link_used(&m->imodules_link));
     257
     258                tls_block = malloc(m->tdata_size + m->tbss_size);
     259                /* XXX This can fail if OOM */
     260                assert(tls_block != NULL);
     261
     262                /* Copy tdata */
     263                memcpy(tls_block, m->tdata, m->tdata_size);
     264                /* Zero out tbss */
     265                memset(tls_block + m->tdata_size, 0, m->tbss_size);
     266
     267                tcb->dtv[mod_id] = tls_block;
     268        }
     269
     270        return (uint8_t *)(tcb->dtv[mod_id]) + offset;
    49271}
    50272
Note: See TracChangeset for help on using the changeset viewer.