3 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
4 * Alexander Warg <warg@os.inf.tu-dresden.de>
5 * economic rights: Technische Universität Dresden (Germany)
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU Lesser General Public License 2.1.
8 * Please see the COPYING-LGPL-2.1 file for details.
13 #include <l4/re/elf_aux.h>
14 #include <l4/util/elf.h>
15 #include <l4/sys/types.h>
16 #include <l4/re/error_helper>
17 #include <l4/libloader/loader>
28 Elf_phdr(void const *hdr, bool _64) : _hdr(hdr), _64(_64) {}
29 Elf32_Phdr const *hdr32() const { return (Elf32_Phdr const*)(_hdr); }
30 Elf64_Phdr const *hdr64() const { return (Elf64_Phdr const*)(_hdr); }
32 char const *phdr_type() const;
33 unsigned long type() const { return _64?hdr64()->p_type:hdr32()->p_type; }
34 unsigned long paddr() const { return _64?hdr64()->p_paddr:hdr32()->p_paddr; }
35 unsigned long vaddr() const { return _64?hdr64()->p_vaddr:hdr32()->p_vaddr; }
36 unsigned long memsz() const { return _64?hdr64()->p_memsz:hdr32()->p_memsz; }
37 unsigned long filesz() const
38 { return _64?hdr64()->p_filesz:hdr32()->p_filesz; }
39 unsigned long flags() const { return _64?hdr64()->p_flags:hdr32()->p_flags; }
40 unsigned long offset() const
41 { return _64?hdr64()->p_offset:hdr32()->p_offset; }
49 unsigned short e_type;
50 unsigned short e_machine;
53 template< typename T >
54 T element(unsigned long offset) const
55 { return reinterpret_cast<T>((unsigned long)this + offset); }
57 template< typename F >
58 void iterate_phdr(F const &func) const
60 unsigned n = num_phdrs();
61 for (unsigned i = 0; i < n; ++i)
67 return l4util_elf_check_magic((ElfW(Ehdr) *)this)
68 && l4util_elf_check_arch((ElfW(Ehdr) *)this);
74 return e_machine == EM_AMD64;
77 Elf64_Ehdr const *hdr64() const { return (Elf64_Ehdr*)this; }
78 Elf32_Ehdr const *hdr32() const { return (Elf32_Ehdr*)this; }
82 bool is_dynamic() const
85 return hdr64()->e_type == ET_DYN;
87 return hdr32()->e_type == ET_DYN;
91 Elf_phdr phdr(unsigned idx) const
94 return Elf_phdr(element<Elf_phdr const*>(hdr64()->e_phoff
95 + hdr64()->e_phentsize * idx), is_64());
97 return Elf_phdr(element<Elf_phdr const*>(hdr32()->e_phoff
98 + hdr32()->e_phentsize * idx), is_64());
102 unsigned num_phdrs() const
105 return hdr64()->e_phnum;
107 return hdr32()->e_phnum;
110 unsigned long entry() const
113 return hdr64()->e_entry;
115 return hdr32()->e_entry;
120 struct Phdr_load_min_max
122 mutable l4_addr_t start;
123 mutable l4_addr_t end;
125 Phdr_load_min_max() : start(~0UL), end(0) {}
126 void operator () (Elf_phdr const &h) const
128 if (h.type() != PT_LOAD)
131 l4_addr_t s = l4_trunc_page(h.paddr());
132 l4_addr_t e = l4_round_page(h.paddr() + h.memsz());
133 if (s < start) start = s;
134 if (e > end) end = e;
138 template< typename Dbg >
142 Phdr_print(Dbg const &ldr) : ldr(ldr) {}
143 void operator () (Elf_phdr const &ph) const
145 char const *pt = ph.phdr_type();
147 ldr.printf(" [%-12s]", pt);
149 ldr.printf(" [%12lx]", ph.type());
151 ldr.cprintf(" 0x%lx\t0x%lx\t0x%lx\t0x%lx\t0x%lx\t%c%c%c\n",
152 ph.offset(), ph.paddr(), ph.vaddr(), ph.filesz(),
154 (ph.flags() & PF_R) ? 'r' : '-',
155 (ph.flags() & PF_W) ? 'w' : '-',
156 (ph.flags() & PF_X) ? 'x' : '-');
161 template< typename App_model, typename Dbg >
164 typedef typename App_model::Dataspace Dataspace;
165 typedef typename App_model::Const_dataspace Const_dataspace;
173 Phdr_load(l4_addr_t base, Const_dataspace bin, App_model *mm,
174 unsigned r_flags, Dbg const &dbg)
175 : base(base), r_flags(r_flags), bin(bin), mm(mm), dbg(dbg)
178 void operator () (Elf_phdr const &ph) const
182 if (ph.type() != PT_LOAD)
188 char *paddr = (char*)(l4_trunc_page(ph.paddr()) + base);
189 l4_umword_t offs = l4_trunc_page(ph.offset());
190 l4_umword_t page_offs = ph.offset() & (L4_PAGESIZE-1);
191 l4_umword_t fsz = ph.filesz();
192 if (fsz && page_offs != (ph.paddr() & (L4_PAGESIZE-1)))
194 dbg.printf("malformed ELF file, file offset and paddr mismatch\n");
195 chksys(-L4_EINVAL, "malformed elf file");
198 l4_umword_t size = l4_round_page(ph.memsz() + page_offs);
200 if ((ph.flags() & PF_W) || ph.memsz() > fsz || mm->all_segs_cow())
203 Dataspace mem = mm->alloc_ds(size);
204 mm->prog_attach_ds(l4_addr_t(paddr), size, mem, 0, r_flags,
205 "attaching rw ELF segement");
206 mm->copy_ds(mem, 0, bin, offs, fsz + page_offs);
211 mm->prog_attach_ds(l4_addr_t(paddr), size, bin, offs,
212 r_flags | L4Re::Rm::Read_only,
213 "attaching ro ELF segement");
218 template< typename App_model >
219 struct Phdr_l4re_elf_aux_infos
221 mutable l4_size_t stack_size;
222 mutable l4_addr_t stack_addr;
223 mutable l4_addr_t kip_addr;
225 typedef typename App_model::Const_dataspace Const_dataspace;
229 explicit Phdr_l4re_elf_aux_infos(App_model const *mm, Const_dataspace bin,
231 : stack_size(0x8000), stack_addr(0x80000000), kip_addr(kip_addr), mm(mm), bin(bin)
234 void operator () (Elf_phdr const &h) const
236 if (h.type() != PT_L4_AUX)
242 l4_addr_t addr = mm->local_attach_ds(bin, h.filesz(), h.offset());
244 l4re_elf_aux_t const *e = (l4re_elf_aux_t const *)addr;
245 l4re_elf_aux_t const *end = (l4re_elf_aux_t const *)(addr + h.filesz());
246 while (e < end && e->type)
250 case L4RE_ELF_AUX_T_STACK_SIZE:
252 l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e;
253 stack_size = v->value;
256 case L4RE_ELF_AUX_T_STACK_ADDR:
258 l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e;
259 stack_addr = v->value;
262 case L4RE_ELF_AUX_T_KIP_ADDR:
264 l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e;
272 e = (l4re_elf_aux_t const *)((char const *)e + e->length);
275 mm->local_detach_ds(addr, h.filesz());
280 template< typename App_model >
283 typedef typename App_model::Const_dataspace Const_dataspace;
288 mutable char interp[100];
289 mutable l4_addr_t phdrs;
290 mutable bool is_dynamic;
292 Phdr_dynamic(App_model const *mm, Const_dataspace bin, l4_addr_t base)
293 : mm(mm), bin(bin), base(base), phdrs(0),
296 static char const *const addr = "rom/libld-l4.so";
298 for (i = 0; i < sizeof(interp)-1 && addr[i]; ++i)
302 void operator () (Elf_phdr const &ph) const
310 char const *addr = (char const *)mm->local_attach_ds(bin, ph.filesz(), ph.offset());
312 for (i = 0; i < sizeof(interp)-1 && addr[i]; ++i)
316 mm->local_detach_ds(l4_addr_t(addr), ph.filesz());
319 //ldr.printf(" found interpreter PHDR: interp='%s'\n", interp);
322 phdrs = base + ph.paddr();
331 template< typename App_model >
332 struct Phdr_l4re_elf_aux
334 typedef typename App_model::Const_dataspace Const_dataspace;
338 explicit Phdr_l4re_elf_aux(App_model *am, Const_dataspace bin)
342 void operator () (Elf_phdr const &h) const
345 if (h.type() != PT_L4_AUX)
350 l4_addr_t addr = am->local_attach_ds(bin, h.filesz(), h.offset());
352 l4re_elf_aux_t const *e = (l4re_elf_aux_t const *)addr;
353 l4re_elf_aux_t const *end = (l4re_elf_aux_t const *)(addr + h.filesz());
355 while (e < end && e->type)
359 case L4RE_ELF_AUX_T_VMA:
361 l4re_elf_aux_vma_t const *v = (l4re_elf_aux_vma_t const *)e;
362 l4_addr_t start = v->start;
363 chksys(am->prog_reserve_area(&start, v->end - v->start + 1, 0, 0));
370 e = (l4re_elf_aux_t const *)((char const *)e + e->length);
373 am->local_detach_ds(addr, h.filesz());
374 // L4::cap_reinterpret_cast<L4Re::Debug_obj>(r)->debug(0);
380 template< typename App_model, typename Dbg_ >
381 class Elf_loader : public Loader<App_model, Dbg_>
384 typedef Loader<App_model, Dbg_> Base;
386 typedef typename Base::Const_dataspace Const_dataspace;
387 typedef typename Base::Dbg_log Dbg_log;
389 void read_infos(App_model *mm, Const_dataspace bin,
394 Elf_ehdr const *eh = reinterpret_cast<Elf_ehdr const*>(mm->local_attach_ds(bin, L4_PAGESIZE, 0));
398 chksys(-L4_EINVAL, "not an ELF binary");
401 Phdr_l4re_elf_aux_infos<App_model> stack_info(mm, bin, mm->prog_info()->kip);
402 eh->iterate_phdr(stack_info);
403 mm->stack()->set_target_stack(stack_info.stack_addr, stack_info.stack_size);
405 mm->prog_info()->kip = stack_info.kip_addr;
406 ldr.printf(" STACK: %lx (%zx) KIP: %lx\n", stack_info.stack_addr,
407 stack_info.stack_size, stack_info.kip_addr);
409 ldr.printf(" PHDRs: type offset\tpaddr\tvaddr\tfilesz\tmemsz\trights\n");
410 eh->iterate_phdr(Phdr_print<Dbg_log>(ldr));
411 mm->local_detach_ds((l4_addr_t)eh, L4_PAGESIZE);
414 void load(App_model *mm, Const_dataspace bin, l4_addr_t *base, bool interpreter,
419 Elf_ehdr const *eh = reinterpret_cast<Elf_ehdr const*>(mm->local_attach_ds(bin, L4_PAGESIZE, 0));
423 ldr.printf("file is not an ELF binary\n");
424 chksys(-L4_EINVAL, "not an ELF binary");
427 unsigned r_flags = 0;
431 Phdr_load_min_max b_func;
432 ldr.printf(" relocate PIC/PIE binary\n");
433 /* figure out size of the binary, if PIC */
434 eh->iterate_phdr(b_func);
436 ldr.printf(" all PHDRs: [0x%lx-0x%lx]\n", b_func.start, b_func.end);
439 l4_addr_t lib = _base + b_func.start;
440 chksys(mm->prog_reserve_area(&lib, b_func.end - b_func.start,
441 L4Re::Rm::Search_addr, L4_SUPERPAGESHIFT));
443 ldr.printf(" relocate to %p\n", (void*)lib);
445 _base = l4_addr_t(lib) - b_func.start;
447 ldr.printf(" PHDRs: type offset\tpaddr\tvaddr\tfilesz\tmemsz\trights\n");
448 eh->iterate_phdr(Phdr_print<Dbg_log>(ldr));
450 r_flags |= L4Re::Rm::In_area;
453 eh->iterate_phdr(Phdr_load<App_model, Dbg_log>(_base, bin, mm, r_flags, ldr));
454 eh->iterate_phdr(Phdr_l4re_elf_aux<App_model>(mm, bin));
456 mm->prog_info()->entry = eh->entry() + _base;
458 Phdr_dynamic<App_model> dyn_info(mm, bin, _base);
459 eh->iterate_phdr(dyn_info);
461 if (!interpreter && dyn_info.phdrs)
463 Prog_start_info *i = mm->prog_info();
464 i->dyn_phdrs = dyn_info.phdrs;
465 i->dyn_num_phdrs = eh->num_phdrs();
468 // Load the interpreter
469 if (dyn_info.is_dynamic)
471 ldr.printf(" dynamically linked executable, load interpreter '%s'\n", dyn_info.interp);
473 Const_dataspace file = mm->open_file(dyn_info.interp);
474 l4_addr_t base = 0x400000;
476 load(mm, file, &base, true, ldr);
478 Prog_start_info *i = mm->prog_info();
480 i->dyn_exec_entry = eh->entry() + _base;
481 i->dyn_interp_base = base;
484 mm->local_detach_ds((l4_addr_t)eh, L4_PAGESIZE);
486 ldr.printf(" done...\n");
489 void load(App_model *mm, Const_dataspace bin,
492 load(mm, bin, 0, false, ldr);