- kdevelop3 project files
[lightOS.git] / kernel / elf.cpp
blob903dd2b04f1719c8711d1b35f883fa8c88b82998
1 /*
2 lightOS kernel
3 Copyright (C) 2006-2009 Jörg Pfähler
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <cstring>
20 #include <climits>
21 #include <kernel/log.hpp>
22 #include <kernel/elf.hpp>
23 #include <kernel/arch/arch.hpp>
24 #include <kernel/page_allocator.hpp>
25 #include <lightOS/c++utils.hpp>
26 #include <kernel/processor.hpp>
28 #include <kernel/virtual_memory.hpp>
29 using namespace std;
30 using namespace kernel;
31 using kernel::virtual_memory;
33 vector<kernel::elf::library> kernel::elf::m_library;
34 uintptr_t elf::m_library_base = SHARED_LIBRARY_START;
35 #ifdef _LIGHTOS_SMP
36 lightOS::spinlock elf::m_lock;
37 #endif
39 size_t elf::library_count()
41 LOCK(m_lock);
42 size_t size = m_library.size();
43 UNLOCK(m_lock);
44 return size;
47 size_t elf::get_library_name(size_t index,
48 char *result)
50 if (index >= m_library.size())return 0;
52 LOCK(m_lock);
54 size_t length = m_library[index].name.length();
55 if (result == 0)
57 UNLOCK(m_lock);
58 return length;
60 strcpy(result,
61 m_library[index].name.c_str());
63 UNLOCK(m_lock);
64 return length;
67 pair<uintptr_t,size_t> elf::get_library_address(size_t index)
69 pair<uintptr_t,size_t> result(0, 0);
71 LOCK(m_lock);
72 if (index < m_library.size())
74 result.first = m_library[index].base_address;
75 result.second = m_library[index].size;
77 UNLOCK(m_lock);
79 return result;
82 elf::elf(void *start, size_t s)
83 : mHeader(reinterpret_cast<elf_header*>(start)), mSize(s), mStringTable(0), mSymbolCount(0), mSymbolSize(0), mSymbolTable(0),
84 mRelocationSize(0), mRelocationTableSize(0), mRelocationTable(0), mRelocationASize(0), mRelocationATableSize(0),
85 mRelocationATable(0), mPltGot(0), mPltGotRelocationTable(0), mPltGotRelocationTableSize(0), mPltGotRelocationType(0)
87 mProgHeader = adjust_pointer(reinterpret_cast<elf_program_header*>(start), mHeader->programHeader);
90 void *elf::get_file_offset(void *vAddress, size_t size)
92 for (size_t i = 0;i < mHeader->programHeaderCount;i++)
94 elf_program_header *p = adjust_pointer(reinterpret_cast<elf_program_header*>(mProgHeader), i * mHeader->programHeaderSize);
95 if (p->vAddress <= reinterpret_cast<uintptr_t>(vAddress) &&
96 (p->vAddress + p->memorySize) >= reinterpret_cast<uintptr_t>(adjust_pointer(vAddress, size)))
98 return adjust_pointer(vAddress, reinterpret_cast<uintptr_t>(mHeader) + p->offset - p->vAddress);
101 return 0;
104 void elf::parse_dynamic(elf_dynamic_entry *list,
105 size_t count,
106 size_t minAddr)
108 for (size_t i = 0;i < count;i++)
110 if (list[i].type == DT_NULL)break;
111 switch (list[i].type)
113 case DT_NEEDED:
115 // Save the index in the string table
116 mNeededLibraries.push_back(list[i].value);
117 }break;
118 case DT_HASH:
120 // Save the number of symbols
121 if (mIsLibrary == true)
122 mSymbolCount = *adjust_pointer(reinterpret_cast<uint32_t*>(mHeader), minAddr + list[i].address + 4);
123 else
124 mSymbolCount = *adjust_pointer(reinterpret_cast<uint32_t*>(mHeader), list[i].address - 0x400000 + 4);
125 }break;
126 case DT_STRTAB:
128 // Save a pointer to the string table
129 if (mIsLibrary == true)
130 mStringTable = adjust_pointer(reinterpret_cast<char*>(mHeader), minAddr + list[i].address);
131 else
132 mStringTable = reinterpret_cast<char*>(list[i].address);
133 }break;
134 case DT_SYMTAB:
136 // Save a pointer to the symbol table
137 if (mIsLibrary == true)
138 mSymbolTable = adjust_pointer(reinterpret_cast<elf_symbol*>(mHeader), minAddr + list[i].address);
139 else
140 mSymbolTable = reinterpret_cast<elf_symbol*>(list[i].address);
141 }break;
142 case DT_SYMENT:
144 // Save the size of one symbol table entry
145 mSymbolSize = list[i].value;
146 }break;
147 case DT_PLTGOT:
149 // Save a pointer to the Procedure Linkage/Global Offset Table
150 mPltGot = reinterpret_cast<void*>(list[i].address);
151 }break;
152 case DT_PLTRELSZ:
154 // Save the size of the relocation table
155 mPltGotRelocationTableSize = list[i].value;
156 }break;
157 case DT_PLTREL:
159 // Save the type of relocation entries
160 mPltGotRelocationType = list[i].value;
161 }break;
162 case DT_JMPREL:
164 mPltGotRelocationTable = reinterpret_cast<void*>(list[i].address);
165 }break;
166 case DT_RELA:
168 // Save a pointer to the relocation table
169 mRelocationATable = reinterpret_cast<elf_relocation_a*>(list[i].address);
170 }break;
171 case DT_RELASZ:
173 // Save the size of the relocation table
174 mRelocationATableSize = list[i].value;
175 }break;
176 case DT_RELAENT:
178 // Save the size of one relocation table entry
179 mRelocationASize = list[i].value;
180 }break;
181 case DT_REL:
183 // Save a pointer to the relocation table
184 mRelocationTable = reinterpret_cast<elf_relocation*>(list[i].address);
185 }break;
186 case DT_RELSZ:
188 // Save the size of the relocation table
189 mRelocationTableSize = list[i].value;
190 }break;
191 case DT_RELENT:
193 // Save the size of one relocation table entry
194 mRelocationSize = list[i].value;
195 }break;
196 default:
198 //LOG("elf::create_library_image(): entry #" << dec << i << " = 0x" << hex << list[i].type << endl);
199 }break;
204 void *elf::lib_find_physical_page(uintptr_t address,
205 library &lib)
207 for (size_t y = 0;y < lib.second.size();y++)
208 if (lib.second[y].second == reinterpret_cast<void*>((address + m_library_base) & (~0xFFF)))
209 return physical_address<void*>(lib.second[y].first);
210 return 0;
213 void elf::lib_do_relocation_table(elf_relocation *table,
214 size_t size,
215 library &lib)
217 table = reinterpret_cast<elf_relocation*>(get_file_offset(table, size));
218 for (size_t i = 0;i < (size / sizeof(elf_relocation));i++)
220 elf_relocation *rel = &table[i];
221 elf_symbol *Symbol = adjust_pointer(reinterpret_cast<elf_symbol*>(mSymbolTable), ELF_RELOCATION_SYM(rel) * mSymbolSize);
223 // Find the right page
224 void *page1 = lib_find_physical_page(rel->address, lib);
225 void *page2 = lib_find_physical_page(rel->address + virtual_memory::page_size, lib);
227 // Process the relocation
228 do_relocation(rel,
229 adjust_pointer(page1, rel->address & 0xFFF),
230 page2,
231 m_library_base,
232 Symbol);
236 void elf::lib_do_relocation_a_table(elf_relocation_a *table,
237 size_t size,
238 library &lib)
240 table = reinterpret_cast<elf_relocation_a*>(get_file_offset(table, size));
241 for (size_t i = 0;i < (size / sizeof(elf_relocation_a));i++)
243 elf_relocation_a *rel = &table[i];
244 elf_symbol *Symbol = adjust_pointer(reinterpret_cast<elf_symbol*>(mSymbolTable), ELF_RELOCATION_SYM(rel) * mSymbolSize);
246 // Find the right page
247 void *page1 = lib_find_physical_page(rel->address, lib);
248 void *page2 = lib_find_physical_page(rel->address + virtual_memory::page_size, lib);
250 // Process the relocation
251 do_relocation_a(rel,
252 adjust_pointer(page1, rel->address & 0xFFF),
253 page2,
254 m_library_base,
255 Symbol);
259 void elf::create_library_image(const char *name)
261 LOCK(m_lock);
263 // Is the library already loaded
264 for (size_t i = 0;i < m_library.size();i++)
265 if (m_library[i].name == name)
267 UNLOCK(m_lock);
268 return;
271 // Library information
272 library lib;
273 lib.name = name;
275 // Go through the segments
276 size_t maxAddr = 0;
277 size_t minAddr = ULONG_MAX;
278 page_allocator &PageAllocator = page_allocator::instance();
279 for (size_t i = 0;i < mHeader->programHeaderCount;i++)
281 elf_program_header *p = reinterpret_cast<elf_program_header*>(reinterpret_cast<uintptr_t>(mProgHeader) + i * mHeader->programHeaderSize);
282 if (p->type == 1)
284 size_t fileSize = p->fileSize;
285 for (size_t i = 0;i < p->memorySize;)
287 size_t y = 0;
288 void *page = 0;
289 bool found = false;
290 for (;y < lib.second.size();y++)
291 if (lib.second[y].second == reinterpret_cast<void*>((p->vAddress + i + m_library_base) & (~0xFFF)))
293 page = lib.second[y].first;
294 found = true;
296 if (found == false)
298 page = PageAllocator.allocate();
299 memset( physical_address<void*>(page),
301 virtual_memory::page_size);
304 // Copy the section content to memory
305 if (fileSize != 0)
307 size_t cpysize = virtual_memory::page_size;
308 size_t offset = 0;
309 if (i == 0 && (p->vAddress & 0xFFF) != 0)
310 offset = p->vAddress & 0xFFF;
311 if (fileSize < virtual_memory::page_size)cpysize = fileSize;
312 if ((cpysize + offset) > virtual_memory::page_size)cpysize = virtual_memory::page_size - offset;
313 memcpy( physical_address<void*>(adjust_pointer(page, offset)),
314 &reinterpret_cast<char*>(mHeader)[p->offset + i],
315 cpysize);
318 // Save the page
319 size_t flags = lightOS::context::user;
320 if ((p->flags & 0x01) != 0)flags |= lightOS::context::execute;
321 if ((p->flags & 0x02) != 0)flags |= lightOS::context::write;
322 if (found == false)
324 lib.second.push_back(triple<void*,void*,size_t>(page, reinterpret_cast<void*>((p->vAddress + i + m_library_base) & (~0xFFF)), flags));
326 else if (flags != lib.second[y].third)
328 lib.second[y].third |= flags;
331 if ((p->vAddress + i + virtual_memory::page_size) > maxAddr)
332 maxAddr = p->vAddress + i + virtual_memory::page_size;
333 if ((p->offset + i) < minAddr)
334 minAddr = p->offset + i;
336 if (i == 0 && (p->vAddress & 0xFFF) != 0)fileSize += p->vAddress & 0xFFF;
337 if (fileSize > virtual_memory::page_size)fileSize -= virtual_memory::page_size;
338 else fileSize = 0;
339 i += virtual_memory::page_size;
342 else if (p->type == 2)
344 // DYNAMIC segment
345 parse_dynamic( adjust_pointer(reinterpret_cast<elf_dynamic_entry*>(mHeader), p->offset),
346 p->fileSize / sizeof(elf_dynamic_entry),
347 minAddr);
351 // correct maxAddr
352 if ((maxAddr % virtual_memory::page_size) != 0)maxAddr -= maxAddr % virtual_memory::page_size;
354 // Go through the symbol table
355 for (size_t i = 1;i < mSymbolCount;i++)
357 elf_symbol *Symbol = adjust_pointer(mSymbolTable, i * mSymbolSize);
358 char *SymbolName = &mStringTable[Symbol->name];
359 if (Symbol->shndx != 0)
361 Symbol->value += m_library_base;
362 lib.third.push_back(pair<string,void*>(SymbolName, reinterpret_cast<void*>(Symbol->value)));
364 else if (Symbol->shndx == 0 && (Symbol->info & 0x0F) == 2 && Symbol->value != 0)
366 LOG("elf: special symbol \"" << SymbolName << "\"");
368 else
370 // Search the symbol in the other shared libraries
371 bool found = false;
372 for (size_t y = 0;y < m_library.size();y++)
373 for (size_t z = 0;z < m_library[y].third.size();z++)
375 if (m_library[y].third[z].first == SymbolName)
377 Symbol->value = reinterpret_cast<uintptr_t>(m_library[y].third[z].second);
378 found = true;
381 if (found == false)
383 WARNING("elf: unknown external symbol \"" << SymbolName << "\"");
388 // Process the relocations (REL)
389 if (mRelocationTable != 0)
391 lib_do_relocation_table(mRelocationTable,
392 mRelocationTableSize,
393 lib);
396 // Process the relocations (RELA)
397 if (mRelocationATable != 0)
399 lib_do_relocation_a_table( mRelocationATable,
400 mRelocationATableSize,
401 lib);
404 // Process PLT/GOT relocation entries
405 if (mPltGotRelocationTable != 0)
407 if (mPltGotRelocationType == DT_REL)
409 lib_do_relocation_table(reinterpret_cast<elf_relocation*>(mPltGotRelocationTable),
410 mPltGotRelocationTableSize,
411 lib);
413 else if (mPltGotRelocationType == DT_RELA)
415 lib_do_relocation_a_table( reinterpret_cast<elf_relocation_a*>(mPltGotRelocationTable),
416 mPltGotRelocationTableSize,
417 lib);
419 else
421 ERROR("elf::create_library_image(): unknown PLT/GOT relocation entries");
425 LOG("elf: \"" << name << "\" loaded (address 0x" << hex(m_library_base) << " - 0x" <<
426 hex(m_library_base + maxAddr) << ")");
428 lib.base_address = m_library_base;
429 lib.size = maxAddr;
430 m_library.push_back(lib);
431 m_library_base += maxAddr;
433 UNLOCK(m_lock);
436 void elf::process_do_relocation_table( elf_relocation *table,
437 size_t size)
439 for (size_t i = 0;i < (size / sizeof(elf_relocation));i++)
441 elf_relocation *rel = &table[i];
442 if (ELF_RELOCATION_SYM(rel) == 0)continue;
444 bool found = false;
445 elf_symbol *Symbol = adjust_pointer(mSymbolTable, ELF_RELOCATION_SYM(rel) * mSymbolSize);
446 const char *name = &mStringTable[Symbol->name];
447 uintptr_t targetAddr = 0;
448 if (Symbol->shndx == 0xFFF1)
450 targetAddr = Symbol->value;
451 found = true;
453 else
455 for (size_t y = 0;y < m_library.size();y++)
456 for (size_t z = 0;z < m_library[y].third.size();z++)
457 if (m_library[y].third[z].first == name)
459 targetAddr = reinterpret_cast<uintptr_t>(m_library[y].third[z].second);
460 found = true;
464 if (found == true)
466 do_relocation( rel,
467 reinterpret_cast<void*>(rel->address),
468 #ifdef X86
469 reinterpret_cast<void*>((rel->address + virtual_memory::page_size) & 0xFFFFF000),
470 #else
471 reinterpret_cast<void*>((rel->address + virtual_memory::page_size) & 0xFFFFFFFFFFFFF000),
472 #endif
473 targetAddr,
474 Symbol);
476 else
478 ERROR("elf::process_do_relocation_table(): could not find symbol \"" << name << "\"");
483 void elf::process_do_relocation_a_table(elf_relocation_a *table,
484 size_t size)
486 for (size_t i = 0;i < (size / sizeof(elf_relocation_a));i++)
488 elf_relocation_a *rel = &table[i];
489 if (ELF_RELOCATION_SYM(rel) == 0)continue;
491 bool found = false;
492 elf_symbol *Symbol = adjust_pointer(mSymbolTable, ELF_RELOCATION_SYM(rel) * mSymbolSize);
493 const char *name = &mStringTable[Symbol->name];
494 uintptr_t targetAddr = 0;
495 if (Symbol->shndx != 0)
497 targetAddr = Symbol->value;
498 found = true;
500 else
502 for (size_t y = 0;y < m_library.size();y++)
503 for (size_t z = 0;z < m_library[y].third.size();z++)
504 if (m_library[y].third[z].first == name)
506 targetAddr = reinterpret_cast<uintptr_t>(m_library[y].third[z].second);
507 found = true;
511 if (found == true)
513 do_relocation_a(rel,
514 reinterpret_cast<void*>(rel->address),
515 #ifdef X86
516 reinterpret_cast<void*>((rel->address + virtual_memory::page_size) & 0xFFFFF000),
517 #else
518 reinterpret_cast<void*>((rel->address + virtual_memory::page_size) & 0xFFFFFFFFFFFFF000),
519 #endif
520 targetAddr,
521 Symbol);
523 else
525 ERROR("elf::process_do_relocation_a_table(): could not find symbol \"" << name << "\"");
530 bool elf::create_process_image( context &Context,
531 std::vector<void*> &Pages,
532 string &libName)
534 LOCK(m_lock);
536 KERNEL_CONTEXT_START;
538 page_allocator &PageAllocator = page_allocator::instance();
540 // Go through the sections
541 bool phdr = false;
542 uintptr_t maxAddr = 0x400000;
543 size_t headerSize = mHeader->programHeaderCount;
544 for (size_t i = 0;i < headerSize;i++)
546 elf_program_header *p = adjust_pointer(mProgHeader, i * mHeader->programHeaderSize);
548 if (p->type == 0)continue;
549 else if (p->type == 1)
551 size_t vAddr = p->vAddress;
552 size_t fileSize = p->fileSize;
553 for (size_t i = 0;i < p->memorySize;)
555 if (vAddr >= SHARED_LIBRARY_START)
557 ERROR("elf: invalid userspace elf file");
559 // Clean up
560 for (size_t i = 0;i < Pages.size();i++)
561 PageAllocator.free(Pages[i]);
563 KERNEL_CONTEXT_END;
565 UNLOCK(m_lock);
566 return false;
569 bool alreadyMapped = true;
570 void *page = Context.physical_address(reinterpret_cast<void*>(vAddr & (~0xFFF)));
571 if (page == 0)
573 page = PageAllocator.allocate();
574 memset( physical_address<void*>(page),
576 virtual_memory::page_size);
577 alreadyMapped = false;
578 Pages.push_back(page);
581 // Copy the section content to memory
582 if (fileSize != 0)
584 size_t cpysize = virtual_memory::page_size;
585 size_t offset = 0;
586 if (i == 0 && (vAddr & 0xFFF) != 0)
587 offset = vAddr & 0xFFF;
588 if (fileSize < virtual_memory::page_size)cpysize = fileSize;
589 if ((cpysize + offset) > virtual_memory::page_size)cpysize = virtual_memory::page_size - offset;
590 memcpy( physical_address<void*>(adjust_pointer(page, offset)),
591 &reinterpret_cast<char*>(mHeader)[p->offset + i],
592 cpysize);
595 // Map the page
596 size_t flags = lightOS::context::user;
597 size_t flags_old;
598 if ((p->flags & 0x01) != 0)flags |= lightOS::context::execute;
599 if ((p->flags & 0x02) != 0)flags |= lightOS::context::write;
600 if (alreadyMapped == false)
602 Context.map(page,
603 reinterpret_cast<void*>(vAddr),
604 flags);
606 // FIXME: We might need to adjust this for x86 (because there it is always executeable)
607 else if ((flags_old = Context.physical_address_flags(reinterpret_cast<void*>(vAddr))) != flags)
609 ERROR("elf: two section with different flags are overlapping @ 0x" << hex(vAddr) << ", flags = 0x" <<
610 hex(flags) << ", flags_old = 0x" << hex(flags_old));
611 processor::halt();
614 if (((vAddr + virtual_memory::page_size) & (~0xFFF)) > maxAddr)
615 maxAddr = (vAddr + virtual_memory::page_size) & (~0xFFF);
617 vAddr += virtual_memory::page_size;
618 if (i == 0 && (vAddr & 0xFFF) != 0)fileSize += p->vAddress & 0xFFF;
619 if (fileSize > virtual_memory::page_size)fileSize -= virtual_memory::page_size;
620 else fileSize = 0;
621 if (i == 0 && (p->vAddress & 0xFFF) != 0)
622 i = virtual_memory::page_size - (p->vAddress & 0xFFF);
623 else i += virtual_memory::page_size;
626 else if (p->type == 2)
628 // DYNAMIC segment
629 parse_dynamic( reinterpret_cast<elf_dynamic_entry*>(reinterpret_cast<uintptr_t>(mHeader) + p->offset),
630 p->fileSize / sizeof(elf_dynamic_entry),
633 else if (p->type == 3)continue;
634 else if (p->type == 6)
636 if (phdr == false)
638 mProgHeader = adjust_pointer(reinterpret_cast<elf_program_header*>(mHeader), p->offset);
639 headerSize = p->fileSize / sizeof(elf_program_header);
640 phdr = true;
641 --i;
644 else if (p->type == 4 || p->type == 5)
646 ERROR("elf: unsupported program header type (0x" << hex(p->type) << ")");
647 break;
649 else
651 LOG("elf: unknown program header type (0x" << hex(p->type) << ")");
652 continue;
656 Context.heap(reinterpret_cast<void*>(maxAddr));
657 KERNEL_CONTEXT_END;
659 // Switch to process's context
660 context_handle_t oldCtx = processor::context();
661 processor::context(Context.get_handle());
663 // Map the needed libraries
664 for (size_t i = 0;i < mNeededLibraries.size();i++)
666 const char *name = &mStringTable[mNeededLibraries[i]];
667 bool found = false;
668 for (size_t i = 0;i < m_library.size();i++)
669 if (m_library[i].name == name)
671 for (size_t y = 0;y < m_library[i].second.size();y++)
673 void *page = m_library[i].second[y].first;
674 size_t flags = m_library[i].second[y].third & (~lightOS::context::write);
675 if ((m_library[i].second[y].third & lightOS::context::write) != 0)
676 flags |= lightOS::context::copy_on_write;
677 Context.map(page,
678 m_library[i].second[y].second,
679 flags);
681 found = true;
683 if (found == false)
685 libName = name;
687 // Clean up
688 for (size_t i = 0;i < Pages.size();i++)
689 PageAllocator.free(Pages[i]);
691 // Switch back to the original context
692 processor::context(oldCtx);
694 UNLOCK(m_lock);
695 return false;
699 // Process the relocations (REL)
700 if (mRelocationTable != 0)
702 process_do_relocation_table(mRelocationTable,
703 mRelocationTableSize);
706 // Process the relocations (RELA)
707 if (mRelocationATable != 0)
709 process_do_relocation_a_table( mRelocationATable,
710 mRelocationATableSize);
713 // Process PLT/GOT relocation entries
714 if (mPltGotRelocationTable != 0)
716 if (mPltGotRelocationType == DT_REL)
718 process_do_relocation_table(reinterpret_cast<elf_relocation*>(mPltGotRelocationTable),
719 mPltGotRelocationTableSize);
721 else if (mPltGotRelocationType == DT_RELA)
723 process_do_relocation_a_table( reinterpret_cast<elf_relocation_a*>(mPltGotRelocationTable),
724 mPltGotRelocationTableSize);
726 else
728 ERROR("elf::create_process_image(): unknown PLT/GOT relocation entries");
732 // Switch back to the original context
733 processor::context(oldCtx);
735 UNLOCK(m_lock);
736 return true;