LibELF: Start implementing elf library
This commit is contained in:
		
							parent
							
								
									60a99d1d23
								
							
						
					
					
						commit
						079df39ca8
					
				|  | @ -28,6 +28,7 @@ set(DISK_IMAGE_PATH ${CMAKE_BINARY_DIR}/banan-os.img) | |||
| add_subdirectory(kernel) | ||||
| add_subdirectory(BAN) | ||||
| add_subdirectory(libc) | ||||
| add_subdirectory(LibELF) | ||||
| 
 | ||||
| add_custom_target(sysroot | ||||
| 	COMMAND mkdir -p ${BANAN_SYSROOT} | ||||
|  | @ -41,6 +42,7 @@ add_custom_target(headers | |||
| 	DEPENDS kernel-headers | ||||
| 	DEPENDS ban-headers | ||||
| 	DEPENDS libc-headers | ||||
| 	DEPENDS libelf-headers | ||||
| ) | ||||
| 
 | ||||
| add_custom_target(toolchain | ||||
|  | @ -50,6 +52,7 @@ add_custom_target(toolchain | |||
| ) | ||||
| 
 | ||||
| add_custom_target(image | ||||
| 	COMMAND ${CMAKE_CXX_COMPILER} -x c ${CMAKE_SOURCE_DIR}/userspace/test.c -o ${BANAN_SYSROOT}/bin/test | ||||
| 	COMMAND ${CMAKE_COMMAND} -E env SYSROOT="${BANAN_SYSROOT}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/image.sh | ||||
| 	DEPENDS kernel-install | ||||
| 	DEPENDS ban-install | ||||
|  |  | |||
|  | @ -0,0 +1,12 @@ | |||
| cmake_minimum_required(VERSION 3.26) | ||||
| 
 | ||||
| project(LibELF CXX) | ||||
| 
 | ||||
| add_custom_target(libelf-headers | ||||
| 	COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include ${BANAN_INCLUDE} | ||||
| 	DEPENDS sysroot | ||||
| ) | ||||
| 
 | ||||
| add_custom_target(libelf-install | ||||
| 	DEPENDS libelf-headers | ||||
| ) | ||||
|  | @ -0,0 +1,189 @@ | |||
| #include <BAN/ScopeGuard.h> | ||||
| #include <kernel/Process.h> | ||||
| #include <LibELF/ELF.h> | ||||
| #include <LibELF/Values.h> | ||||
| 
 | ||||
| #include <fcntl.h> | ||||
| 
 | ||||
| namespace LibELF | ||||
| { | ||||
| 
 | ||||
| 	BAN::ErrorOr<ELF*> ELF::load_from_file(BAN::StringView file_path) | ||||
| 	{ | ||||
| 		ELF* elf = nullptr; | ||||
| 
 | ||||
| 		{ | ||||
| 			BAN::Vector<uint8_t> data; | ||||
| 
 | ||||
| 			int fd = TRY(Kernel::Process::current()->open(file_path, O_RDONLY)); | ||||
| 			BAN::ScopeGuard _([fd] { MUST(Kernel::Process::current()->close(fd)); }); | ||||
| 
 | ||||
| 			stat st; | ||||
| 			TRY(Kernel::Process::current()->fstat(fd, &st)); | ||||
| 
 | ||||
| 			TRY(data.resize(st.st_size)); | ||||
| 
 | ||||
| 			TRY(Kernel::Process::current()->read(fd, data.data(), data.size())); | ||||
| 
 | ||||
| 			elf = new ELF(BAN::move(data)); | ||||
| 			ASSERT(elf); | ||||
| 		} | ||||
| 
 | ||||
| 		if (auto res = elf->load(); res.is_error()) | ||||
| 		{ | ||||
| 			delete elf; | ||||
| 			return res.error(); | ||||
| 		} | ||||
| 
 | ||||
| 		return elf; | ||||
| 	} | ||||
| 
 | ||||
| 	const char* ELF::lookup_section_name(uint32_t offset) const | ||||
| 	{ | ||||
| 		return lookup_string(file_header64().e_shstrndx, offset); | ||||
| 	} | ||||
| 
 | ||||
| 	const char* ELF::lookup_string(size_t table_index, uint32_t offset) const | ||||
| 	{ | ||||
| 		if (table_index == SHN_UNDEF) | ||||
| 			return nullptr; | ||||
| 		auto& section_header = section_header64(table_index); | ||||
| 		return (const char*)m_data.data() + section_header.sh_offset + offset; | ||||
| 	} | ||||
| 
 | ||||
| 	bool ELF::parse_elf64_file_header(const Elf64FileHeader& header) | ||||
| 	{ | ||||
| 		if (header.e_type != ET_EXEC) | ||||
| 		{ | ||||
| 			dprintln("Only executable files are supported"); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		if (header.e_version != EV_CURRENT) | ||||
| 		{ | ||||
| 			dprintln("Invalid ELF version"); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	bool ELF::parse_elf64_section_header(const Elf64SectionHeader& header) | ||||
| 	{ | ||||
| 		if (auto* name = lookup_section_name(header.sh_name)) | ||||
| 			dprintln("{}", name); | ||||
| 
 | ||||
| 		switch (header.sh_type) | ||||
| 		{ | ||||
| 			case SHT_NULL: | ||||
| 				dprintln("  SHT_NULL"); | ||||
| 				break; | ||||
| 			case SHT_PROGBITS: | ||||
| 				dprintln("  SHT_PROGBITS"); | ||||
| 				break; | ||||
| 			case SHT_SYMTAB: | ||||
| 				for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++) | ||||
| 				{ | ||||
| 					auto& symbol = ((const Elf64Symbol*)(m_data.data() + header.sh_offset))[i]; | ||||
| 					if (auto* name = lookup_string(header.sh_link, symbol.st_name)) | ||||
| 						dprintln("  {}", name); | ||||
| 				} | ||||
| 				break; | ||||
| 			case SHT_STRTAB: | ||||
| 				dprintln("  SHT_STRTAB"); | ||||
| 				break; | ||||
| 			case SHT_RELA: | ||||
| 				dprintln("  SHT_RELA"); | ||||
| 				break; | ||||
| 			case SHT_NOBITS: | ||||
| 				dprintln("  SHT_NOBITS"); | ||||
| 				break; | ||||
| 			case SHT_REL: | ||||
| 				dprintln("  SHT_REL"); | ||||
| 				break; | ||||
| 			case SHT_SHLIB: | ||||
| 				dprintln("  SHT_SHLIB"); | ||||
| 				break; | ||||
| 			case SHT_DYNSYM: | ||||
| 				dprintln("  SHT_DYNSYM"); | ||||
| 				break; | ||||
| 			default: | ||||
| 				ASSERT(false); | ||||
| 		}	 | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> ELF::load() | ||||
| 	{ | ||||
| 		if (m_data.size() < EI_NIDENT) | ||||
| 		{ | ||||
| 			dprintln("Too small ELF file"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_data[EI_MAG0] != ELFMAG0 ||  | ||||
| 			m_data[EI_MAG1] != ELFMAG1 || | ||||
| 			m_data[EI_MAG2] != ELFMAG2 || | ||||
| 			m_data[EI_MAG3] != ELFMAG3) | ||||
| 		{ | ||||
| 			dprintln("Invalid ELF header"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_data[EI_DATA] != ELFDATA2LSB) | ||||
| 		{ | ||||
| 			dprintln("Only little-endian is supported"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_data[EI_VERSION] != EV_CURRENT) | ||||
| 		{ | ||||
| 			dprintln("Invalid ELF version"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_data[EI_CLASS] != ELFCLASS64) | ||||
| 		{ | ||||
| 			dprintln("Only 64 bit is supported"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_data.size() <= sizeof(Elf64FileHeader)) | ||||
| 		{ | ||||
| 			dprintln("Too small ELF file"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		auto& header = file_header64(); | ||||
| 		if (!parse_elf64_file_header(header)) | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 
 | ||||
| 		for (size_t i = 1; i < header.e_shnum; i++) | ||||
| 		{ | ||||
| 			auto& section_header = section_header64(i); | ||||
| 			if (!parse_elf64_section_header(section_header)) | ||||
| 				return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	const Elf64FileHeader& ELF::file_header64() const | ||||
| 	{ | ||||
| 		return *(const Elf64FileHeader*)m_data.data(); | ||||
| 	} | ||||
| 
 | ||||
| 	const Elf64ProgramHeader& ELF::program_header64(size_t index) const | ||||
| 	{ | ||||
| 		return ((const Elf64ProgramHeader*)(m_data.data() + file_header64().e_phoff))[index]; | ||||
| 	} | ||||
| 
 | ||||
| 	const Elf64SectionHeader& ELF::section_header64(size_t index) const | ||||
| 	{ | ||||
| 		return ((const Elf64SectionHeader*)(m_data.data() + file_header64().e_shoff))[index]; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,35 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/StringView.h> | ||||
| #include <BAN/Vector.h> | ||||
| #include "Types.h" | ||||
| 
 | ||||
| namespace LibELF | ||||
| { | ||||
| 
 | ||||
| 	class ELF | ||||
| 	{ | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<ELF*> load_from_file(BAN::StringView); | ||||
| 
 | ||||
| 		const Elf64FileHeader& file_header64() const; | ||||
| 		const Elf64ProgramHeader& program_header64(size_t) const; | ||||
| 		const Elf64SectionHeader& section_header64(size_t) const; | ||||
| 
 | ||||
| 		const char* lookup_section_name(uint32_t) const; | ||||
| 		const char* lookup_string(size_t, uint32_t) const; | ||||
| 
 | ||||
| 	private: | ||||
| 		ELF(BAN::Vector<uint8_t>&& data) | ||||
| 			: m_data(BAN::move(data)) | ||||
| 		{} | ||||
| 		BAN::ErrorOr<void> load(); | ||||
| 		 | ||||
| 		bool parse_elf64_file_header(const Elf64FileHeader&); | ||||
| 		bool parse_elf64_section_header(const Elf64SectionHeader&); | ||||
| 
 | ||||
| 	private: | ||||
| 		const BAN::Vector<uint8_t> m_data; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,83 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| namespace LibELF | ||||
| { | ||||
| 
 | ||||
| 	using Elf64Addr = uint64_t; | ||||
| 	using Elf64Off = uint64_t; | ||||
| 	using Elf64Half = uint16_t; | ||||
| 	using Elf64Word = uint32_t; | ||||
| 	using Elf64Sword = int32_t; | ||||
| 	using Elf64Xword = uint64_t; | ||||
| 	using Elf64Sxword = int64_t; | ||||
| 
 | ||||
| 	struct Elf64FileHeader | ||||
| 	{ | ||||
| 		unsigned char e_ident[16]; | ||||
| 		Elf64Half e_type; | ||||
| 		Elf64Half e_machine; | ||||
| 		Elf64Word e_version; | ||||
| 		Elf64Addr e_entry; | ||||
| 		Elf64Off e_phoff; | ||||
| 		Elf64Off e_shoff; | ||||
| 		Elf64Word e_flags; | ||||
| 		Elf64Half e_ehsize; | ||||
| 		Elf64Half e_phentsize; | ||||
| 		Elf64Half e_phnum; | ||||
| 		Elf64Half e_shentsize; | ||||
| 		Elf64Half e_shnum; | ||||
| 		Elf64Half e_shstrndx; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct Elf64SectionHeader | ||||
| 	{ | ||||
| 		Elf64Word sh_name; | ||||
| 		Elf64Word sh_type; | ||||
| 		Elf64Xword sh_flags; | ||||
| 		Elf64Addr sh_addr; | ||||
| 		Elf64Off sh_offset; | ||||
| 		Elf64Xword sh_size; | ||||
| 		Elf64Word sh_link; | ||||
| 		Elf64Word sh_info; | ||||
| 		Elf64Xword sh_addralign; | ||||
| 		Elf64Xword sh_entsize; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct Elf64Symbol | ||||
| 	{ | ||||
| 		Elf64Word st_name; | ||||
| 		unsigned char st_info; | ||||
| 		unsigned char st_other; | ||||
| 		Elf64Half st_shndx; | ||||
| 		Elf64Addr st_value; | ||||
| 		Elf64Xword st_size; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct Elf64Relocation | ||||
| 	{ | ||||
| 		Elf64Addr r_offset; | ||||
| 		Elf64Xword r_info; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct Elf64RelocationA | ||||
| 	{ | ||||
| 		Elf64Addr r_offset; | ||||
| 		Elf64Xword r_info; | ||||
| 		Elf64Sxword r_addend; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct Elf64ProgramHeader | ||||
| 	{ | ||||
| 		Elf64Word p_type; | ||||
| 		Elf64Word p_flags; | ||||
| 		Elf64Off p_offset; | ||||
| 		Elf64Addr p_vaddr; | ||||
| 		Elf64Addr p_paddr; | ||||
| 		Elf64Xword p_filesz; | ||||
| 		Elf64Xword p_memsz; | ||||
| 		Elf64Xword p_align; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,140 @@ | |||
| #pragma once | ||||
| 
 | ||||
| namespace LibELF | ||||
| { | ||||
| 
 | ||||
| 	enum ELF_Ident | ||||
| 	{ | ||||
| 		ELFMAG0			= 0x7F, | ||||
| 		ELFMAG1			= 'E', | ||||
| 		ELFMAG2			= 'L', | ||||
| 		ELFMAG3			= 'F', | ||||
| 
 | ||||
| 		ELFCLASSNONE	= 0, | ||||
| 		ELFCLASS32		= 1, | ||||
| 		ELFCLASS64		= 2, | ||||
| 
 | ||||
| 		ELFDATANONE		= 0, | ||||
| 		ELFDATA2LSB		= 1, | ||||
| 		ELFDATA2MSB		= 2, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_EI | ||||
| 	{ | ||||
| 		EI_MAG0			= 0, | ||||
| 		EI_MAG1			= 1, | ||||
| 		EI_MAG2			= 2, | ||||
| 		EI_MAG3			= 3, | ||||
| 		EI_CLASS		= 4, | ||||
| 		EI_DATA			= 5, | ||||
| 		EI_VERSION		= 6, | ||||
| 		EI_OSABI		= 7, | ||||
| 		EI_ABIVERSION	= 8, | ||||
| 		EI_NIDENT		= 16, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_ET | ||||
| 	{ | ||||
| 		ET_NONE		= 0, | ||||
| 		ET_REL		= 1, | ||||
| 		ET_EXEC		= 2, | ||||
| 		ET_DYN		= 3, | ||||
| 		ET_CORE		= 4, | ||||
| 		ET_LOOS		= 0xfe00, | ||||
| 		ET_HIOS		= 0xfeff, | ||||
| 		ET_LOPROC	= 0xff00, | ||||
| 		ET_HIPROC	= 0xffff, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_EV | ||||
| 	{ | ||||
| 		EV_NONE		= 0, | ||||
| 		EV_CURRENT	= 1, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_SHT | ||||
| 	{ | ||||
| 		SHT_NULL		= 0, | ||||
| 		SHT_PROGBITS	= 1, | ||||
| 		SHT_SYMTAB		= 2, | ||||
| 		SHT_STRTAB		= 3, | ||||
| 		SHT_RELA		= 4, | ||||
| 		SHT_NOBITS		= 8, | ||||
| 		SHT_REL			= 9, | ||||
| 		SHT_SHLIB		= 10, | ||||
| 		SHT_DYNSYM		= 11, | ||||
| 		SHT_LOOS		= 0x60000000, | ||||
| 		SHT_HIOS		= 0x6FFFFFFF, | ||||
| 		SHT_LOPROC		= 0x70000000, | ||||
| 		SHT_HIPROC		= 0x7FFFFFFF, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_SHF | ||||
| 	{ | ||||
| 		SHF_WRITE		= 0x1, | ||||
| 		SHF_ALLOC		= 0x2, | ||||
| 		SHF_EXECINSTR	= 0x4, | ||||
| 		SHF_MASKOS		= 0x0F000000, | ||||
| 		SHF_MASKPROC	= 0xF0000000, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_SHN | ||||
| 	{ | ||||
| 		SHN_UNDEF	= 0, | ||||
| 		SHN_LOPROC	= 0xFF00, | ||||
| 		SHN_HIPROC	= 0xFF1F, | ||||
| 		SHN_LOOS	= 0xFF20, | ||||
| 		SHN_HIOS	= 0xFF3F, | ||||
| 		SHN_ABS		= 0xFFF1, | ||||
| 		SHN_COMMON	= 0xFFF2, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_STB | ||||
| 	{ | ||||
| 		STB_LOCAL	= 0, | ||||
| 		STB_GLOBAL	= 1, | ||||
| 		STB_WEAK	= 2, | ||||
| 		STB_LOOS	= 10, | ||||
| 		STB_HIOS	= 12, | ||||
| 		STB_LOPROC	= 13, | ||||
| 		STB_HIPROC	= 15, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_STT | ||||
| 	{ | ||||
| 		STT_NOTYPE	= 0, | ||||
| 		STT_OBJECT	= 1, | ||||
| 		STT_FUNC	= 2, | ||||
| 		STT_SECTION	= 3, | ||||
| 		STT_FILE	= 4, | ||||
| 		STT_LOOS	= 10, | ||||
| 		STT_HIOS	= 12, | ||||
| 		STT_LOPROC	= 13, | ||||
| 		STT_HIPROC	= 15, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_PT | ||||
| 	{ | ||||
| 		PT_NULL		= 0, | ||||
| 		PT_LOAD		= 1, | ||||
| 		PT_DYNAMIC	= 2, | ||||
| 		PT_INTERP	= 3, | ||||
| 		PT_NOTE		= 4, | ||||
| 		PT_SHLIB	= 5, | ||||
| 		PT_PHDR		= 6, | ||||
| 		PT_LOOS		= 0x60000000, | ||||
| 		PT_HIOS		= 0x6FFFFFFF, | ||||
| 		PT_LOPROC	= 0x70000000, | ||||
| 		PT_HIPROC	= 0x7FFFFFFF, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum ELF_PF | ||||
| 	{ | ||||
| 		PF_X		= 0x1, | ||||
| 		PF_W		= 0x2, | ||||
| 		PF_R		= 0x4, | ||||
| 		PF_MASKOS	= 0x00FF0000, | ||||
| 		PF_MASKPROC	= 0xFF000000, | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -93,10 +93,15 @@ set(LIBC_SOURCES | |||
| 	../libc/string.cpp | ||||
| ) | ||||
| 
 | ||||
| set(LIBELF_SOURCES | ||||
| 	../LibELF/LibELF/ELF.cpp | ||||
| ) | ||||
| 
 | ||||
| set(KERNEL_SOURCES | ||||
| 	${KERNEL_SOURCES} | ||||
| 	${BAN_SOURCES} | ||||
| 	${LIBC_SOURCES} | ||||
| 	${LIBELF_SOURCES} | ||||
| ) | ||||
| 
 | ||||
| add_executable(kernel ${KERNEL_SOURCES}) | ||||
|  |  | |||
|  | @ -22,6 +22,8 @@ | |||
| #include <kernel/Terminal/TTY.h> | ||||
| #include <kernel/Terminal/VesaTerminalDriver.h> | ||||
| 
 | ||||
| #include <LibELF/ELF.h> | ||||
| 
 | ||||
| extern "C" const char g_kernel_cmdline[]; | ||||
| 
 | ||||
| struct ParsedCommandLine | ||||
|  | @ -177,7 +179,17 @@ static void init2(void* terminal_driver) | |||
| 	ASSERT(tty1); | ||||
| 	DeviceManager::get().add_device(tty1); | ||||
| 
 | ||||
| 	return jump_userspace(); | ||||
| 	MUST(Process::create_kernel( | ||||
| 		[](void*) | ||||
| 		{ | ||||
| 			MUST(LibELF::ELF::load_from_file("/bin/test"sv)); | ||||
| 			Process::current()->exit(); | ||||
| 		}, nullptr | ||||
| 	)); | ||||
| 	return; | ||||
| 
 | ||||
| 	jump_userspace(); | ||||
| 	return; | ||||
| 
 | ||||
| 	MUST(Process::create_kernel( | ||||
| 		[](void*)  | ||||
|  |  | |||
|  | @ -0,0 +1,5 @@ | |||
| int main() | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue