Skip to content

Commit

Permalink
Make loading /bin/bash ~250x faster.
Browse files Browse the repository at this point in the history
The ELF loader was doing huge amounts of unnecessary work.
Got rid of the "export symbols" and relocation passes since we don't need them.
They were useful things when bringing up the ELF loading code.

Also added a simple TSC-based Stopwatch RAII thingy to help debug performance issues.
  • Loading branch information
awesomekling committed Nov 12, 2018
1 parent 1cf20a2 commit dea474d
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 41 deletions.
4 changes: 4 additions & 0 deletions ELFLoader/ELFImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,13 @@ bool ELFImage::parse()
}
}

#ifdef SUPPORT_RELOCATIONS
// Then create a name-to-index map.
for (unsigned i = 0; i < section_count(); ++i) {
auto& section = this->section(i);
m_sections.set(section.name(), move(i));
}
#endif
return true;
}

Expand Down Expand Up @@ -172,6 +174,7 @@ const ELFImage::ProgramHeader ELFImage::program_header(unsigned index) const
return ProgramHeader(*this, index);
}

#ifdef SUPPORT_RELOCATIONS
const ELFImage::Relocation ELFImage::RelocationSection::relocation(unsigned index) const
{
ASSERT(index < relocation_count());
Expand Down Expand Up @@ -204,4 +207,5 @@ const ELFImage::Section ELFImage::lookupSection(const char* name) const
return section((*it).value);
return section(0);
}
#endif

11 changes: 11 additions & 0 deletions ELFLoader/ELFImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,12 @@ class ELFImage {
dword address() const { return m_section_header.sh_addr; }
const char* raw_data() const { return m_image.raw_data(m_section_header.sh_offset); }
bool is_undefined() const { return m_section_index == SHN_UNDEF; }
#ifdef SUPPORT_RELOCATIONS
const RelocationSection relocations() const;
#endif
dword flags() const { return m_section_header.sh_flags; }
bool is_writable() const { return flags() & SHF_WRITE; }
bool is_executable() const { return flags() & PF_X; }

protected:
friend class RelocationSection;
Expand All @@ -97,6 +102,7 @@ class ELFImage {
unsigned m_section_index;
};

#ifdef SUPPORT_RELOCATIONS
class RelocationSection : public Section {
public:
RelocationSection(const Section& section)
Expand Down Expand Up @@ -127,6 +133,7 @@ class ELFImage {
const ELFImage& m_image;
const Elf32_Rel& m_rel;
};
#endif

unsigned symbol_count() const;
unsigned section_count() const;
Expand Down Expand Up @@ -159,7 +166,9 @@ class ELFImage {
const char* section_index_to_string(unsigned index);

const byte* m_buffer { nullptr };
#ifdef SUPPORT_RELOCATIONS
HashMap<String, unsigned> m_sections;
#endif
bool m_valid { false };
unsigned m_symbol_table_section_index { 0 };
unsigned m_string_table_section_index { 0 };
Expand All @@ -184,6 +193,7 @@ inline void ELFImage::for_each_section_of_type(unsigned type, F func) const
}
}

#ifdef SUPPORT_RELOCATIONS
template<typename F>
inline void ELFImage::RelocationSection::for_each_relocation(F func) const
{
Expand All @@ -192,6 +202,7 @@ inline void ELFImage::RelocationSection::for_each_relocation(F func) const
break;
}
}
#endif

template<typename F>
inline void ELFImage::for_each_symbol(F func) const
Expand Down
72 changes: 34 additions & 38 deletions ELFLoader/ELFLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <AK/kstdio.h>

//#define ELFLOADER_DEBUG
//#define SUPPORT_RELOCATIONS

ELFLoader::ELFLoader(const byte* buffer)
: m_image(buffer)
Expand All @@ -22,9 +23,10 @@ bool ELFLoader::load()

if (!layout())
return false;
export_symbols();
#ifdef SUPPORT_RELOCATIONS
if (!perform_relocations())
return false;
#endif

return true;
}
Expand All @@ -49,7 +51,7 @@ bool ELFLoader::layout()
}
});

m_image.for_each_section_of_type(SHT_PROGBITS, [this] (const ELFImage::Section& section) {
m_image.for_each_section_of_type(SHT_PROGBITS, [] (const ELFImage::Section& section) {
#ifdef ELFLOADER_DEBUG
kprintf("ELFLoader: Copying progbits section: %s\n", section.name());
#endif
Expand All @@ -62,11 +64,15 @@ bool ELFLoader::layout()
#endif
return true;
}
memcpy(ptr, section.raw_data(), section.size());
// If this section isn't writable, it's already mmapped.
if (section.is_writable())
memcpy(ptr, section.raw_data(), section.size());
#ifdef SUPPORT_RELOCATIONS
m_sections.set(section.name(), move(ptr));
#endif
return true;
});
m_image.for_each_section_of_type(SHT_NOBITS, [this, &failed] (const ELFImage::Section& section) {
m_image.for_each_section_of_type(SHT_NOBITS, [&failed] (const ELFImage::Section& section) {
#ifdef ELFLOADER_DEBUG
kprintf("ELFLoader: Copying nobits section: %s\n", section.name());
#endif
Expand All @@ -79,19 +85,24 @@ bool ELFLoader::layout()
return false;
}
memset(ptr, 0, section.size());
#ifdef SUPPORT_RELOCATIONS
m_sections.set(section.name(), move(ptr));
#endif
return true;
});
return !failed;
}

#ifdef SUPPORT_RELOCATIONS
void* ELFLoader::lookup(const ELFImage::Symbol& symbol)
{
if (symbol.section().is_undefined())
return symbol_ptr(symbol.name());
return area_for_section(symbol.section()) + symbol.value();
}
#endif

#ifdef SUPPORT_RELOCATIONS
char* ELFLoader::area_for_section(const ELFImage::Section& section)
{
return area_for_section_name(section.name());
Expand All @@ -104,7 +115,9 @@ char* ELFLoader::area_for_section_name(const char* name)
ASSERT_NOT_REACHED();
return nullptr;
}
#endif

#ifdef SUPPORT_RELOCATIONS
bool ELFLoader::perform_relocations()
{
#ifdef ELFLOADER_DEBUG
Expand Down Expand Up @@ -166,39 +179,27 @@ bool ELFLoader::perform_relocations()
});
return !failed;
}
#endif

