Changeset f356618 in mainline for uspace/lib/c/generic


Ignore:
Timestamp:
2016-05-22T21:05:55Z (10 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
b3364b7c
Parents:
af2254ec (diff), 3a9414e (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge dynamic linking support for thread local storage.

Location:
uspace/lib/c/generic
Files:
7 edited

Legend:

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

    raf2254ec rf356618  
    4949        module_t *m;
    5050
    51         if (runtime_env == NULL) {
    52                 printf("Dynamic linker not set up -- initializing.\n");
    53                 rtld_init_static();
    54         }
    55 
    56         printf("dlopen(\"%s\", %d)\n", path, flag);
    57 
    58         printf("module_find('%s')\n", path);
    5951        m = module_find(runtime_env, path);
    6052        if (m == NULL) {
    61                 printf("NULL. module_load('%s')\n", path);
    6253                m = module_load(runtime_env, path, mlf_local);
    63                 printf("module_load_deps(m)\n");
    6454                module_load_deps(m, mlf_local);
    6555                /* Now relocate. */
    66                 printf("module_process_relocs(m)\n");
    6756                module_process_relocs(m);
    68         } else {
    69                 printf("not NULL\n");
    7057        }
    7158
     
    8168        module_t *sm;
    8269
    83         printf("dlsym(0x%lx, \"%s\")\n", (long)mod, sym_name);
    8470        sd = symbol_bfs_find(sym_name, (module_t *) mod, &sm);
    8571        if (sd != NULL) {
    86                 return symbol_get_addr(sd, sm);
     72                return symbol_get_addr(sd, sm, __tcb_get());
    8773        }
    8874
  • uspace/lib/c/generic/elf/elf_mod.c

    raf2254ec rf356618  
    248248}
    249249
     250/** Process TLS program header.
     251 *
     252 * @param elf  Pointer to loader state buffer.
     253 * @param hdr  TLS program header
     254 * @param info Place to store TLS info
     255 */
     256static void tls_program_header(elf_ld_t *elf, elf_segment_header_t *hdr,
     257    elf_tls_info_t *info)
     258{
     259        info->tdata = (void *)((uint8_t *)hdr->p_vaddr + elf->bias);
     260        info->tdata_size = hdr->p_filesz;
     261        info->tbss_size = hdr->p_memsz - hdr->p_filesz;
     262        info->tls_align = hdr->p_align;
     263}
     264
    250265/** Process segment header.
    251266 *
     267 * @param elf   Pointer to loader state buffer.
    252268 * @param entry Segment header.
    253269 *
     
    277293        case 0x70000000:
    278294                /* FIXME: MIPS reginfo */
     295                break;
     296        case PT_TLS:
     297                /* Parse TLS program header */
     298                tls_program_header(elf, entry, &elf->info->tls);
     299                DPRINTF("TLS header found at %p\n",
     300                    (void *)((uint8_t *)entry->p_vaddr + elf->bias));
    279301                break;
    280302        case PT_SHLIB:
  • uspace/lib/c/generic/libc.c

    raf2254ec rf356618  
    4141 */
    4242
     43#include <errno.h>
    4344#include <libc.h>
    4445#include <stdlib.h>
     
    6869        __malloc_init();
    6970       
     71        /* Save the PCB pointer */
     72        __pcb = (pcb_t *) pcb_ptr;
     73       
     74#ifdef CONFIG_RTLD
     75        if (__pcb != NULL && __pcb->rtld_runtime != NULL) {
     76                runtime_env = (rtld_t *) __pcb->rtld_runtime;
     77        } else {
     78                if (rtld_init_static() != EOK)
     79                        abort();
     80        }
     81#endif
     82       
    7083        fibril_t *fibril = fibril_setup();
    7184        if (fibril == NULL)
     
    7487        __tcb_set(fibril->tcb);
    7588       
    76         /* Save the PCB pointer */
    77         __pcb = (pcb_t *) pcb_ptr;
    7889       
    7990#ifdef FUTEX_UPGRADABLE
     
    89100        char **argv;
    90101       
    91 #ifdef CONFIG_RTLD
    92         if (__pcb != NULL && __pcb->rtld_runtime != NULL) {
    93                 runtime_env = (rtld_t *) __pcb->rtld_runtime;
    94         }
    95 #endif
    96102        /*
    97103         * Get command line arguments and initialize
  • uspace/lib/c/generic/rtld/module.c

    raf2254ec rf356618  
    3737#include <adt/list.h>
    3838#include <elf/elf_load.h>
     39#include <errno.h>
    3940#include <fcntl.h>
    4041#include <loader/pcb.h>
     
    4849#include <rtld/rtld_arch.h>
    4950#include <rtld/module.h>
     51
     52/** Create module for static executable.
     53 *
     54 * @param rtld Run-time dynamic linker
     55 * @param rmodule Place to store pointer to new module or @c NULL
     56 * @return EOK on success, ENOMEM if out of memory
     57 */
     58int module_create_static_exec(rtld_t *rtld, module_t **rmodule)
     59{
     60        module_t *module;
     61
     62        module = calloc(1, sizeof(module_t));
     63        if (module == NULL)
     64                return ENOMEM;
     65
     66        module->id = rtld_get_next_id(rtld);
     67        module->dyn.soname = "[program]";
     68
     69        module->rtld = rtld;
     70        module->exec = true;
     71        module->local = true;
     72
     73        module->tdata = &_tdata_start;
     74        module->tdata_size = &_tdata_end - &_tdata_start;
     75        module->tbss_size = &_tbss_end - &_tbss_start;
     76        module->tls_align = (uintptr_t)&_tls_alignment;
     77
     78        list_append(&module->modules_link, &rtld->modules);
     79
     80        if (rmodule != NULL)
     81                *rmodule = module;
     82        return EOK;
     83}
    5084
    5185/** (Eagerly) process all relocation tables in a module.
     
    135169
    136170        m = calloc(1, sizeof(module_t));
    137         if (!m) {
     171        if (m == NULL) {
    138172                printf("malloc failed\n");
    139173                exit(1);
     
    141175
    142176        m->rtld = rtld;
     177        m->id = rtld_get_next_id(rtld);
     178
    143179        if ((flags & mlf_local) != 0)
    144180                m->local = true;
     
    181217        /* Insert into the list of loaded modules */
    182218        list_append(&m->modules_link, &rtld->modules);
     219
     220        /* Copy TLS info */
     221        m->tdata = info.tls.tdata;
     222        m->tdata_size = info.tls.tdata_size;
     223        m->tbss_size = info.tls.tbss_size;
     224        m->tls_align = info.tls.tls_align;
     225
     226        DPRINTF("tdata at %p size %zu, tbss size %zu\n",
     227            m->tdata, m->tdata_size, m->tbss_size);
    183228
    184229        return m;
     
    243288}
    244289
     290/** Find module structure by ID. */
     291module_t *module_by_id(rtld_t *rtld, unsigned long id)
     292{
     293        list_foreach(rtld->modules, modules_link, module_t, m) {
     294                if (m->id == id)
     295                        return m;
     296        }
     297
     298        return NULL;
     299}
     300
    245301/** Process relocations in modules.
    246302 *
     
    260316}
    261317
     318void modules_process_tls(rtld_t *rtld)
     319{
     320#ifdef CONFIG_TLS_VARIANT_1
     321        list_foreach(rtld->modules, modules_link, module_t, m) {
     322                m->ioffs = rtld->tls_size;
     323                list_append(&m->imodules_link, &rtmd->imodules);
     324                rtld->tls_size += m->tdata_size + m->tbss_size;
     325        }
     326#else /* CONFIG_TLS_VARIANT_2 */
     327        size_t offs;
     328
     329        list_foreach(rtld->modules, modules_link, module_t, m) {
     330                rtld->tls_size += m->tdata_size + m->tbss_size;
     331        }
     332
     333        offs = 0;
     334        list_foreach(rtld->modules, modules_link, module_t, m) {
     335                offs += m->tdata_size + m->tbss_size;
     336                m->ioffs = rtld->tls_size - offs;
     337                list_append(&m->imodules_link, &rtld->imodules);
     338        }
     339#endif
     340}
     341
    262342/** Clear BFS tags of all modules.
    263343 */
  • uspace/lib/c/generic/rtld/rtld.c

    raf2254ec rf356618  
    4343rtld_t *runtime_env;
    4444static rtld_t rt_env_static;
    45 static module_t prog_mod;
    4645
    4746/** Initialize the runtime linker for use in a statically-linked executable. */
    48 void rtld_init_static(void)
    49 {
     47int rtld_init_static(void)
     48{
     49        int rc;
     50
    5051        runtime_env = &rt_env_static;
    5152        list_initialize(&runtime_env->modules);
     53        list_initialize(&runtime_env->imodules);
    5254        runtime_env->next_bias = 0x2000000;
    5355        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;
    5465}
    5566
     
    6273{
    6374        rtld_t *env;
     75        module_t *prog;
    6476
    6577        DPRINTF("Load dynamically linked program.\n");
     
    7082                return ENOMEM;
    7183
     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
    7292        /*
    7393         * First we need to process dynamic sections of the executable
     
    7696
    7797        DPRINTF("Parse program .dynamic section at %p\n", p_info->dynamic);
    78         dynamic_parse(p_info->dynamic, 0, &prog_mod.dyn);
    79         prog_mod.bias = 0;
    80         prog_mod.dyn.soname = "[program]";
    81         prog_mod.rtld = env;
    82         prog_mod.exec = true;
    83         prog_mod.local = false;
     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);
    84113
    85114        /* Initialize list of loaded modules */
    86115        list_initialize(&env->modules);
    87         list_append(&prog_mod.modules_link, &env->modules);
     116        list_initialize(&env->imodules);
     117        list_append(&prog->modules_link, &env->modules);
    88118
    89119        /* Pointer to program module. Used as root of the module graph. */
    90         env->program = &prog_mod;
     120        env->program = prog;
    91121
    92122        /* Work around non-existent memory space allocation. */
     
    98128
    99129        DPRINTF("Load all program dependencies\n");
    100         module_load_deps(&prog_mod, 0);
     130        module_load_deps(prog, 0);
     131
     132        /* Compute static TLS size */
     133        modules_process_tls(env);
    101134
    102135        /*
     
    106139        /* Process relocations in all modules */
    107140        DPRINTF("Relocate all modules\n");
    108         modules_process_relocs(env, &prog_mod);
     141        modules_process_relocs(env, prog);
    109142
    110143        *rre = env;
     
    112145}
    113146
     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;
     271}
     272
    114273/** @}
    115274 */
  • uspace/lib/c/generic/rtld/symbol.c

    raf2254ec rf356618  
    249249}
    250250
    251 void *symbol_get_addr(elf_symbol_t *sym, module_t *m)
    252 {
    253         if (sym->st_shndx == SHN_ABS) {
     251/** Get symbol address.
     252 *
     253 * @param sym Symbol
     254 * @param m Module contaning the symbol
     255 * @param tcb TCB of the thread whose thread-local variable instance should
     256 *            be returned. If @a tcb is @c NULL then @c NULL is returned for
     257 *            thread-local variables.
     258 *
     259 * @return Symbol address
     260 */
     261void *symbol_get_addr(elf_symbol_t *sym, module_t *m, tcb_t *tcb)
     262{
     263        if (ELF_ST_TYPE(sym->st_info) == STT_TLS) {
     264                if (tcb == NULL)
     265                        return NULL;
     266                return rtld_tls_get_addr(m->rtld, tcb, m->id, sym->st_value);
     267        } else if (sym->st_shndx == SHN_ABS) {
    254268                /* Do not add bias to absolute symbols */
    255269                return (void *) sym->st_value;
  • uspace/lib/c/generic/tls.c

    raf2254ec rf356618  
    3434 * Support for thread-local storage, as described in:
    3535 *      Drepper U.: ELF Handling For Thread-Local Storage, 2005
    36  *
    37  * Only static model is supported.
    38  */
     36 */
    3937
    4038#include <tls.h>
    4139#include <malloc.h>
    4240#include <str.h>
    43 #include <align.h>
    4441#include <unistd.h>
    4542
     43#ifdef CONFIG_RTLD
     44#include <rtld/rtld.h>
     45#endif
     46
     47size_t tls_get_size(void)
     48{
     49#ifdef CONFIG_RTLD
     50        if (runtime_env != NULL)
     51                return runtime_env->tls_size;
     52#endif
     53        return &_tbss_end - &_tdata_start;
     54}
     55
     56/** Get address of static TLS block */
     57void *tls_get(void)
     58{
     59#ifdef CONFIG_TLS_VARIANT_1
     60        return (uint8_t *)__tcb_get() + sizeof(tcb_t);
     61#else /* CONFIG_TLS_VARIANT_2 */
     62        return (uint8_t *)__tcb_get() - tls_get_size();
     63#endif
     64}
     65
    4666/** Create TLS (Thread Local Storage) data structures.
    47  *
    48  * The code requires, that sections .tdata and .tbss are adjacent. It may be
    49  * changed in the future.
    5067 *
    5168 * @return Pointer to TCB.
     
    5673        tcb_t *tcb;
    5774        size_t tls_size = &_tbss_end - &_tdata_start;
    58        
     75
     76#ifdef CONFIG_RTLD
     77        if (runtime_env != NULL)
     78                return rtld_tls_make(runtime_env);
     79#endif
    5980        tcb = tls_alloc_arch(&data, tls_size);
    6081        if (!tcb)
    6182                return NULL;
    62        
     83
    6384        /*
    6485         * Copy thread local data from the initialization image.
     
    7697void tls_free(tcb_t *tcb)
    7798{
    78         size_t tls_size = &_tbss_end - &_tdata_start;
    79         tls_free_arch(tcb, tls_size);
     99#ifdef CONFIG_RTLD
     100        free(tcb->dtv);
     101#endif
     102        tls_free_arch(tcb, tls_get_size());
    80103}
    81104
     
    89112tcb_t *tls_alloc_variant_1(void **data, size_t size)
    90113{
    91         tcb_t *result;
     114        tcb_t *tcb;
    92115
    93         result = malloc(sizeof(tcb_t) + size);
    94         if (!result)
     116        tcb = malloc(sizeof(tcb_t) + size);
     117        if (!tcb)
    95118                return NULL;
    96         *data = ((void *)result) + sizeof(tcb_t);
     119        *data = ((void *)tcb) + sizeof(tcb_t);
     120#ifdef CONFIG_RTLD
     121        tcb->dtv = NULL;
     122#endif
    97123
    98         return result;
     124        return tcb;
    99125}
    100126
     
    121147{
    122148        tcb_t *tcb;
    123        
    124         size = ALIGN_UP(size, &_tls_alignment);
    125         *data = memalign((uintptr_t) &_tls_alignment, sizeof(tcb_t) + size);
    126         if (!*data)
     149
     150        *data = malloc(sizeof(tcb_t) + size);
     151        if (*data == NULL)
    127152                return NULL;
    128153        tcb = (tcb_t *) (*data + size);
    129154        tcb->self = tcb;
     155#ifdef CONFIG_RTLD
     156        tcb->dtv = NULL;
     157#endif
    130158
    131159        return tcb;
     
    139167void tls_free_variant_2(tcb_t *tcb, size_t size)
    140168{
    141         size = ALIGN_UP(size, &_tls_alignment);
    142169        void *start = ((void *) tcb) - size;
    143170        free(start);
Note: See TracChangeset for help on using the changeset viewer.