source: mainline/uspace/lib/c/generic/rtld/module.c@ a63966d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a63966d was 40abf56, checked in by Jiří Zárevúcky <jiri.zarevucky@…>, 7 years ago

Make sure that a thread with uninitialized TLS does not need to call malloc()
to initialize it.

For threads and tasks created by loader, we create TLS beforehand and pass
it to the child. For tasks spawned directly by the kernel, we require it is
a static executable and allocate the initial TLS using as_area_create() instead
of the libc allocator.

  • Property mode set to 100644
File size: 9.4 KB
RevLine 
[1ea99cc]1/*
2 * Copyright (c) 2008 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup rtld rtld
30 * @brief
31 * @{
[1b20da0]32 */
[1ea99cc]33/**
34 * @file
35 */
36
[4f205248]37#include <align.h>
[bfdb5af1]38#include <adt/list.h>
39#include <elf/elf_load.h>
[6adb775f]40#include <errno.h>
[bfdb5af1]41#include <loader/pcb.h>
[1ea99cc]42#include <stdio.h>
43#include <stdlib.h>
[1d6dd2a]44#include <str.h>
[4f205248]45#include <macros.h>
[1ea99cc]46
[8a1fb09]47#include <rtld/rtld.h>
48#include <rtld/rtld_debug.h>
49#include <rtld/dynamic.h>
50#include <rtld/rtld_arch.h>
51#include <rtld/module.h>
[1ea99cc]52
[2eadda9]53#include "../private/libc.h"
54
[153c7a29]55/** Create module for static executable.
56 *
57 * @param rtld Run-time dynamic linker
58 * @param rmodule Place to store pointer to new module or @c NULL
59 * @return EOK on success, ENOMEM if out of memory
60 */
[b7fd2a0]61errno_t module_create_static_exec(rtld_t *rtld, module_t **rmodule)
[153c7a29]62{
63 module_t *module;
64
65 module = calloc(1, sizeof(module_t));
66 if (module == NULL)
67 return ENOMEM;
68
69 module->id = rtld_get_next_id(rtld);
70 module->dyn.soname = "[program]";
71
72 module->rtld = rtld;
73 module->exec = true;
74 module->local = true;
75
[2c4e1cc]76 const elf_segment_header_t *tls =
[2eadda9]77 elf_get_phdr(__progsymbols.elfstart, PT_TLS);
[2c4e1cc]78
[4f205248]79 if (tls) {
[2eadda9]80 uintptr_t bias = elf_get_bias(__progsymbols.elfstart);
[4f205248]81 module->tdata = (void *) (tls->p_vaddr + bias);
82 module->tdata_size = tls->p_filesz;
83 module->tbss_size = tls->p_memsz - tls->p_filesz;
84 module->tls_align = tls->p_align;
85 } else {
86 module->tdata = NULL;
87 module->tdata_size = 0;
88 module->tbss_size = 0;
89 module->tls_align = 1;
90 }
[153c7a29]91
92 list_append(&module->modules_link, &rtld->modules);
93
94 if (rmodule != NULL)
95 *rmodule = module;
96 return EOK;
97}
98
[1ea99cc]99/** (Eagerly) process all relocation tables in a module.
100 *
101 * Currently works as if LD_BIND_NOW was specified.
102 */
103void module_process_relocs(module_t *m)
104{
105 DPRINTF("module_process_relocs('%s')\n", m->dyn.soname);
106
107 /* Do not relocate twice. */
[1433ecda]108 if (m->relocated)
109 return;
[1ea99cc]110
111 module_process_pre_arch(m);
112
[634e020]113 /* jmp_rel table */
114 if (m->dyn.jmp_rel != NULL) {
115 DPRINTF("jmp_rel table\n");
116 if (m->dyn.plt_rel == DT_REL) {
117 DPRINTF("jmp_rel table type DT_REL\n");
[1ea99cc]118 rel_table_process(m, m->dyn.jmp_rel, m->dyn.plt_rel_sz);
[634e020]119 } else {
120 assert(m->dyn.plt_rel == DT_RELA);
121 DPRINTF("jmp_rel table type DT_RELA\n");
122 rela_table_process(m, m->dyn.jmp_rel, m->dyn.plt_rel_sz);
[1ea99cc]123 }
[634e020]124 }
125
126 /* rel table */
127 if (m->dyn.rel != NULL) {
128 DPRINTF("rel table\n");
129 rel_table_process(m, m->dyn.rel, m->dyn.rel_sz);
130 }
131
132 /* rela table */
133 if (m->dyn.rela != NULL) {
134 DPRINTF("rela table\n");
135 rela_table_process(m, m->dyn.rela, m->dyn.rela_sz);
[1ea99cc]136 }
137
138 m->relocated = true;
139}
140
141/** Find module structure by soname/pathname.
142 *
143 * Used primarily to see if a module has already been loaded.
144 * Modules are compared according to their soname, i.e. possible
145 * path components are ignored.
146 */
[17341d4]147module_t *module_find(rtld_t *rtld, const char *name)
[1ea99cc]148{
[04803bf]149 const char *p, *soname;
[1ea99cc]150
[a6dffb8]151 DPRINTF("module_find('%s')\n", name);
152
[1ea99cc]153 /*
154 * If name contains slashes, treat it as a pathname and
155 * construct soname by chopping off the path. Otherwise
156 * treat it as soname.
157 */
158 p = str_rchr(name, '/');
159 soname = p ? (p + 1) : name;
160
161 /* Traverse list of all modules. Not extremely fast, but simple */
[17341d4]162 list_foreach(rtld->modules, modules_link, module_t, m) {
[4b63316]163 DPRINTF("m = %p\n", m);
[1ea99cc]164 if (str_cmp(m->dyn.soname, soname) == 0) {
165 return m; /* Found */
166 }
167 }
[a35b458]168
[1ea99cc]169 return NULL; /* Not found */
170}
171
172#define NAME_BUF_SIZE 64
173
174/** Load a module.
175 *
176 * Currently this trivially tries to load '/<name>'.
177 */
[5035ba05]178module_t *module_load(rtld_t *rtld, const char *name, mlflags_t flags)
[1ea99cc]179{
[17341d4]180 elf_finfo_t info;
[1ea99cc]181 char name_buf[NAME_BUF_SIZE];
182 module_t *m;
183 int rc;
[a35b458]184
[6adb775f]185 m = calloc(1, sizeof(module_t));
186 if (m == NULL) {
[1ea99cc]187 printf("malloc failed\n");
188 exit(1);
189 }
[a35b458]190
[17341d4]191 m->rtld = rtld;
[6adb775f]192 m->id = rtld_get_next_id(rtld);
[17341d4]193
[5035ba05]194 if ((flags & mlf_local) != 0)
195 m->local = true;
[17341d4]196
[1ea99cc]197 if (str_size(name) > NAME_BUF_SIZE - 2) {
198 printf("soname too long. increase NAME_BUF_SIZE\n");
199 exit(1);
200 }
201
202 /* Prepend soname with '/lib/' */
203 str_cpy(name_buf, NAME_BUF_SIZE, "/lib/");
204 str_cpy(name_buf + 5, NAME_BUF_SIZE - 5, name);
205
206
207 DPRINTF("filename:'%s'\n", name_buf);
208
[742fc98e]209 rc = elf_load_file_name(name_buf, ELDF_RW, &info);
[1ea99cc]210 if (rc != EE_OK) {
211 printf("Failed to load '%s'\n", name_buf);
212 exit(1);
213 }
214
[742fc98e]215 m->bias = elf_get_bias(info.base);
216
217 DPRINTF("loaded '%s' at 0x%zx\n", name_buf, m->bias);
218
[1ea99cc]219 if (info.dynamic == NULL) {
220 printf("Error: '%s' is not a dynamically-linked object.\n",
221 name_buf);
222 exit(1);
223 }
224
225 /* Pending relocation. */
226 m->relocated = false;
227
228 DPRINTF("parse dynamic section\n");
229 /* Parse ELF .dynamic section. Store info to m->dyn. */
230 dynamic_parse(info.dynamic, m->bias, &m->dyn);
231
232 /* Insert into the list of loaded modules */
[17341d4]233 list_append(&m->modules_link, &rtld->modules);
[a35b458]234
[6adb775f]235 /* Copy TLS info */
236 m->tdata = info.tls.tdata;
237 m->tdata_size = info.tls.tdata_size;
238 m->tbss_size = info.tls.tbss_size;
[29405ac]239 m->tls_align = info.tls.tls_align;
[a35b458]240
[153c7a29]241 DPRINTF("tdata at %p size %zu, tbss size %zu\n",
[6adb775f]242 m->tdata, m->tdata_size, m->tbss_size);
243
[1ea99cc]244 return m;
245}
246
247/** Load all modules on which m (transitively) depends.
248 */
[5035ba05]249void module_load_deps(module_t *m, mlflags_t flags)
[1ea99cc]250{
251 elf_dyn_t *dp;
252 char *dep_name;
253 module_t *dm;
254 size_t n, i;
255
[a6dffb8]256 DPRINTF("module_load_deps('%s')\n", m->dyn.soname);
257
[1ea99cc]258 /* Count direct dependencies */
[a35b458]259
[1ea99cc]260 dp = m->dyn.dynamic;
261 n = 0;
262
263 while (dp->d_tag != DT_NULL) {
[1433ecda]264 if (dp->d_tag == DT_NEEDED)
265 ++n;
[1ea99cc]266 ++dp;
267 }
268
269 /* Create an array of pointers to direct dependencies */
270
271 m->n_deps = n;
272
273 if (n == 0) {
274 /* There are no dependencies, so we are done. */
275 m->deps = NULL;
276 return;
277 }
278
279 m->deps = malloc(n * sizeof(module_t *));
280 if (!m->deps) {
281 printf("malloc failed\n");
282 exit(1);
283 }
284
285 i = 0; /* Current dependency index */
286 dp = m->dyn.dynamic;
287
288 while (dp->d_tag != DT_NULL) {
289 if (dp->d_tag == DT_NEEDED) {
290 dep_name = m->dyn.str_tab + dp->d_un.d_val;
291
292 DPRINTF("%s needs %s\n", m->dyn.soname, dep_name);
[17341d4]293 dm = module_find(m->rtld, dep_name);
[1ea99cc]294 if (!dm) {
[5035ba05]295 dm = module_load(m->rtld, dep_name, flags);
296 module_load_deps(dm, flags);
[1ea99cc]297 }
298
299 /* Save into deps table */
300 m->deps[i++] = dm;
301 }
302 ++dp;
303 }
304}
305
[6adb775f]306/** Find module structure by ID. */
307module_t *module_by_id(rtld_t *rtld, unsigned long id)
308{
309 list_foreach(rtld->modules, modules_link, module_t, m) {
310 if (m->id == id)
311 return m;
312 }
313
314 return NULL;
315}
316
[1ea99cc]317/** Process relocations in modules.
318 *
319 * Processes relocations in @a start and all its dependencies.
320 * Modules that have already been relocated are unaffected.
321 *
322 * @param start The module where to start from.
323 */
[17341d4]324void modules_process_relocs(rtld_t *rtld, module_t *start)
[1ea99cc]325{
[17341d4]326 list_foreach(rtld->modules, modules_link, module_t, m) {
327 /* Skip rtld module, since it has already been processed */
328 if (m != &rtld->rtld) {
[1ea99cc]329 module_process_relocs(m);
330 }
331 }
332}
333
[6adb775f]334void modules_process_tls(rtld_t *rtld)
335{
[29405ac]336#ifdef CONFIG_TLS_VARIANT_1
[4f205248]337 rtld->tls_size = sizeof(tcb_t);
338 rtld->tls_align = _Alignof(tcb_t);
[29405ac]339
340 list_foreach(rtld->modules, modules_link, module_t, m) {
[4f205248]341 list_append(&m->imodules_link, &rtld->imodules);
342 rtld->tls_align = max(rtld->tls_align, m->tls_align);
343
344 rtld->tls_size = ALIGN_UP(rtld->tls_size, m->tls_align);
345 m->tpoff = rtld->tls_size;
[29405ac]346 rtld->tls_size += m->tdata_size + m->tbss_size;
347 }
348
[4f205248]349#else
350 rtld->tls_size = 0;
351 rtld->tls_align = _Alignof(tcb_t);
352
[29405ac]353 list_foreach(rtld->modules, modules_link, module_t, m) {
[bab0f42]354 list_append(&m->imodules_link, &rtld->imodules);
[4f205248]355 rtld->tls_align = max(rtld->tls_align, m->tls_align);
356
[7c3fb9b]357 /*
358 * We are allocating spans "backwards", here,
[4f205248]359 * as described in U. Drepper's paper.
360 */
361 rtld->tls_size += m->tdata_size + m->tbss_size;
362 rtld->tls_size = ALIGN_UP(rtld->tls_size, m->tls_align);
363 m->tpoff = -(ptrdiff_t) rtld->tls_size;
[29405ac]364 }
[4f205248]365
[7c3fb9b]366 /*
367 * We are in negative offsets. In order for the alignments to
[4f205248]368 * be correct, "zero" offset (i.e. the total size) must be aligned
369 * to the strictest alignment present.
[40abf56]370 * Note that the padding is actually in front of the TLS data,
371 * not after it.
[4f205248]372 */
373 rtld->tls_size = ALIGN_UP(rtld->tls_size, rtld->tls_align);
374
375 /* Space for the TCB. */
376 rtld->tls_size += sizeof(tcb_t);
[29405ac]377#endif
[6adb775f]378}
379
[1ea99cc]380/** Clear BFS tags of all modules.
381 */
[17341d4]382void modules_untag(rtld_t *rtld)
[1ea99cc]383{
[17341d4]384 list_foreach(rtld->modules, modules_link, module_t, m) {
[1ea99cc]385 m->bfs_tag = false;
386 }
387}
388
389/** @}
390 */
Note: See TracBrowser for help on using the repository browser.