1// vi:set ft=cpp: -*- Mode: C++ -*- 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 19namespace Ldr { 20 21class Elf_phdr 22{ 23private: 24 void const *_hdr; 25 bool _64; 26 27public: 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 45class Elf_ehdr 46{ 47private: 48 char e_ident[16]; 49 unsigned short e_type; 50 unsigned short e_machine; 51 unsigned e_version; 52public: 53 template< typename T > 54 T element(unsigned long offset) const 55 { return reinterpret_cast<T>((unsigned long)this + offset); } 56 57 bool is_valid() const 58 { 59 return l4util_elf_check_magic((ElfW(Ehdr) *)this) 60 && l4util_elf_check_arch((ElfW(Ehdr) *)this); 61 } 62 63 bool is_64() const 64 { 65 return e_ident[EI_CLASS] == ELFCLASS64; 66 } 67 68private: 69 Elf64_Ehdr const *hdr64() const { return (Elf64_Ehdr*)this; } 70 Elf32_Ehdr const *hdr32() const { return (Elf32_Ehdr*)this; } 71 72public: 73 74 bool is_dynamic() const 75 { 76 if (is_64()) 77 return hdr64()->e_type == ET_DYN; 78 else 79 return hdr32()->e_type == ET_DYN; 80 } 81 82 l4_addr_t phdrs_offset() const 83 { 84 if (is_64()) 85 return hdr64()->e_phoff; 86 else 87 return hdr32()->e_phoff; 88 } 89 90 l4_size_t phdr_size() const 91 { 92 if (is_64()) 93 return hdr64()->e_phentsize; 94 else 95 return hdr32()->e_phentsize; 96 } 97 98 unsigned num_phdrs() const 99 { 100 if (is_64()) 101 return hdr64()->e_phnum; 102 else 103 return hdr32()->e_phnum; 104 } 105 106 unsigned long entry() const 107 { 108 if (is_64()) 109 return hdr64()->e_entry; 110 else 111 return hdr32()->e_entry; 112 } 113}; 114 115template<typename APP_MODEL> 116class Elf_binary 117{ 118private: 119 void detach_eh_ds() 120 { 121 if (!_eh) 122 return; 123 124 _mm->local_detach_ds((l4_addr_t)_eh, L4_PAGESIZE); 125 _eh = nullptr; 126 } 127 128public: 129 typedef APP_MODEL App_model; 130 typedef typename App_model::Const_dataspace Const_dataspace; 131 132 Elf_binary(Elf_binary const &) = delete; 133 Elf_binary(Elf_binary &&o) 134 : _mm(o._mm), _eh(o._eh), _ph(o._ph), _ph_size(o._ph_size), _64bit(o._64bit) 135 { 136 o._eh = nullptr; 137 o._ph = nullptr; 138 o._ph_size = 0; 139 } 140 141 Elf_binary(App_model *mm, Const_dataspace bin) 142 : _mm(mm) 143 { 144 _eh = reinterpret_cast<Elf_ehdr const*>( 145 mm->local_attach_ds(bin, L4_PAGESIZE, 0)); 146 147 if (!_eh) 148 return; 149 150 if (!_eh->is_valid()) 151 { 152 detach_eh_ds(); 153 return; 154 } 155 156 l4_size_t phsize = _eh->phdr_size() * _eh->num_phdrs(); 157 l4_addr_t phoffset = _eh->phdrs_offset(); 158 if (phoffset + phsize > L4_PAGESIZE) 159 { 160 // need xtra mapping for the PHDRs 161 _ph = reinterpret_cast<char const *>( 162 mm->local_attach_ds(bin, phsize, phoffset)); 163 164 if (!_ph) 165 { 166 detach_eh_ds(); 167 return; 168 } 169 170 _ph_size = phsize; 171 } 172 else 173 _ph = reinterpret_cast<char const *>(_eh) + phoffset; 174 175 _64bit = _eh->is_64(); 176 } 177 178 bool is_valid() const 179 { 180 return _eh; 181 } 182 183 bool is_64() const 184 { 185 return _64bit; 186 } 187 188 unsigned long entry() const 189 { 190 return _eh->entry(); 191 } 192 193 unsigned num_phdrs() const 194 { 195 return _eh->num_phdrs(); 196 } 197 198 Elf_phdr phdr(int index) const 199 { 200 return Elf_phdr(_ph + index * _eh->phdr_size(), _64bit); 201 } 202 203 template< typename F > 204 void iterate_phdr(F const &func) const 205 { 206 unsigned n = num_phdrs(); 207 for (unsigned i = 0; i < n; ++i) 208 func(phdr(i)); 209 } 210 211 ~Elf_binary() 212 { 213 if (!_eh) 214 return; 215 216 detach_eh_ds(); 217 218 if (_ph_size) 219 { 220 _mm->local_detach_ds((l4_addr_t)_ph, _ph_size); 221 _ph_size = 0; 222 } 223 224 _ph = nullptr; 225 } 226 227private: 228 App_model *_mm; 229 Elf_ehdr const *_eh = nullptr; 230 char const *_ph = nullptr; 231 l4_size_t _ph_size = 0; 232 bool _64bit = false; 233}; 234 235struct Phdr_load_min_max 236{ 237 mutable l4_addr_t start; 238 mutable l4_addr_t end; 239 240 Phdr_load_min_max() : start(~0UL), end(0) {} 241 void operator () (Elf_phdr const &h) const 242 { 243 if (h.type() != PT_LOAD && h.type() != PT_L4_KIP) 244 return; 245 246 l4_addr_t s = l4_trunc_page(h.paddr()); 247 l4_addr_t e = l4_round_page(h.paddr() + h.memsz()); 248 if (s < start) start = s; 249 if (e > end) end = e; 250 } 251}; 252 253template< typename Dbg > 254struct Phdr_print 255{ 256 Dbg const &ldr; 257 Phdr_print(Dbg const &ldr) : ldr(ldr) {} 258 void operator () (Elf_phdr const &ph) const 259 { 260 char const *pt = ph.phdr_type(); 261 if (pt) 262 ldr.printf(" [%-12s]", pt); 263 else 264 ldr.printf(" [%12lx]", ph.type()); 265 266 ldr.cprintf(" 0x%lx\t0x%lx\t0x%lx\t0x%lx\t0x%lx\t%c%c%c\n", 267 ph.offset(), ph.paddr(), ph.vaddr(), ph.filesz(), 268 ph.memsz(), 269 (ph.flags() & PF_R) ? 'r' : '-', 270 (ph.flags() & PF_W) ? 'w' : '-', 271 (ph.flags() & PF_X) ? 'x' : '-'); 272 273 } 274}; 275 276template< typename App_model, typename Dbg > 277struct Phdr_load 278{ 279 typedef typename App_model::Dataspace Dataspace; 280 typedef typename App_model::Const_dataspace Const_dataspace; 281 282 l4_addr_t base; 283 L4Re::Rm::Flags r_flags; 284 Const_dataspace bin; 285 App_model *mm; 286 Dbg const &dbg; 287 288 Phdr_load(l4_addr_t base, Const_dataspace bin, App_model *mm, 289 L4Re::Rm::Flags r_flags, Dbg const &dbg) 290 : base(base), r_flags(r_flags), bin(bin), mm(mm), dbg(dbg) 291 {} 292 293 void operator () (Elf_phdr const &ph) const 294 { 295 using L4Re::chksys; 296 297 if (ph.type() == PT_L4_KIP) 298 { 299 char *paddr = (char*)(l4_trunc_page(ph.paddr()) + base); 300 mm->prog_attach_ds(l4_addr_t(paddr), L4_PAGESIZE, 301 mm->local_kip_ds(), 0, r_flags | L4Re::Rm::F::RX, 302 "attaching KIP ELF segment"); 303 return; 304 } 305 306 if (ph.type() != PT_LOAD) 307 return; 308 309 if (!ph.memsz()) 310 return; 311 312 char *paddr = (char*)(l4_trunc_page(ph.paddr()) + base); 313 l4_umword_t offs = l4_trunc_page(ph.offset()); 314 l4_umword_t page_offs = ph.offset() & (L4_PAGESIZE-1); 315 l4_umword_t fsz = ph.filesz(); 316 if (fsz && page_offs != (ph.paddr() & (L4_PAGESIZE-1))) 317 { 318 dbg.printf("malformed ELF file, file offset and paddr mismatch\n"); 319 chksys(-L4_EINVAL, "malformed elf file"); 320 } 321 322 l4_umword_t size = l4_round_page(ph.memsz() + page_offs); 323 324 L4Re::Rm::Flags rf(r_flags); 325 unsigned long o = offs; 326 Const_dataspace ds = bin; 327 328 if ((ph.flags() & PF_W) || ph.memsz() > fsz || mm->all_segs_cow()) 329 { 330 // copy section 331 Dataspace mem = mm->alloc_ds(size); 332 mm->copy_ds(mem, 0, bin, offs, fsz + page_offs); 333 ds = mem; 334 o = 0; 335 } 336 337 if (ph.flags() & PF_R) 338 rf |= L4Re::Rm::F::R; 339 340 if (ph.flags() & PF_W || mm->all_segs_cow()) 341 rf |= L4Re::Rm::F::W; 342 343 if (ph.flags() & PF_X) 344 rf |= L4Re::Rm::F::X; 345 346 mm->prog_attach_ds(l4_addr_t(paddr), size, ds, o, rf, 347 "attaching ELF segment"); 348 } 349}; 350 351template< typename App_model > 352struct Phdr_l4re_elf_aux_infos 353{ 354 mutable l4_size_t stack_size; 355 mutable l4_addr_t stack_addr; 356 mutable l4_addr_t kip_addr; 357 358 typedef typename App_model::Const_dataspace Const_dataspace; 359 App_model const *mm; 360 Const_dataspace bin; 361 362 explicit Phdr_l4re_elf_aux_infos(App_model const *mm, Const_dataspace bin, 363 l4_addr_t kip_addr) 364 : stack_size(sizeof(void*) * 0x2000), stack_addr(0x80000000), 365 kip_addr(kip_addr), mm(mm), bin(bin) 366 {} 367 368 void operator () (Elf_phdr const &h) const 369 { 370 if (h.type() != PT_L4_AUX) 371 return; 372 373 374 if (h.filesz()) 375 { 376 l4_addr_t addr = mm->local_attach_ds(bin, h.filesz(), h.offset()); 377 378 l4re_elf_aux_t const *e = (l4re_elf_aux_t const *)addr; 379 l4re_elf_aux_t const *end = (l4re_elf_aux_t const *)(addr + h.filesz()); 380 while (e < end && e->type) 381 { 382 switch (e->type) 383 { 384 case L4RE_ELF_AUX_T_STACK_SIZE: 385 { 386 l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e; 387 stack_size = v->value; 388 break; 389 } 390 case L4RE_ELF_AUX_T_STACK_ADDR: 391 { 392 l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e; 393 stack_addr = v->value; 394 break; 395 } 396 case L4RE_ELF_AUX_T_KIP_ADDR: 397 { 398 l4re_elf_aux_mword_t const *v = (l4re_elf_aux_mword_t const *)e; 399 kip_addr = v->value; 400 break; 401 } 402 default: 403 break; 404 } 405 406 e = (l4re_elf_aux_t const *)((char const *)e + e->length); 407 } 408 409 mm->local_detach_ds(addr, h.filesz()); 410 } 411 } 412}; 413 414template< typename App_model > 415struct Phdr_dynamic 416{ 417 typedef typename App_model::Const_dataspace Const_dataspace; 418 App_model const *mm; 419 Const_dataspace bin; 420 421 l4_addr_t base; 422 mutable char interp[100]; 423 mutable l4_addr_t phdrs; 424 mutable bool is_dynamic; 425 426 Phdr_dynamic(App_model const *mm, Const_dataspace bin, l4_addr_t base) 427 : mm(mm), bin(bin), base(base), phdrs(0), 428 is_dynamic(false) 429 { 430 static char const *const addr = "rom/libld-l4.so"; 431 unsigned i; 432 for (i = 0; i < sizeof(interp)-1 && addr[i]; ++i) 433 interp[i] = addr[i]; 434 } 435 436 void operator () (Elf_phdr const &ph) const 437 { 438 switch (ph.type()) 439 { 440 default: 441 return; 442 case PT_INTERP: 443 { 444 char const *addr = (char const *)mm->local_attach_ds(bin, ph.filesz(), ph.offset()); 445 unsigned i; 446 for (i = 0; i < sizeof(interp)-1 && addr[i]; ++i) 447 interp[i] = addr[i]; 448 449 interp[i] = 0; 450 mm->local_detach_ds(l4_addr_t(addr), ph.filesz()); 451 is_dynamic = true; 452 } 453 //ldr.printf(" found interpreter PHDR: interp='%s'\n", interp); 454 break; 455 case PT_PHDR: 456 phdrs = base + ph.paddr(); 457 break; 458 case PT_DYNAMIC: 459 //is_dynamic = true; 460 break; 461 } 462 } 463}; 464 465template< typename App_model > 466struct Phdr_l4re_elf_aux 467{ 468 typedef typename App_model::Const_dataspace Const_dataspace; 469 App_model *am; 470 Const_dataspace bin; 471 472 explicit Phdr_l4re_elf_aux(App_model *am, Const_dataspace bin) 473 : am(am), bin(bin) 474 {} 475 476 void operator () (Elf_phdr const &h) const 477 { 478 using L4Re::chksys; 479 if (h.type() != PT_L4_AUX) 480 return; 481 482 if (h.filesz()) 483 { 484 l4_addr_t addr = am->local_attach_ds(bin, h.filesz(), h.offset()); 485 486 l4re_elf_aux_t const *e = (l4re_elf_aux_t const *)addr; 487 l4re_elf_aux_t const *end = (l4re_elf_aux_t const *)(addr + h.filesz()); 488 489 while (e < end && e->type) 490 { 491 switch (e->type) 492 { 493 case L4RE_ELF_AUX_T_VMA: 494 { 495 l4re_elf_aux_vma_t const *v = (l4re_elf_aux_vma_t const *)e; 496 l4_addr_t start = v->start; 497 chksys(am->prog_reserve_area(&start, v->end - v->start + 1, 498 L4Re::Rm::Flags(0), 0)); 499 break; 500 } 501 default: 502 break; 503 } 504 505 e = (l4re_elf_aux_t const *)((char const *)e + e->length); 506 } 507 508 am->local_detach_ds(addr, h.filesz()); 509 // L4::cap_reinterpret_cast<L4Re::Debug_obj>(r)->debug(0); 510 } 511 } 512 513}; 514 515template< typename App_model, typename Dbg_ > 516class Elf_loader : public Loader<App_model, Dbg_> 517{ 518public: 519 typedef Loader<App_model, Dbg_> Base; 520public: 521 typedef typename Base::Const_dataspace Const_dataspace; 522 typedef typename Base::Dbg_log Dbg_log; 523 524 void read_infos(App_model *mm, Const_dataspace bin, 525 Dbg_log const &ldr) 526 { 527 using L4Re::chksys; 528 529 Elf_binary<App_model> elf(mm, bin); 530 531 if (!elf.is_valid()) 532 chksys(-L4_EINVAL, "not an ELF binary"); 533 534 Phdr_l4re_elf_aux_infos<App_model> stack_info(mm, bin, mm->prog_info()->kip); 535 elf.iterate_phdr(stack_info); 536 mm->stack()->set_target_stack(stack_info.stack_addr, stack_info.stack_size); 537 538 mm->prog_info()->kip = stack_info.kip_addr; 539 ldr.printf(" STACK: %lx (%zx) KIP: %lx\n", stack_info.stack_addr, 540 stack_info.stack_size, stack_info.kip_addr); 541 542 ldr.printf(" PHDRs: type offset\tpaddr\tvaddr\tfilesz\tmemsz\trights\n"); 543 elf.iterate_phdr(Phdr_print<Dbg_log>(ldr)); 544 } 545 546 void load(App_model *mm, Const_dataspace bin, l4_addr_t *base, bool interpreter, 547 Dbg_log const &ldr) 548 { 549 using L4Re::chksys; 550 551 Elf_binary<App_model> elf(mm, bin); 552 if (!elf.is_valid()) 553 { 554 ldr.printf("file is not an ELF binary\n"); 555 chksys(-L4_EINVAL, "not an ELF binary"); 556 } 557 558 L4Re::Rm::Flags r_flags(0); 559 l4_addr_t _base = 0; 560 if (base) 561 { 562 Phdr_load_min_max b_func; 563 ldr.printf(" relocate PIC/PIE binary\n"); 564 /* figure out size of the binary, if PIC */ 565 elf.iterate_phdr(b_func); 566 567 ldr.printf(" all PHDRs: [0x%lx-0x%lx]\n", b_func.start, b_func.end); 568 _base = *base; 569 570 l4_addr_t lib = _base + b_func.start; 571 chksys(mm->prog_reserve_area(&lib, b_func.end - b_func.start, 572 L4Re::Rm::F::Search_addr, L4_SUPERPAGESHIFT)); 573 574 ldr.printf(" relocate to %p\n", (void*)lib); 575 576 _base = l4_addr_t(lib) - b_func.start; 577 578 ldr.printf(" PHDRs: type offset\tpaddr\tvaddr\tfilesz\tmemsz\trights\n"); 579 elf.iterate_phdr(Phdr_print<Dbg_log>(ldr)); 580 *base = _base; 581 r_flags |= L4Re::Rm::F::In_area; 582 } 583 584 elf.iterate_phdr(Phdr_load<App_model, Dbg_log>(_base, bin, mm, r_flags, ldr)); 585 elf.iterate_phdr(Phdr_l4re_elf_aux<App_model>(mm, bin)); 586 587 mm->prog_info()->entry = elf.entry() + _base; 588 589 Phdr_dynamic<App_model> dyn_info(mm, bin, _base); 590 elf.iterate_phdr(dyn_info); 591 592 if (!interpreter && dyn_info.phdrs) 593 { 594 Prog_start_info *i = mm->prog_info(); 595 i->dyn_phdrs = dyn_info.phdrs; 596 i->dyn_num_phdrs = elf.num_phdrs(); 597 } 598 599 // Load the interpreter 600 if (!interpreter && dyn_info.is_dynamic) 601 { 602 ldr.printf(" dynamically linked executable, load interpreter '%s'\n", dyn_info.interp); 603 604 Const_dataspace file = mm->open_file(dyn_info.interp); 605 l4_addr_t base = 0x400000; 606 607 load(mm, file, &base, true, ldr); 608 609 Prog_start_info *i = mm->prog_info(); 610 611 i->dyn_exec_entry = elf.entry() + _base; 612 i->dyn_interp_base = base; 613 } 614 615 ldr.printf(" done...\n"); 616 } 617 618 void load(App_model *mm, Const_dataspace bin, 619 Dbg_log const &ldr) 620 { 621 load(mm, bin, 0, false, ldr); 622 } 623 624 625 626}; 627 628} 629 630 631