2 * Copyright (c) 2008 Jiri Svoboda
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 /** @addtogroup rtld rtld
38 #include <elf/elf_load.h>
40 #include <loader/pcb.h>
44 #include <rtld/rtld.h>
45 #include <rtld/rtld_debug.h>
46 #include <rtld/dynamic.h>
47 #include <rtld/rtld_arch.h>
48 #include <rtld/module.h>
50 /** Create module for static executable.
52 * @param rtld Run-time dynamic linker
53 * @param rmodule Place to store pointer to new module or @c NULL
54 * @return EOK on success, ENOMEM if out of memory
56 int module_create_static_exec(rtld_t
*rtld
, module_t
**rmodule
)
60 module
= calloc(1, sizeof(module_t
));
64 module
->id
= rtld_get_next_id(rtld
);
65 module
->dyn
.soname
= "[program]";
71 module
->tdata
= &_tdata_start
;
72 module
->tdata_size
= &_tdata_end
- &_tdata_start
;
73 module
->tbss_size
= &_tbss_end
- &_tbss_start
;
74 module
->tls_align
= (uintptr_t)&_tls_alignment
;
76 list_append(&module
->modules_link
, &rtld
->modules
);
83 /** (Eagerly) process all relocation tables in a module.
85 * Currently works as if LD_BIND_NOW was specified.
87 void module_process_relocs(module_t
*m
)
89 DPRINTF("module_process_relocs('%s')\n", m
->dyn
.soname
);
91 /* Do not relocate twice. */
92 if (m
->relocated
) return;
94 module_process_pre_arch(m
);
97 if (m
->dyn
.jmp_rel
!= NULL
) {
98 DPRINTF("jmp_rel table\n");
99 if (m
->dyn
.plt_rel
== DT_REL
) {
100 DPRINTF("jmp_rel table type DT_REL\n");
101 rel_table_process(m
, m
->dyn
.jmp_rel
, m
->dyn
.plt_rel_sz
);
103 assert(m
->dyn
.plt_rel
== DT_RELA
);
104 DPRINTF("jmp_rel table type DT_RELA\n");
105 rela_table_process(m
, m
->dyn
.jmp_rel
, m
->dyn
.plt_rel_sz
);
110 if (m
->dyn
.rel
!= NULL
) {
111 DPRINTF("rel table\n");
112 rel_table_process(m
, m
->dyn
.rel
, m
->dyn
.rel_sz
);
116 if (m
->dyn
.rela
!= NULL
) {
117 DPRINTF("rela table\n");
118 rela_table_process(m
, m
->dyn
.rela
, m
->dyn
.rela_sz
);
124 /** Find module structure by soname/pathname.
126 * Used primarily to see if a module has already been loaded.
127 * Modules are compared according to their soname, i.e. possible
128 * path components are ignored.
130 module_t
*module_find(rtld_t
*rtld
, const char *name
)
132 const char *p
, *soname
;
134 DPRINTF("module_find('%s')\n", name
);
137 * If name contains slashes, treat it as a pathname and
138 * construct soname by chopping off the path. Otherwise
139 * treat it as soname.
141 p
= str_rchr(name
, '/');
142 soname
= p
? (p
+ 1) : name
;
144 /* Traverse list of all modules. Not extremely fast, but simple */
145 list_foreach(rtld
->modules
, modules_link
, module_t
, m
) {
146 DPRINTF("m = %p\n", m
);
147 if (str_cmp(m
->dyn
.soname
, soname
) == 0) {
148 return m
; /* Found */
152 return NULL
; /* Not found */
155 #define NAME_BUF_SIZE 64
159 * Currently this trivially tries to load '/<name>'.
161 module_t
*module_load(rtld_t
*rtld
, const char *name
, mlflags_t flags
)
164 char name_buf
[NAME_BUF_SIZE
];
168 m
= calloc(1, sizeof(module_t
));
170 printf("malloc failed\n");
175 m
->id
= rtld_get_next_id(rtld
);
177 if ((flags
& mlf_local
) != 0)
180 if (str_size(name
) > NAME_BUF_SIZE
- 2) {
181 printf("soname too long. increase NAME_BUF_SIZE\n");
185 /* Prepend soname with '/lib/' */
186 str_cpy(name_buf
, NAME_BUF_SIZE
, "/lib/");
187 str_cpy(name_buf
+ 5, NAME_BUF_SIZE
- 5, name
);
189 /* FIXME: need to real allocation of address space */
190 m
->bias
= rtld
->next_bias
;
191 rtld
->next_bias
+= 0x100000;
193 DPRINTF("filename:'%s'\n", name_buf
);
194 DPRINTF("load '%s' at 0x%x\n", name_buf
, m
->bias
);
196 rc
= elf_load_file_name(name_buf
, m
->bias
, ELDF_RW
, &info
);
198 printf("Failed to load '%s'\n", name_buf
);
202 if (info
.dynamic
== NULL
) {
203 printf("Error: '%s' is not a dynamically-linked object.\n",
208 /* Pending relocation. */
209 m
->relocated
= false;
211 DPRINTF("parse dynamic section\n");
212 /* Parse ELF .dynamic section. Store info to m->dyn. */
213 dynamic_parse(info
.dynamic
, m
->bias
, &m
->dyn
);
215 /* Insert into the list of loaded modules */
216 list_append(&m
->modules_link
, &rtld
->modules
);
219 m
->tdata
= info
.tls
.tdata
;
220 m
->tdata_size
= info
.tls
.tdata_size
;
221 m
->tbss_size
= info
.tls
.tbss_size
;
222 m
->tls_align
= info
.tls
.tls_align
;
224 DPRINTF("tdata at %p size %zu, tbss size %zu\n",
225 m
->tdata
, m
->tdata_size
, m
->tbss_size
);
230 /** Load all modules on which m (transitively) depends.
232 void module_load_deps(module_t
*m
, mlflags_t flags
)
239 DPRINTF("module_load_deps('%s')\n", m
->dyn
.soname
);
241 /* Count direct dependencies */
246 while (dp
->d_tag
!= DT_NULL
) {
247 if (dp
->d_tag
== DT_NEEDED
) ++n
;
251 /* Create an array of pointers to direct dependencies */
256 /* There are no dependencies, so we are done. */
261 m
->deps
= malloc(n
* sizeof(module_t
*));
263 printf("malloc failed\n");
267 i
= 0; /* Current dependency index */
270 while (dp
->d_tag
!= DT_NULL
) {
271 if (dp
->d_tag
== DT_NEEDED
) {
272 dep_name
= m
->dyn
.str_tab
+ dp
->d_un
.d_val
;
274 DPRINTF("%s needs %s\n", m
->dyn
.soname
, dep_name
);
275 dm
= module_find(m
->rtld
, dep_name
);
277 dm
= module_load(m
->rtld
, dep_name
, flags
);
278 module_load_deps(dm
, flags
);
281 /* Save into deps table */
288 /** Find module structure by ID. */
289 module_t
*module_by_id(rtld_t
*rtld
, unsigned long id
)
291 list_foreach(rtld
->modules
, modules_link
, module_t
, m
) {
299 /** Process relocations in modules.
301 * Processes relocations in @a start and all its dependencies.
302 * Modules that have already been relocated are unaffected.
304 * @param start The module where to start from.
306 void modules_process_relocs(rtld_t
*rtld
, module_t
*start
)
308 list_foreach(rtld
->modules
, modules_link
, module_t
, m
) {
309 /* Skip rtld module, since it has already been processed */
310 if (m
!= &rtld
->rtld
) {
311 module_process_relocs(m
);
316 void modules_process_tls(rtld_t
*rtld
)
318 #ifdef CONFIG_TLS_VARIANT_1
319 list_foreach(rtld
->modules
, modules_link
, module_t
, m
) {
320 m
->ioffs
= rtld
->tls_size
;
321 list_append(&m
->imodules_link
, &rtmd
->imodules
);
322 rtld
->tls_size
+= m
->tdata_size
+ m
->tbss_size
;
324 #else /* CONFIG_TLS_VARIANT_2 */
327 list_foreach(rtld
->modules
, modules_link
, module_t
, m
) {
328 rtld
->tls_size
+= m
->tdata_size
+ m
->tbss_size
;
332 list_foreach(rtld
->modules
, modules_link
, module_t
, m
) {
333 offs
+= m
->tdata_size
+ m
->tbss_size
;
334 m
->ioffs
= rtld
->tls_size
- offs
;
335 list_append(&m
->imodules_link
, &rtld
->imodules
);
340 /** Clear BFS tags of all modules.
342 void modules_untag(rtld_t
*rtld
)
344 list_foreach(rtld
->modules
, modules_link
, module_t
, m
) {