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
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>
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
;
36 lightOS::spinlock
elf::m_lock
;
39 size_t elf::library_count()
42 size_t size
= m_library
.size();
47 size_t elf::get_library_name(size_t index
,
50 if (index
>= m_library
.size())return 0;
54 size_t length
= m_library
[index
].name
.length();
61 m_library
[index
].name
.c_str());
67 pair
<uintptr_t,size_t> elf::get_library_address(size_t index
)
69 pair
<uintptr_t,size_t> result(0, 0);
72 if (index
< m_library
.size())
74 result
.first
= m_library
[index
].base_address
;
75 result
.second
= m_library
[index
].size
;
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
);
104 void elf::parse_dynamic(elf_dynamic_entry
*list
,
108 for (size_t i
= 0;i
< count
;i
++)
110 if (list
[i
].type
== DT_NULL
)break;
111 switch (list
[i
].type
)
115 // Save the index in the string table
116 mNeededLibraries
.push_back(list
[i
].value
);
120 // Save the number of symbols
121 if (mIsLibrary
== true)
122 mSymbolCount
= *adjust_pointer(reinterpret_cast<uint32_t*>(mHeader
), minAddr
+ list
[i
].address
+ 4);
124 mSymbolCount
= *adjust_pointer(reinterpret_cast<uint32_t*>(mHeader
), list
[i
].address
- 0x400000 + 4);
128 // Save a pointer to the string table
129 if (mIsLibrary
== true)
130 mStringTable
= adjust_pointer(reinterpret_cast<char*>(mHeader
), minAddr
+ list
[i
].address
);
132 mStringTable
= reinterpret_cast<char*>(list
[i
].address
);
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
);
140 mSymbolTable
= reinterpret_cast<elf_symbol
*>(list
[i
].address
);
144 // Save the size of one symbol table entry
145 mSymbolSize
= list
[i
].value
;
149 // Save a pointer to the Procedure Linkage/Global Offset Table
150 mPltGot
= reinterpret_cast<void*>(list
[i
].address
);
154 // Save the size of the relocation table
155 mPltGotRelocationTableSize
= list
[i
].value
;
159 // Save the type of relocation entries
160 mPltGotRelocationType
= list
[i
].value
;
164 mPltGotRelocationTable
= reinterpret_cast<void*>(list
[i
].address
);
168 // Save a pointer to the relocation table
169 mRelocationATable
= reinterpret_cast<elf_relocation_a
*>(list
[i
].address
);
173 // Save the size of the relocation table
174 mRelocationATableSize
= list
[i
].value
;
178 // Save the size of one relocation table entry
179 mRelocationASize
= list
[i
].value
;
183 // Save a pointer to the relocation table
184 mRelocationTable
= reinterpret_cast<elf_relocation
*>(list
[i
].address
);
188 // Save the size of the relocation table
189 mRelocationTableSize
= list
[i
].value
;
193 // Save the size of one relocation table entry
194 mRelocationSize
= list
[i
].value
;
198 //LOG("elf::create_library_image(): entry #" << dec << i << " = 0x" << hex << list[i].type << endl);
204 void *elf::lib_find_physical_page(uintptr_t address
,
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
);
213 void elf::lib_do_relocation_table(elf_relocation
*table
,
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
229 adjust_pointer(page1
, rel
->address
& 0xFFF),
236 void elf::lib_do_relocation_a_table(elf_relocation_a
*table
,
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
252 adjust_pointer(page1
, rel
->address
& 0xFFF),
259 void elf::create_library_image(const char *name
)
263 // Is the library already loaded
264 for (size_t i
= 0;i
< m_library
.size();i
++)
265 if (m_library
[i
].name
== name
)
271 // Library information
275 // Go through the segments
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
);
284 size_t fileSize
= p
->fileSize
;
285 for (size_t i
= 0;i
< p
->memorySize
;)
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
;
298 page
= PageAllocator
.allocate();
299 memset( physical_address
<void*>(page
),
301 virtual_memory::page_size
);
304 // Copy the section content to memory
307 size_t cpysize
= virtual_memory::page_size
;
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
],
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
;
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
;
339 i
+= virtual_memory::page_size
;
342 else if (p
->type
== 2)
345 parse_dynamic( adjust_pointer(reinterpret_cast<elf_dynamic_entry
*>(mHeader
), p
->offset
),
346 p
->fileSize
/ sizeof(elf_dynamic_entry
),
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
<< "\"");
370 // Search the symbol in the other shared libraries
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
);
383 WARNING("elf: unknown external symbol \"" << SymbolName
<< "\"");
388 // Process the relocations (REL)
389 if (mRelocationTable
!= 0)
391 lib_do_relocation_table(mRelocationTable
,
392 mRelocationTableSize
,
396 // Process the relocations (RELA)
397 if (mRelocationATable
!= 0)
399 lib_do_relocation_a_table( mRelocationATable
,
400 mRelocationATableSize
,
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
,
413 else if (mPltGotRelocationType
== DT_RELA
)
415 lib_do_relocation_a_table( reinterpret_cast<elf_relocation_a
*>(mPltGotRelocationTable
),
416 mPltGotRelocationTableSize
,
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
;
430 m_library
.push_back(lib
);
431 m_library_base
+= maxAddr
;
436 void elf::process_do_relocation_table( elf_relocation
*table
,
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;
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
;
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
);
467 reinterpret_cast<void*>(rel
->address
),
469 reinterpret_cast<void*>((rel
->address
+ virtual_memory::page_size
) & 0xFFFFF000),
471 reinterpret_cast<void*>((rel
->address
+ virtual_memory::page_size
) & 0xFFFFFFFFFFFFF000),
478 ERROR("elf::process_do_relocation_table(): could not find symbol \"" << name
<< "\"");
483 void elf::process_do_relocation_a_table(elf_relocation_a
*table
,
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;
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
;
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
);
514 reinterpret_cast<void*>(rel
->address
),
516 reinterpret_cast<void*>((rel
->address
+ virtual_memory::page_size
) & 0xFFFFF000),
518 reinterpret_cast<void*>((rel
->address
+ virtual_memory::page_size
) & 0xFFFFFFFFFFFFF000),
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
,
536 KERNEL_CONTEXT_START
;
538 page_allocator
&PageAllocator
= page_allocator::instance();
540 // Go through the sections
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");
560 for (size_t i
= 0;i
< Pages
.size();i
++)
561 PageAllocator
.free(Pages
[i
]);
569 bool alreadyMapped
= true;
570 void *page
= Context
.physical_address(reinterpret_cast<void*>(vAddr
& (~0xFFF)));
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
584 size_t cpysize
= virtual_memory::page_size
;
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
],
596 size_t flags
= lightOS::context::user
;
598 if ((p
->flags
& 0x01) != 0)flags
|= lightOS::context::execute
;
599 if ((p
->flags
& 0x02) != 0)flags
|= lightOS::context::write
;
600 if (alreadyMapped
== false)
603 reinterpret_cast<void*>(vAddr
),
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
));
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
;
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)
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)
638 mProgHeader
= adjust_pointer(reinterpret_cast<elf_program_header
*>(mHeader
), p
->offset
);
639 headerSize
= p
->fileSize
/ sizeof(elf_program_header
);
644 else if (p
->type
== 4 || p
->type
== 5)
646 ERROR("elf: unsupported program header type (0x" << hex(p
->type
) << ")");
651 LOG("elf: unknown program header type (0x" << hex(p
->type
) << ")");
656 Context
.heap(reinterpret_cast<void*>(maxAddr
));
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
]];
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
;
678 m_library
[i
].second
[y
].second
,
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
);
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
);
728 ERROR("elf::create_process_image(): unknown PLT/GOT relocation entries");
732 // Switch back to the original context
733 processor::context(oldCtx
);