mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
48a9d0ede8
Introduces new builders, mainly `SectionTable` and `StringTable`, and a final `build_elf_image` to merge everything into a single memory image. Each of the builders are fully detached from one another, although StringTable provides an extra API to remove steps when using it with a SectionTable. This automates the part of figuring out and properly writing offsets to headers, and making sure all required data is properly copied and referenced in the final image.
179 lines
5.7 KiB
C++
179 lines
5.7 KiB
C++
/*
|
|
* Copyright (c) 2023, Jesús Lapastora <cyber.gsuscode@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
// Collection of utilities to produce an in-memory ELF file in the same format
|
|
// as the host.
|
|
|
|
#include <AK/FixedArray.h>
|
|
#include <AK/Span.h>
|
|
#include <AK/Vector.h>
|
|
#include <LibELF/ELFABI.h>
|
|
|
|
namespace ELF {
|
|
|
|
// Represents an ELF Section that is optionally bound to some data.
|
|
struct Section {
|
|
Elf64_Shdr header;
|
|
Optional<ReadonlyBytes> data {};
|
|
|
|
explicit Section(Elf64_Shdr header)
|
|
: header(header)
|
|
{
|
|
}
|
|
Section(ReadonlyBytes data, Elf64_Shdr header)
|
|
: header(header)
|
|
, data(data)
|
|
{
|
|
}
|
|
};
|
|
|
|
// Receives a list of sections, and writes the following layout:
|
|
// <elf layout> <section headers> <section data>
|
|
//
|
|
// Both the section headers & the data for those sections will be written in the
|
|
// exact order as they appear in the list.
|
|
// If a `Section` contains data, then its `sh_offset` is set to the offset in
|
|
// the final image, and `sh_size` to the size of the specified data. `Section`s
|
|
// that do not contain data will have their `sh_offset` set to the end offset of
|
|
// the section that comes right before them.
|
|
//
|
|
// Notes on the ELF Header:
|
|
// The elf header is mostly filled by this function. It needs help in a couple
|
|
// of fields: `e_shstrndx` and `e_type`.
|
|
//
|
|
// - `shstrndx` is the index of the `Section` that contains the section name
|
|
// string table.
|
|
// - `image_type` is the image file type: ET_CORE, ET_REL, ET_EXEC, etc.
|
|
FixedArray<u8> build_elf_image(u64 shstrndx, Elf64_Quarter image_type, ReadonlySpan<Section> sections);
|
|
|
|
// Takes care of tracking section header indices and their order
|
|
struct SectionTable {
|
|
|
|
struct Index {
|
|
u64 index;
|
|
|
|
constexpr explicit Index(u64 index)
|
|
: index(index)
|
|
{
|
|
}
|
|
|
|
constexpr u64 raw_index() const noexcept { return index; }
|
|
};
|
|
|
|
ReadonlySpan<Section> span() const noexcept { return m_sections.span(); }
|
|
|
|
// Appends a default-intialized header with no data. The client is
|
|
// responsible for initializing the header before producing the final image.
|
|
Index reserve() noexcept
|
|
{
|
|
return append(Section(Elf64_Shdr()));
|
|
}
|
|
|
|
// Appends a Section and returns the index to refer to it.
|
|
Index append(Section section) noexcept
|
|
{
|
|
auto const index = m_sections.size();
|
|
m_sections.append(move(section));
|
|
return Index(index);
|
|
}
|
|
template<typename... Args>
|
|
Index empend(Args&&... args) noexcept
|
|
{
|
|
auto const index = m_sections.size();
|
|
m_sections.empend(forward<Args>(args)...);
|
|
return Index(index);
|
|
}
|
|
|
|
// Calls `header_builder` with a reference to the Section header, so that
|
|
// the builder can initialize it.
|
|
// Returns the index for the section.
|
|
template<typename Builder>
|
|
Index build_nobits(Builder header_builder)
|
|
{
|
|
auto index = reserve();
|
|
build_nobits_at(index, move(header_builder));
|
|
return index;
|
|
}
|
|
|
|
// Creates a null section header. Useful for avoiding index 0 for the text
|
|
// section, since if we use 0 for its index then symbols that relate to
|
|
// .text will be misinterpreted as related to an 'undefined' section.
|
|
Index build_null()
|
|
{
|
|
Elf64_Shdr header {};
|
|
header.sh_type = SHT_NULL;
|
|
header.sh_name = 0;
|
|
return empend(header);
|
|
}
|
|
|
|
// Same as `build_nobits`, but writes an already reserved header instead of
|
|
// creating a new one.
|
|
template<typename Builder>
|
|
void build_nobits_at(Index at, Builder header_builder)
|
|
{
|
|
Elf64_Shdr header {};
|
|
header.sh_type = SHT_NOBITS;
|
|
header_builder(header);
|
|
new (&m_sections[at.raw_index()]) Section(header);
|
|
}
|
|
|
|
// Reinterprets `typed_data` as a byte slice, and calls `header_builder`
|
|
// with a reference to the Section header to be initialized.
|
|
// Sets the header's `sh_entsize` to `sizeof(T)` before calling the builder,
|
|
// so it can be overridden if required.
|
|
// Returns the index for the section.
|
|
template<typename T, typename Builder>
|
|
Index build(ReadonlySpan<T> typed_data, Builder header_builder)
|
|
{
|
|
auto index = reserve();
|
|
build_at(index, move(typed_data), move(header_builder));
|
|
return index;
|
|
}
|
|
|
|
// Same as `build`, but writes an already reserved header instead of
|
|
// creating a new one.
|
|
template<typename T, typename Builder>
|
|
void build_at(Index at, ReadonlySpan<T> typed_data, Builder header_builder)
|
|
{
|
|
Elf64_Shdr header {};
|
|
header.sh_entsize = sizeof(T);
|
|
header_builder(static_cast<Elf64_Shdr&>(header));
|
|
ReadonlyBytes data = ReadonlyBytes {
|
|
reinterpret_cast<u8 const*>(typed_data.offset(0)),
|
|
typed_data.size() * sizeof(T),
|
|
};
|
|
new (&m_sections[at.raw_index()]) Section(data, header);
|
|
}
|
|
|
|
// Makes header editing available after construction. The reference is valid
|
|
// until another header is added.
|
|
Elf64_Shdr& header_at(Index index) noexcept { return m_sections[index.raw_index()].header; }
|
|
|
|
private:
|
|
Vector<Section> m_sections;
|
|
};
|
|
|
|
struct StringTable {
|
|
// Inserts the given string into the table, giving back the offset it begins
|
|
// at. The string must not contain any zeroes.
|
|
u32 insert(StringView str) noexcept;
|
|
|
|
// Emits the section information for the current state, so that it can be
|
|
// merged into an ELF image.
|
|
Section emit_section(u32 name_index) const noexcept;
|
|
|
|
// Like `emit_section`, but writes the section directly into the builder.
|
|
// Returns the index for the section.
|
|
SectionTable::Index emit_into_builder(u32 name_index, SectionTable& builder) const noexcept;
|
|
|
|
private:
|
|
Vector<u8> m_data;
|
|
};
|
|
|
|
};
|