void ELFLoader::export_symbols()
char* ELFLoader::symbol_ptr(const char* name)
{
char* found_ptr = nullptr;
m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) {
#ifdef ELFLOADER_DEBUG
kprintf("symbol: %u, type=%u, name=%s, section=%u\n", symbol.index(), symbol.type(), symbol.name(), symbol.sectionIndex());
#endif
if (symbol.type() == STT_FUNC) {
char* ptr;
if (m_image.is_executable())
ptr = (char*)symbol.value();
else if (m_image.is_relocatable())
ptr = area_for_section(symbol.section()) + symbol.value();
else
ASSERT_NOT_REACHED();
add_symbol(symbol.name(), ptr, symbol.size());
}
// FIXME: What about other symbol types?
return true;
if (symbol.type() != STT_FUNC)
return true;
if (strcmp(symbol.name(), name))
return true;
if (m_image.is_executable())
found_ptr = (char*)symbol.value();
#ifdef SUPPORT_RELOCATIONS
else if (m_image.is_relocatable())
found_ptr = area_for_section(symbol.section()) + symbol.value();
#endif
else
ASSERT_NOT_REACHED();
return false;
});
}

char* ELFLoader::symbol_ptr(const char* name)
{
if (auto it = m_symbols.find(name); it != m_symbols.end()) {
auto& symbol = (*it).value;
#ifdef EXECSPACE_DEBUG
kprintf("[ELFLoader] symbol_ptr(%s) dump:\n", name);
disassemble(symbol.ptr, symbol.size);
#endif
return symbol.ptr;
}
return nullptr;
return found_ptr;
}

bool ELFLoader::allocate_section(LinearAddress laddr, size_t size, size_t alignment, bool is_readable, bool is_writable)
Expand All @@ -216,8 +217,3 @@ bool ELFLoader::map_section(LinearAddress laddr, size_t size, size_t alignment,
ksprintf(namebuf, "elf-map-%s%s", is_readable ? "r" : "", is_writable ? "w" : "");
return map_section_hook(laddr, size, alignment, offset_in_image, is_readable, is_writable, namebuf);
}

void ELFLoader::add_symbol(String&& name, char* ptr, unsigned size)
{
m_symbols.set(move(name), { ptr, size });
}
3 changes: 0 additions & 3 deletions ELFLoader/ELFLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ class ELFLoader {
Function<void*(LinearAddress, size_t, size_t, bool, bool, const String&)> alloc_section_hook;
Function<void*(LinearAddress, size_t, size_t, size_t, bool, bool, const String&)> map_section_hook;
char* symbol_ptr(const char* name);
void add_symbol(String&& name, char* ptr, unsigned size);
bool allocate_section(LinearAddress, size_t, size_t alignment, bool is_readable, bool is_writable);
bool map_section(LinearAddress, size_t, size_t alignment, size_t offset_in_image, bool is_readable, bool is_writable);

private:
bool layout();
bool perform_relocations();
void export_symbols();
void* lookup(const ELFImage::Symbol&);
char* area_for_section(const ELFImage::Section&);
char* area_for_section_name(const char*);
Expand All @@ -40,7 +38,6 @@ class ELFLoader {
};
ELFImage m_image;

HashMap<String, PtrAndSize> m_symbols;
HashMap<String, char*> m_sections;
};

33 changes: 33 additions & 0 deletions Kernel/i386.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "types.h"
#include "kprintf.h"

#define PAGE_SIZE 4096
#define PAGE_MASK 0xfffff000
Expand Down Expand Up @@ -218,3 +219,35 @@ class CPUID {
dword m_ecx { 0xffffffff };
dword m_edx { 0xffffffff };
};

inline void read_tsc(dword& lsw, dword& msw)
{
asm volatile("rdtsc":"=d"(msw),"=a"(lsw));
}

struct Stopwatch {
public:
Stopwatch(const char* name)
: m_name(name)
{
read_tsc(m_start_lsw, m_start_msw);
}

~Stopwatch()
{
dword end_lsw;
dword end_msw;
read_tsc(end_lsw, end_msw);
if (m_start_msw != end_msw) {
dbgprintf("differing msw's\n");
asm volatile("cli;hlt");
}
dword diff = end_lsw - m_start_lsw;
dbgprintf("Stopwatch(%s): %u ticks\n", m_name, diff);
}

private:
const char* m_name { nullptr };
dword m_start_lsw { 0 };
dword m_start_msw { 0 };
};

0 comments on commit dea474d

Please sign in to comment.