/* * Copyright (c) 2023, Jesús Lapastora * * SPDX-License-Identifier: BSD-2-Clause */ #include namespace ELF { SectionTable::Index StringTable::emit_into_builder(u32 name_index, SectionTable& builder) const noexcept { return builder.append(emit_section(name_index)); } Section StringTable::emit_section(u32 name_index) const noexcept { Elf64_Shdr header {}; header.sh_name = name_index; header.sh_type = SHT_STRTAB; header.sh_flags = 0; header.sh_addr = 0; header.sh_link = 0; header.sh_info = 0; header.sh_entsize = 0; header.sh_addralign = 0; return Section(m_data.span(), header); } u32 StringTable::insert(StringView str) noexcept { // The offsets for sh_name and st_name are 32-bit unsigned integers, so it // won't make sense to address a string table bigger than what u32 can // provide. VERIFY(m_data.size() < NumericLimits::max()); auto const offset = static_cast(m_data.size()); auto const final_size = m_data.size() + str.length() + 1; VERIFY(final_size < NumericLimits::max()); m_data.ensure_capacity(m_data.size() + str.length() + 1); for (auto ch : str) { VERIFY(ch != 0); m_data.unchecked_append(ch); } m_data.append(0); return offset; } FixedArray build_elf_image(u64 shstrndx, Elf64_Quarter image_type, ReadonlySpan
sections) { Checked final_image_size = sizeof(Elf64_Ehdr); Vector section_offsets; section_offsets.ensure_capacity(sections.size()); auto const sections_begin = final_image_size.value_unchecked(); final_image_size += sizeof(Elf64_Shdr) * sections.size(); for (auto const& section : sections) { auto const offset = final_image_size.value(); section_offsets.unchecked_append(offset); if (section.data.has_value()) { final_image_size += section.data.value().size(); } } auto image = MUST(FixedArray::create(final_image_size.value())); { auto section_headers = Span { reinterpret_cast(image.span().offset_pointer(sections_begin)), sections.size(), }; for (size_t i = 0; i < sections.size(); ++i) { section_headers[i] = sections[i].header; section_headers[i].sh_offset = section_offsets[i]; if (sections[i].data.has_value()) { auto const data = sections[i].data.value(); auto const data_in_elf = image.span().slice(section_offsets[i], data.size()); data.copy_to(data_in_elf); section_headers[i].sh_size = data.size(); } } } { auto* const final_elf_hdr = reinterpret_cast(image.data()); final_elf_hdr->e_ident[EI_MAG0] = 0x7f; final_elf_hdr->e_ident[EI_MAG1] = 'E'; final_elf_hdr->e_ident[EI_MAG2] = 'L'; final_elf_hdr->e_ident[EI_MAG3] = 'F'; final_elf_hdr->e_ident[EI_CLASS] = ELFCLASS64; // FIXME: This is platform-dependent. Any big-endian host will write the // data in MSB format, so the EI_DATA field should be set to // ELFDATA2MSB. final_elf_hdr->e_ident[EI_DATA] = ELFDATA2LSB; final_elf_hdr->e_ident[EI_VERSION] = EV_CURRENT; // FIXME: This is platform-dependent. The host must set the OSABI to the // one of the image target. final_elf_hdr->e_ident[EI_OSABI] = ELFOSABI_SYSV; final_elf_hdr->e_ident[EI_ABIVERSION] = 0; auto padding = Bytes { &final_elf_hdr->e_ident[EI_PAD], EI_NIDENT - EI_PAD, }; padding.fill(0); final_elf_hdr->e_type = image_type; // FIXME: This is platform-dependent. This must be set to the host // architecture. final_elf_hdr->e_machine = EM_AMD64; final_elf_hdr->e_version = EV_CURRENT; // Currently segments aren't supported, hence no program headers. // FIXME: Update program header info on ELF header when adding segment // information. final_elf_hdr->e_phoff = 0; final_elf_hdr->e_phnum = 0; final_elf_hdr->e_phentsize = 0; final_elf_hdr->e_shoff = sections_begin; final_elf_hdr->e_shnum = sections.size(); final_elf_hdr->e_shentsize = sizeof(Section::header); // FIXME: This is platform-dependent. The flags field should be in sync // with the architecture flags assumed in the code sections, otherwise // instructions may be misinterpreted. final_elf_hdr->e_flags = 0; final_elf_hdr->e_ehsize = sizeof(*final_elf_hdr); final_elf_hdr->e_shstrndx = shstrndx; } return image; } };