ELFBuild.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /*
  2. * Copyright (c) 2023, Jesús Lapastora <cyber.gsuscode@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. // Collection of utilities to produce an in-memory ELF file in the same format
  8. // as the host.
  9. #include <AK/FixedArray.h>
  10. #include <AK/Span.h>
  11. #include <AK/Vector.h>
  12. #include <LibELF/ELFABI.h>
  13. namespace ELF {
  14. // Represents an ELF Section that is optionally bound to some data.
  15. struct Section {
  16. Elf64_Shdr header;
  17. Optional<ReadonlyBytes> data {};
  18. explicit Section(Elf64_Shdr header)
  19. : header(header)
  20. {
  21. }
  22. Section(ReadonlyBytes data, Elf64_Shdr header)
  23. : header(header)
  24. , data(data)
  25. {
  26. }
  27. };
  28. // Receives a list of sections, and writes the following layout:
  29. // <elf layout> <section headers> <section data>
  30. //
  31. // Both the section headers & the data for those sections will be written in the
  32. // exact order as they appear in the list.
  33. // If a `Section` contains data, then its `sh_offset` is set to the offset in
  34. // the final image, and `sh_size` to the size of the specified data. `Section`s
  35. // that do not contain data will have their `sh_offset` set to the end offset of
  36. // the section that comes right before them.
  37. //
  38. // Notes on the ELF Header:
  39. // The elf header is mostly filled by this function. It needs help in a couple
  40. // of fields: `e_shstrndx` and `e_type`.
  41. //
  42. // - `shstrndx` is the index of the `Section` that contains the section name
  43. // string table.
  44. // - `image_type` is the image file type: ET_CORE, ET_REL, ET_EXEC, etc.
  45. FixedArray<u8> build_elf_image(u64 shstrndx, Elf64_Quarter image_type, ReadonlySpan<Section> sections);
  46. // Takes care of tracking section header indices and their order
  47. struct SectionTable {
  48. struct Index {
  49. u64 index;
  50. constexpr explicit Index(u64 index)
  51. : index(index)
  52. {
  53. }
  54. constexpr u64 raw_index() const noexcept { return index; }
  55. };
  56. ReadonlySpan<Section> span() const noexcept { return m_sections.span(); }
  57. // Appends a default-intialized header with no data. The client is
  58. // responsible for initializing the header before producing the final image.
  59. Index reserve() noexcept
  60. {
  61. return append(Section(Elf64_Shdr()));
  62. }
  63. // Appends a Section and returns the index to refer to it.
  64. Index append(Section section) noexcept
  65. {
  66. auto const index = m_sections.size();
  67. m_sections.append(move(section));
  68. return Index(index);
  69. }
  70. template<typename... Args>
  71. Index empend(Args&&... args) noexcept
  72. {
  73. auto const index = m_sections.size();
  74. m_sections.empend(forward<Args>(args)...);
  75. return Index(index);
  76. }
  77. // Calls `header_builder` with a reference to the Section header, so that
  78. // the builder can initialize it.
  79. // Returns the index for the section.
  80. template<typename Builder>
  81. Index build_nobits(Builder header_builder)
  82. {
  83. auto index = reserve();
  84. build_nobits_at(index, move(header_builder));
  85. return index;
  86. }
  87. // Creates a null section header. Useful for avoiding index 0 for the text
  88. // section, since if we use 0 for its index then symbols that relate to
  89. // .text will be misinterpreted as related to an 'undefined' section.
  90. Index build_null()
  91. {
  92. Elf64_Shdr header {};
  93. header.sh_type = SHT_NULL;
  94. header.sh_name = 0;
  95. return empend(header);
  96. }
  97. // Same as `build_nobits`, but writes an already reserved header instead of
  98. // creating a new one.
  99. template<typename Builder>
  100. void build_nobits_at(Index at, Builder header_builder)
  101. {
  102. Elf64_Shdr header {};
  103. header.sh_type = SHT_NOBITS;
  104. header_builder(header);
  105. new (&m_sections[at.raw_index()]) Section(header);
  106. }
  107. // Reinterprets `typed_data` as a byte slice, and calls `header_builder`
  108. // with a reference to the Section header to be initialized.
  109. // Sets the header's `sh_entsize` to `sizeof(T)` before calling the builder,
  110. // so it can be overridden if required.
  111. // Returns the index for the section.
  112. template<typename T, typename Builder>
  113. Index build(ReadonlySpan<T> typed_data, Builder header_builder)
  114. {
  115. auto index = reserve();
  116. build_at(index, move(typed_data), move(header_builder));
  117. return index;
  118. }
  119. // Same as `build`, but writes an already reserved header instead of
  120. // creating a new one.
  121. template<typename T, typename Builder>
  122. void build_at(Index at, ReadonlySpan<T> typed_data, Builder header_builder)
  123. {
  124. Elf64_Shdr header {};
  125. header.sh_entsize = sizeof(T);
  126. header_builder(static_cast<Elf64_Shdr&>(header));
  127. ReadonlyBytes data = ReadonlyBytes {
  128. reinterpret_cast<u8 const*>(typed_data.offset(0)),
  129. typed_data.size() * sizeof(T),
  130. };
  131. new (&m_sections[at.raw_index()]) Section(data, header);
  132. }
  133. // Makes header editing available after construction. The reference is valid
  134. // until another header is added.
  135. Elf64_Shdr& header_at(Index index) noexcept { return m_sections[index.raw_index()].header; }
  136. private:
  137. Vector<Section> m_sections;
  138. };
  139. struct StringTable {
  140. // Inserts the given string into the table, giving back the offset it begins
  141. // at. The string must not contain any zeroes.
  142. u32 insert(StringView str) noexcept;
  143. // Emits the section information for the current state, so that it can be
  144. // merged into an ELF image.
  145. Section emit_section(u32 name_index) const noexcept;
  146. // Like `emit_section`, but writes the section directly into the builder.
  147. // Returns the index for the section.
  148. SectionTable::Index emit_into_builder(u32 name_index, SectionTable& builder) const noexcept;
  149. private:
  150. Vector<u8> m_data;
  151. };
  152. };