]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libloader/include/elf
update
[l4.git] / l4 / pkg / libloader / include / elf
1 // vi:ft=cpp
2 /*
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.
9  */
10
11 #pragma once
12
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>
18
19 namespace Ldr {
20
21 class Elf_phdr
22 {
23 private:
24   void const *_hdr;
25   bool _64;
26
27 public:
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); }
31
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; }
42
43 };
44
45 class Elf_ehdr
46 {
47 private:
48   char e_ident[16];
49   unsigned short e_type;
50   unsigned short e_machine;
51   unsigned e_version;
52 public:
53   template< typename T >
54   T element(unsigned long offset) const
55   { return reinterpret_cast<T>((unsigned long)this + offset); }
56
57   template< typename F >
58   void iterate_phdr(F const &func) const
59   {
60     unsigned n = num_phdrs();
61     for (unsigned i = 0; i < n; ++i)
62       func(phdr(i));
63   }
64
65   bool is_valid() const
66   {
67     return    l4util_elf_check_magic((ElfW(Ehdr) *)this)
68            && l4util_elf_check_arch((ElfW(Ehdr) *)this);
69   }
70
71 private:
72   bool is_64() const
73   {
74     return e_machine == EM_AMD64;
75   }
76
77   Elf64_Ehdr const *hdr64() const { return (Elf64_Ehdr*)this; }
78   Elf32_Ehdr const *hdr32() const { return (Elf32_Ehdr*)this; }
79
80 public:
81
82   bool is_dynamic() const
83   {
84     if (is_64())
85       return hdr64()->e_type == ET_DYN;
86     else
87       return hdr32()->e_type == ET_DYN;
88   }
89
90
91   Elf_phdr phdr(unsigned idx) const
92   {
93     if (is_64())
94       return Elf_phdr(element<Elf_phdr const*>(hdr64()->e_phoff
95           + hdr64()->e_phentsize * idx), is_64());
96     else
97       return Elf_phdr(element<Elf_phdr const*>(hdr32()->e_phoff
98           + hdr32()->e_phentsize * idx), is_64());
99
100   }
101
102   unsigned num_phdrs() const
103   {
104     if (is_64())
105       return hdr64()->e_phnum;
106     else
107       return hdr32()->e_phnum;
108   }
109
110   unsigned long entry() const
111   {
112     if (is_64())
113       return hdr64()->e_entry;
114     else
115       return hdr32()->e_entry;
116   }
117 };
118
119
120 struct Phdr_load_min_max
121 {
122   mutable l4_addr_t start;
123   mutable l4_addr_t end;
124
125   Phdr_load_min_max() : start(~0UL), end(0) {}
126   void operator () (Elf_phdr const &h) const
127   {
128     if (h.type() != PT_LOAD)
129       return;
130
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;
135   }
136 };
137
138 struct Phdr_kip
139 {
140   mutable l4_addr_t kip;
141
142   explicit Phdr_kip(l4_addr_t kip_default)
143   : kip(kip_default)
144   {}
145
146   void operator () (Elf_phdr const &h) const
147   {
148     switch (h.type())
149       {
150       case PT_L4_KIP:
151         kip = h.paddr();
152         break;
153       default:
154         break;
155       }
156   }
157 };
158
159 template< typename Dbg >
160 struct Phdr_print
161 {
162   Dbg const &ldr;
163   Phdr_print(Dbg const &ldr) : ldr(ldr) {}
164   void operator () (Elf_phdr const &ph) const
165   {
166     char const *pt = ph.phdr_type();
167     if (pt)
168       ldr.printf("   [%-12s]", pt);
169     else
170       ldr.printf("   [%12lx]", ph.type());
171
172     ldr.cprintf(" 0x%lx\t0x%lx\t0x%lx\t0x%lx\t0x%lx\t%c%c%c\n",
173                 ph.offset(), ph.paddr(), ph.vaddr(), ph.filesz(),
174                 ph.memsz(),
175                 (ph.flags() & PF_R) ? 'r' : '-',
176                 (ph.flags() & PF_W) ? 'w' : '-',
177                 (ph.flags() & PF_X) ? 'x' : '-');
178
179   }
180 };
181
182 template< typename App_model, typename Dbg >
183 struct Phdr_load
184 {
185   typedef typename App_model::Dataspace Dataspace;
186   typedef typename App_model::Const_dataspace Const_dataspace;
187
188   l4_addr_t base;
189   unsigned r_flags;
190   Const_dataspace bin;
191   App_model *mm;
192   Dbg const &dbg;
193
194   Phdr_load(l4_addr_t base, Const_dataspace bin, App_model *mm,
195             unsigned r_flags, Dbg const &dbg)
196   : base(base), r_flags(r_flags), bin(bin), mm(mm), dbg(dbg)
197   {}
198
199   void operator () (Elf_phdr const &ph) const
200   {
201     using L4Re::chksys;
202
203     if (ph.type() != PT_LOAD)
204       return;
205
206     if (!ph.memsz())
207       return;
208
209     char *paddr = (char*)(l4_trunc_page(ph.paddr()) + base);
210     l4_umword_t offs = l4_trunc_page(ph.offset());
211     l4_umword_t page_offs = ph.offset() & (L4_PAGESIZE-1);
212     l4_umword_t fsz  = ph.filesz();
213     if (fsz && page_offs != (ph.paddr() & (L4_PAGESIZE-1)))
214       {
215         dbg.printf("malformed ELF file, file offset and paddr mismatch\n");
216         chksys(-L4_EINVAL, "malformed elf file");
217       }
218
219     l4_umword_t size = l4_round_page(ph.memsz() + page_offs);
220
221     if ((ph.flags() & PF_W) || ph.memsz() > fsz || mm->all_segs_cow())
222       {
223         // copy section
224         Dataspace mem = mm->alloc_ds(size);
225         mm->prog_attach_ds(l4_addr_t(paddr), size, mem, 0, r_flags,
226                            "attaching rw ELF segement");
227         mm->copy_ds(mem, 0, bin, offs, fsz + page_offs);
228       }
229     else
230       {
231         // map from file
232         mm->prog_attach_ds(l4_addr_t(paddr), size, bin, offs,
233                            r_flags | L4Re::Rm::Read_only,
234                            "attaching ro ELF segement");
235       }
236   }
237 };
238
239 template< typename App_model >
240 struct Phdr_l4re_elf_aux_stack
241 {
242   mutable l4_size_t stack_size;
243   mutable l4_addr_t stack_addr;
244
245   typedef typename App_model::Const_dataspace Const_dataspace;
246   App_model const *mm;
247   Const_dataspace bin;
248
249   explicit Phdr_l4re_elf_aux_stack(App_model const *mm, Const_dataspace bin)
250   : stack_size(0x8000), stack_addr(0x80000000), mm(mm), bin(bin)
251   {}
252
253   void operator () (Elf_phdr const &h) const
254   {
255     if (h.type() != PT_L4_AUX)
256       return;
257
258
259     if (h.filesz())
260       {
261         l4_addr_t addr = mm->local_attach_ds(bin, h.filesz(), h.offset());
262
263         l4re_elf_aux_t const *e = (l4re_elf_aux_t const *)addr;
264         l4re_elf_aux_t const *end = (l4re_elf_aux_t const *)(addr + h.filesz());
265         while (e < end && e->type)
266           {
267             switch (e->type)
268               {
269               case L4RE_ELF_AUX_T_STACK_SIZE:
270                   {
271                     l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e;
272                     stack_size = v->value;
273                     break;
274                   }
275               case L4RE_ELF_AUX_T_STACK_ADDR:
276                   {
277                     l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e;
278                     stack_addr = v->value;
279                     break;
280                   }
281               default:
282                 break;
283               }
284
285             e = (l4re_elf_aux_t const *)((char const *)e + e->length);
286           }
287
288         mm->local_detach_ds(addr, h.filesz());
289       }
290   }
291 };
292
293 template< typename App_model >
294 struct Phdr_dynamic
295 {
296   typedef typename App_model::Const_dataspace Const_dataspace;
297   App_model const *mm;
298   Const_dataspace bin;
299
300   l4_addr_t base;
301   mutable char interp[100];
302   mutable l4_addr_t phdrs;
303   mutable bool is_dynamic;
304
305   Phdr_dynamic(App_model const *mm, Const_dataspace bin, l4_addr_t base)
306   : mm(mm), bin(bin), base(base), phdrs(0),
307     is_dynamic(false)
308   {
309     static char const *const addr = "rom/libld-l4.so";
310     unsigned i;
311     for (i = 0; i < sizeof(interp)-1 && addr[i]; ++i)
312       interp[i] = addr[i];
313   }
314
315   void operator () (Elf_phdr const &ph) const
316   {
317     switch (ph.type())
318       {
319       default:
320         return;
321       case PT_INTERP:
322           {
323             char const *addr = (char const *)mm->local_attach_ds(bin, ph.filesz(), ph.offset());
324             unsigned i;
325             for (i = 0; i < sizeof(interp)-1 && addr[i]; ++i)
326               interp[i] = addr[i];
327
328             interp[i] = 0;
329             mm->local_detach_ds(l4_addr_t(addr), ph.filesz());
330             is_dynamic = true;
331           }
332         //ldr.printf("  found interpreter PHDR: interp='%s'\n", interp);
333         break;
334       case PT_PHDR:
335         phdrs = base + ph.paddr();
336         break;
337       case PT_DYNAMIC:
338         //is_dynamic = true;
339         break;
340       }
341   }
342 };
343
344 template< typename App_model >
345 struct Phdr_l4re_elf_aux
346 {
347   typedef typename App_model::Const_dataspace Const_dataspace;
348   App_model *am;
349   Const_dataspace bin;
350
351   explicit Phdr_l4re_elf_aux(App_model *am, Const_dataspace bin)
352   : am(am), bin(bin)
353   {}
354
355   void operator () (Elf_phdr const &h) const
356   {
357     using L4Re::chksys;
358     if (h.type() != PT_L4_AUX)
359       return;
360
361     if (h.filesz())
362       {
363         l4_addr_t addr = am->local_attach_ds(bin, h.filesz(), h.offset());
364
365         l4re_elf_aux_t const *e = (l4re_elf_aux_t const *)addr;
366         l4re_elf_aux_t const *end = (l4re_elf_aux_t const *)(addr + h.filesz());
367
368         while (e < end && e->type)
369           {
370             switch (e->type)
371               {
372               case L4RE_ELF_AUX_T_VMA:
373                   {
374                     l4re_elf_aux_vma_t const *v = (l4re_elf_aux_vma_t const *)e;
375                     l4_addr_t start = v->start;
376                     chksys(am->prog_reserve_area(&start, v->end - v->start + 1, 0, 0));
377                     break;
378                   }
379               default:
380                 break;
381               }
382
383             e = (l4re_elf_aux_t const *)((char const *)e + e->length);
384           }
385
386         am->local_detach_ds(addr, h.filesz());
387         // L4::cap_reinterpret_cast<L4Re::Debug_obj>(r)->debug(0);
388       }
389   }
390
391 };
392
393 template< typename App_model, typename Dbg_ >
394 class Elf_loader : public Loader<App_model, Dbg_>
395 {
396 public:
397   typedef Loader<App_model, Dbg_> Base;
398 public:
399   typedef typename Base::Const_dataspace Const_dataspace;
400   typedef typename Base::Dbg_log Dbg_log;
401
402   void read_infos(App_model *mm, Const_dataspace bin,
403                   Dbg_log const &ldr)
404   {
405     using L4Re::chksys;
406
407     Elf_ehdr const *eh = reinterpret_cast<Elf_ehdr const*>(mm->local_attach_ds(bin, L4_PAGESIZE, 0));
408
409     if (!eh->is_valid())
410       {
411         ldr.printf("file is not an ELF binary\n");
412         chksys(-L4_EINVAL, "not an ELF binary");
413       }
414
415
416     Phdr_kip stack_kip(mm->prog_info()->kip);
417 #if 0
418     Phdr_kip stack_kip(info->stack.target_addr(), info->stack.stack_size(),
419         info->kip);
420 #endif
421
422     eh->iterate_phdr(stack_kip);
423
424     mm->prog_info()->kip = stack_kip.kip;
425
426     Phdr_l4re_elf_aux_stack<App_model> stack_info(mm, bin);
427
428     eh->iterate_phdr(stack_info);
429     mm->stack()->set_target_stack(stack_info.stack_addr, stack_info.stack_size);
430
431     ldr.printf("  PHDRs: type  offset\tpaddr\tvaddr\tfilesz\tmemsz\trights\n");
432     eh->iterate_phdr(Phdr_print<Dbg_log>(ldr));
433     mm->local_detach_ds((l4_addr_t)eh, L4_PAGESIZE);
434   }
435
436   void load(App_model *mm, Const_dataspace bin, l4_addr_t *base,
437             Dbg_log const &ldr)
438   {
439     using L4Re::chksys;
440
441     Elf_ehdr const *eh = reinterpret_cast<Elf_ehdr const*>(mm->local_attach_ds(bin, L4_PAGESIZE, 0));
442
443     if (!eh->is_valid())
444       {
445         ldr.printf("file is not an ELF binary\n");
446         chksys(-L4_EINVAL, "not an ELF binary");
447       }
448
449     unsigned r_flags = 0;
450     l4_addr_t _base = 0;
451     if (base)
452       {
453         Phdr_load_min_max b_func;
454         ldr.printf("  relocate PIC/PIE binary\n");
455         /* figure out size of the binary, if PIC */
456         eh->iterate_phdr(b_func);
457
458         ldr.printf("   all PHDRs: [0x%lx-0x%lx]\n", b_func.start, b_func.end);
459         _base = *base;
460
461         l4_addr_t lib = _base + b_func.start;
462         chksys(mm->prog_reserve_area(&lib, b_func.end - b_func.start,
463               L4Re::Rm::Search_addr, L4_SUPERPAGESHIFT));
464
465         ldr.printf("   relocate to %p\n", (void*)lib);
466
467         _base = l4_addr_t(lib) - b_func.start;
468
469         ldr.printf("  PHDRs: type  offset\tpaddr\tvaddr\tfilesz\tmemsz\trights\n");
470         eh->iterate_phdr(Phdr_print<Dbg_log>(ldr));
471         *base = _base;
472         r_flags |= L4Re::Rm::In_area;
473       }
474
475     eh->iterate_phdr(Phdr_load<App_model, Dbg_log>(_base, bin, mm, r_flags, ldr));
476     eh->iterate_phdr(Phdr_l4re_elf_aux<App_model>(mm, bin));
477
478     mm->prog_info()->entry = eh->entry() + _base;
479
480     Phdr_dynamic<App_model> dyn_info(mm, bin, _base);
481     eh->iterate_phdr(dyn_info);
482
483     // Load the interpreter
484     if (dyn_info.is_dynamic)
485       {
486         ldr.printf("  dynamically linked executable, load interpreter '%s'\n", dyn_info.interp);
487
488         Const_dataspace file = mm->open_file(dyn_info.interp);
489         l4_addr_t base = 0x400000;
490
491         load(mm, file, &base, ldr);
492
493         Prog_start_info *i = mm->prog_info();
494
495         i->dyn_exec_entry = eh->entry() + _base;
496         i->dyn_phdrs = dyn_info.phdrs;
497         i->dyn_num_phdrs = eh->num_phdrs();
498         i->dyn_interp_base = base;
499       }
500
501     mm->local_detach_ds((l4_addr_t)eh, L4_PAGESIZE);
502
503     ldr.printf(" done...\n");
504   }
505
506   void load(App_model *mm, Const_dataspace bin,
507             Dbg_log const &ldr)
508   {
509     load(mm, bin, 0, ldr);
510   }
511
512
513
514 };
515
516 }
517
518