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

Last change on this file since 1d2f85e was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 9.4 KB
Line 
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
30 * @brief
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <align.h>
38#include <adt/list.h>
39#include <elf/elf_load.h>
40#include <errno.h>
41#include <loader/pcb.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <str.h>
45#include <macros.h>
46
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>
52#include <libarch/rtld/module.h>
53
54#include "../private/libc.h"
55
56/** Create module for static executable.
57 *
58 * @param rtld Run-time dynamic linker
59 * @param rmodule Place to store pointer to new module or @c NULL
60 * @return EOK on success, ENOMEM if out of memory
61 */
62errno_t module_create_static_exec(rtld_t *rtld, module_t **rmodule)
63{
64 module_t *module;
65
66 module = calloc(1, sizeof(module_t));
67 if (module == NULL)
68 return ENOMEM;
69
70 module->id = rtld_get_next_id(rtld);
71 module->dyn.soname = "[program]";
72
73 module->rtld = rtld;
74 module->exec = true;
75 module->local = true;
76
77 const elf_segment_header_t *tls =
78 elf_get_phdr(__progsymbols.elfstart, PT_TLS);
79
80 if (tls) {
81 uintptr_t bias = elf_get_bias(__progsymbols.elfstart);
82 module->tdata = (void *) (tls->p_vaddr + bias);
83 module->tdata_size = tls->p_filesz;
84 module->tbss_size = tls->p_memsz - tls->p_filesz;
85 module->tls_align = tls->p_align;
86 } else {
87 module->tdata = NULL;
88 module->tdata_size = 0;
89 module->tbss_size = 0;
90 module->tls_align = 1;
91 }
92
93 list_append(&module->modules_link, &rtld->modules);
94
95 if (rmodule != NULL)
96 *rmodule = module;
97 return EOK;
98}
99
100/** (Eagerly) process all relocation tables in a module.
101 *
102 * Currently works as if LD_BIND_NOW was specified.
103 */
104void module_process_relocs(module_t *m)
105{
106 DPRINTF("module_process_relocs('%s')\n", m->dyn.soname);
107
108 /* Do not relocate twice. */
109 if (m->relocated)
110 return;
111
112 module_process_pre_arch(m);
113
114 /* jmp_rel table */
115 if (m->dyn.jmp_rel != NULL) {
116 DPRINTF("jmp_rel table\n");
117 if (m->dyn.plt_rel == DT_REL) {
118 DPRINTF("jmp_rel table type DT_REL\n");
119 rel_table_process(m, m->dyn.jmp_rel, m->dyn.plt_rel_sz);
120 } else {
121 assert(m->dyn.plt_rel == DT_RELA);
122 DPRINTF("jmp_rel table type DT_RELA\n");
123 rela_table_process(m, m->dyn.jmp_rel, m->dyn.plt_rel_sz);
124 }
125 }
126
127 /* rel table */
128 if (m->dyn.rel != NULL) {
129 DPRINTF("rel table\n");
130 rel_table_process(m, m->dyn.rel, m->dyn.rel_sz);
131 }
132
133 /* rela table */
134 if (m->dyn.rela != NULL) {
135 DPRINTF("rela table\n");
136 rela_table_process(m, m->dyn.rela, m->dyn.rela_sz);
137 }
138
139 m->relocated = true;
140}
141
142/** Find module structure by soname/pathname.
143 *
144 * Used primarily to see if a module has already been loaded.
145 * Modules are compared according to their soname, i.e. possible
146 * path components are ignored.
147 */
148module_t *module_find(rtld_t *rtld, const char *name)
149{
150 const char *p, *soname;
151
152 DPRINTF("module_find('%s')\n", name);
153
154 /*
155 * If name contains slashes, treat it as a pathname and
156 * construct soname by chopping off the path. Otherwise
157 * treat it as soname.
158 */
159 p = str_rchr(name, '/');
160 soname = p ? (p + 1) : name;
161
162 /* Traverse list of all modules. Not extremely fast, but simple */
163 list_foreach(rtld->modules, modules_link, module_t, m) {
164 DPRINTF("m = %p\n", m);
165 if (str_cmp(m->dyn.soname, soname) == 0) {
166 return m; /* Found */
167 }
168 }
169
170 return NULL; /* Not found */
171}
172
173#define NAME_BUF_SIZE 64
174
175/** Load a module.
176 *
177 * Currently this trivially tries to load '/<name>'.
178 */
179module_t *module_load(rtld_t *rtld, const char *name, mlflags_t flags)
180{
181 elf_finfo_t info;
182 char name_buf[NAME_BUF_SIZE];
183 module_t *m;
184 int rc;
185
186 m = calloc(1, sizeof(module_t));
187 if (m == NULL) {
188 printf("malloc failed\n");
189 exit(1);
190 }
191
192 m->rtld = rtld;
193 m->id = rtld_get_next_id(rtld);
194
195 if ((flags & mlf_local) != 0)
196 m->local = true;
197
198 if (str_bytes(name) > NAME_BUF_SIZE - 2) {
199 printf("soname too long. increase NAME_BUF_SIZE\n");
200 exit(1);
201 }
202
203 /* Prepend soname with '/lib/' */
204 str_cpy(name_buf, NAME_BUF_SIZE, "/lib/");
205 str_cpy(name_buf + 5, NAME_BUF_SIZE - 5, name);
206
207 DPRINTF("filename:'%s'\n", name_buf);
208
209 rc = elf_load_file_name(name_buf, RTLD_MODULE_LDF, &info);
210 if (rc != EE_OK) {
211 printf("Failed to load '%s'\n", name_buf);
212 exit(1);
213 }
214
215 m->bias = elf_get_bias(info.base);
216
217 DPRINTF("loaded '%s' at 0x%zx\n", name_buf, m->bias);
218
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 */
233 list_append(&m->modules_link, &rtld->modules);
234
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;
239 m->tls_align = info.tls.tls_align;
240
241 DPRINTF("tdata at %p size %zu, tbss size %zu\n",
242 m->tdata, m->tdata_size, m->tbss_size);
243
244 return m;
245}
246
247/** Load all modules on which m (transitively) depends.
248 */
249void module_load_deps(module_t *m, mlflags_t flags)
250{
251 elf_dyn_t *dp;
252 char *dep_name;
253 module_t *dm;
254 size_t n, i;
255
256 DPRINTF("module_load_deps('%s')\n", m->dyn.soname);
257
258 /* Count direct dependencies */
259
260 dp = m->dyn.dynamic;
261 n = 0;
262
263 while (dp->d_tag != DT_NULL) {
264 if (dp->d_tag == DT_NEEDED)
265 ++n;
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);
293 dm = module_find(m->rtld, dep_name);
294 if (!dm) {
295 dm = module_load(m->rtld, dep_name, flags);
296 module_load_deps(dm, flags);
297 }
298
299 /* Save into deps table */
300 m->deps[i++] = dm;
301 }
302 ++dp;
303 }
304}
305
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
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 */
324void modules_process_relocs(rtld_t *rtld, module_t *start)
325{
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) {
329 module_process_relocs(m);
330 }
331 }
332}
333
334void modules_process_tls(rtld_t *rtld)
335{
336#ifdef CONFIG_TLS_VARIANT_1
337 rtld->tls_size = sizeof(tcb_t);
338 rtld->tls_align = _Alignof(tcb_t);
339
340 list_foreach(rtld->modules, modules_link, module_t, m) {
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;
346 rtld->tls_size += m->tdata_size + m->tbss_size;
347 }
348
349#else
350 rtld->tls_size = 0;
351 rtld->tls_align = _Alignof(tcb_t);
352
353 list_foreach(rtld->modules, modules_link, module_t, m) {
354 list_append(&m->imodules_link, &rtld->imodules);
355 rtld->tls_align = max(rtld->tls_align, m->tls_align);
356
357 /*
358 * We are allocating spans "backwards", here,
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;
364 }
365
366 /*
367 * We are in negative offsets. In order for the alignments to
368 * be correct, "zero" offset (i.e. the total size) must be aligned
369 * to the strictest alignment present.
370 * Note that the padding is actually in front of the TLS data,
371 * not after it.
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);
377#endif
378}
379
380/** Clear BFS tags of all modules.
381 */
382void modules_untag(rtld_t *rtld)
383{
384 list_foreach(rtld->modules, modules_link, module_t, m) {
385 m->bfs_tag = false;
386 }
387}
388
389/** @}
390 */
Note: See TracBrowser for help on using the repository browser.