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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.5 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 rtld
30 * @brief
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <adt/list.h>
38#include <elf/elf_load.h>
39#include <errno.h>
40#include <loader/pcb.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <str.h>
44
45#include <rtld/rtld.h>
46#include <rtld/rtld_debug.h>
47#include <rtld/dynamic.h>
48#include <rtld/rtld_arch.h>
49#include <rtld/module.h>
50
51/** Create module for static executable.
52 *
53 * @param rtld Run-time dynamic linker
54 * @param rmodule Place to store pointer to new module or @c NULL
55 * @return EOK on success, ENOMEM if out of memory
56 */
57errno_t module_create_static_exec(rtld_t *rtld, module_t **rmodule)
58{
59 module_t *module;
60
61 module = calloc(1, sizeof(module_t));
62 if (module == NULL)
63 return ENOMEM;
64
65 module->id = rtld_get_next_id(rtld);
66 module->dyn.soname = "[program]";
67
68 module->rtld = rtld;
69 module->exec = true;
70 module->local = true;
71
72 module->tdata = &_tdata_start;
73 module->tdata_size = &_tdata_end - &_tdata_start;
74 module->tbss_size = &_tbss_end - &_tbss_start;
75 module->tls_align = (uintptr_t)&_tls_alignment;
76
77 list_append(&module->modules_link, &rtld->modules);
78
79 if (rmodule != NULL)
80 *rmodule = module;
81 return EOK;
82}
83
84/** (Eagerly) process all relocation tables in a module.
85 *
86 * Currently works as if LD_BIND_NOW was specified.
87 */
88void module_process_relocs(module_t *m)
89{
90 DPRINTF("module_process_relocs('%s')\n", m->dyn.soname);
91
92 /* Do not relocate twice. */
93 if (m->relocated) return;
94
95 module_process_pre_arch(m);
96
97 /* jmp_rel table */
98 if (m->dyn.jmp_rel != NULL) {
99 DPRINTF("jmp_rel table\n");
100 if (m->dyn.plt_rel == DT_REL) {
101 DPRINTF("jmp_rel table type DT_REL\n");
102 rel_table_process(m, m->dyn.jmp_rel, m->dyn.plt_rel_sz);
103 } else {
104 assert(m->dyn.plt_rel == DT_RELA);
105 DPRINTF("jmp_rel table type DT_RELA\n");
106 rela_table_process(m, m->dyn.jmp_rel, m->dyn.plt_rel_sz);
107 }
108 }
109
110 /* rel table */
111 if (m->dyn.rel != NULL) {
112 DPRINTF("rel table\n");
113 rel_table_process(m, m->dyn.rel, m->dyn.rel_sz);
114 }
115
116 /* rela table */
117 if (m->dyn.rela != NULL) {
118 DPRINTF("rela table\n");
119 rela_table_process(m, m->dyn.rela, m->dyn.rela_sz);
120 }
121
122 m->relocated = true;
123}
124
125/** Find module structure by soname/pathname.
126 *
127 * Used primarily to see if a module has already been loaded.
128 * Modules are compared according to their soname, i.e. possible
129 * path components are ignored.
130 */
131module_t *module_find(rtld_t *rtld, const char *name)
132{
133 const char *p, *soname;
134
135 DPRINTF("module_find('%s')\n", name);
136
137 /*
138 * If name contains slashes, treat it as a pathname and
139 * construct soname by chopping off the path. Otherwise
140 * treat it as soname.
141 */
142 p = str_rchr(name, '/');
143 soname = p ? (p + 1) : name;
144
145 /* Traverse list of all modules. Not extremely fast, but simple */
146 list_foreach(rtld->modules, modules_link, module_t, m) {
147 DPRINTF("m = %p\n", m);
148 if (str_cmp(m->dyn.soname, soname) == 0) {
149 return m; /* Found */
150 }
151 }
152
153 return NULL; /* Not found */
154}
155
156#define NAME_BUF_SIZE 64
157
158/** Load a module.
159 *
160 * Currently this trivially tries to load '/<name>'.
161 */
162module_t *module_load(rtld_t *rtld, const char *name, mlflags_t flags)
163{
164 elf_finfo_t info;
165 char name_buf[NAME_BUF_SIZE];
166 module_t *m;
167 int rc;
168
169 m = calloc(1, sizeof(module_t));
170 if (m == NULL) {
171 printf("malloc failed\n");
172 exit(1);
173 }
174
175 m->rtld = rtld;
176 m->id = rtld_get_next_id(rtld);
177
178 if ((flags & mlf_local) != 0)
179 m->local = true;
180
181 if (str_size(name) > NAME_BUF_SIZE - 2) {
182 printf("soname too long. increase NAME_BUF_SIZE\n");
183 exit(1);
184 }
185
186 /* Prepend soname with '/lib/' */
187 str_cpy(name_buf, NAME_BUF_SIZE, "/lib/");
188 str_cpy(name_buf + 5, NAME_BUF_SIZE - 5, name);
189
190 /* FIXME: need to real allocation of address space */
191 m->bias = rtld->next_bias;
192 rtld->next_bias += 0x100000;
193
194 DPRINTF("filename:'%s'\n", name_buf);
195 DPRINTF("load '%s' at 0x%zx\n", name_buf, m->bias);
196
197 rc = elf_load_file_name(name_buf, m->bias, ELDF_RW, &info);
198 if (rc != EE_OK) {
199 printf("Failed to load '%s'\n", name_buf);
200 exit(1);
201 }
202
203 if (info.dynamic == NULL) {
204 printf("Error: '%s' is not a dynamically-linked object.\n",
205 name_buf);
206 exit(1);
207 }
208
209 /* Pending relocation. */
210 m->relocated = false;
211
212 DPRINTF("parse dynamic section\n");
213 /* Parse ELF .dynamic section. Store info to m->dyn. */
214 dynamic_parse(info.dynamic, m->bias, &m->dyn);
215
216 /* Insert into the list of loaded modules */
217 list_append(&m->modules_link, &rtld->modules);
218
219 /* Copy TLS info */
220 m->tdata = info.tls.tdata;
221 m->tdata_size = info.tls.tdata_size;
222 m->tbss_size = info.tls.tbss_size;
223 m->tls_align = info.tls.tls_align;
224
225 DPRINTF("tdata at %p size %zu, tbss size %zu\n",
226 m->tdata, m->tdata_size, m->tbss_size);
227
228 return m;
229}
230
231/** Load all modules on which m (transitively) depends.
232 */
233void module_load_deps(module_t *m, mlflags_t flags)
234{
235 elf_dyn_t *dp;
236 char *dep_name;
237 module_t *dm;
238 size_t n, i;
239
240 DPRINTF("module_load_deps('%s')\n", m->dyn.soname);
241
242 /* Count direct dependencies */
243
244 dp = m->dyn.dynamic;
245 n = 0;
246
247 while (dp->d_tag != DT_NULL) {
248 if (dp->d_tag == DT_NEEDED) ++n;
249 ++dp;
250 }
251
252 /* Create an array of pointers to direct dependencies */
253
254 m->n_deps = n;
255
256 if (n == 0) {
257 /* There are no dependencies, so we are done. */
258 m->deps = NULL;
259 return;
260 }
261
262 m->deps = malloc(n * sizeof(module_t *));
263 if (!m->deps) {
264 printf("malloc failed\n");
265 exit(1);
266 }
267
268 i = 0; /* Current dependency index */
269 dp = m->dyn.dynamic;
270
271 while (dp->d_tag != DT_NULL) {
272 if (dp->d_tag == DT_NEEDED) {
273 dep_name = m->dyn.str_tab + dp->d_un.d_val;
274
275 DPRINTF("%s needs %s\n", m->dyn.soname, dep_name);
276 dm = module_find(m->rtld, dep_name);
277 if (!dm) {
278 dm = module_load(m->rtld, dep_name, flags);
279 module_load_deps(dm, flags);
280 }
281
282 /* Save into deps table */
283 m->deps[i++] = dm;
284 }
285 ++dp;
286 }
287}
288
289/** Find module structure by ID. */
290module_t *module_by_id(rtld_t *rtld, unsigned long id)
291{
292 list_foreach(rtld->modules, modules_link, module_t, m) {
293 if (m->id == id)
294 return m;
295 }
296
297 return NULL;
298}
299
300/** Process relocations in modules.
301 *
302 * Processes relocations in @a start and all its dependencies.
303 * Modules that have already been relocated are unaffected.
304 *
305 * @param start The module where to start from.
306 */
307void modules_process_relocs(rtld_t *rtld, module_t *start)
308{
309 list_foreach(rtld->modules, modules_link, module_t, m) {
310 /* Skip rtld module, since it has already been processed */
311 if (m != &rtld->rtld) {
312 module_process_relocs(m);
313 }
314 }
315}
316
317void modules_process_tls(rtld_t *rtld)
318{
319#ifdef CONFIG_TLS_VARIANT_1
320 list_foreach(rtld->modules, modules_link, module_t, m) {
321 m->ioffs = rtld->tls_size;
322 list_append(&m->imodules_link, &rtmd->imodules);
323 rtld->tls_size += m->tdata_size + m->tbss_size;
324 }
325#else /* CONFIG_TLS_VARIANT_2 */
326 size_t offs;
327
328 list_foreach(rtld->modules, modules_link, module_t, m) {
329 rtld->tls_size += m->tdata_size + m->tbss_size;
330 }
331
332 offs = 0;
333 list_foreach(rtld->modules, modules_link, module_t, m) {
334 offs += m->tdata_size + m->tbss_size;
335 m->ioffs = rtld->tls_size - offs;
336 list_append(&m->imodules_link, &rtld->imodules);
337 }
338#endif
339}
340
341/** Clear BFS tags of all modules.
342 */
343void modules_untag(rtld_t *rtld)
344{
345 list_foreach(rtld->modules, modules_link, module_t, m) {
346 m->bfs_tag = false;
347 }
348}
349
350/** @}
351 */
Note: See TracBrowser for help on using the repository browser.