summaryrefslogtreecommitdiff
path: root/compiler/elf_builder.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/elf_builder.h')
-rw-r--r--compiler/elf_builder.h945
1 files changed, 945 insertions, 0 deletions
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
new file mode 100644
index 0000000000..bbd962fae2
--- /dev/null
+++ b/compiler/elf_builder.h
@@ -0,0 +1,945 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_ELF_BUILDER_H_
+#define ART_COMPILER_ELF_BUILDER_H_
+
+#include <vector>
+
+#include "arch/instruction_set.h"
+#include "base/bit_utils.h"
+#include "base/unix_file/fd_file.h"
+#include "buffered_output_stream.h"
+#include "elf_utils.h"
+#include "file_output_stream.h"
+
+namespace art {
+
+class CodeOutput {
+ public:
+ virtual bool Write(OutputStream* out) = 0;
+ virtual ~CodeOutput() {}
+};
+
+// Writes ELF file.
+// The main complication is that the sections often want to reference
+// each other. We solve this by writing the ELF file in two stages:
+// * Sections are asked about their size, and overall layout is calculated.
+// * Sections do the actual writes which may use offsets of other sections.
+template <typename ElfTypes>
+class ElfBuilder FINAL {
+ public:
+ using Elf_Addr = typename ElfTypes::Addr;
+ using Elf_Off = typename ElfTypes::Off;
+ using Elf_Word = typename ElfTypes::Word;
+ using Elf_Sword = typename ElfTypes::Sword;
+ using Elf_Ehdr = typename ElfTypes::Ehdr;
+ using Elf_Shdr = typename ElfTypes::Shdr;
+ using Elf_Sym = typename ElfTypes::Sym;
+ using Elf_Phdr = typename ElfTypes::Phdr;
+ using Elf_Dyn = typename ElfTypes::Dyn;
+
+ // Base class of all sections.
+ class Section {
+ public:
+ Section(const std::string& name, Elf_Word type, Elf_Word flags,
+ const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize)
+ : header_(), section_index_(0), name_(name), link_(link) {
+ header_.sh_type = type;
+ header_.sh_flags = flags;
+ header_.sh_info = info;
+ header_.sh_addralign = align;
+ header_.sh_entsize = entsize;
+ }
+ virtual ~Section() {}
+
+ // Returns the size of the content of this section. It is used to
+ // calculate file offsets of all sections before doing any writes.
+ virtual Elf_Word GetSize() const = 0;
+
+ // Write the content of this section to the given file.
+ // This must write exactly the number of bytes returned by GetSize().
+ // Offsets of all sections are known when this method is called.
+ virtual bool Write(File* elf_file) = 0;
+
+ Elf_Word GetLink() const {
+ return (link_ != nullptr) ? link_->GetSectionIndex() : 0;
+ }
+
+ const Elf_Shdr* GetHeader() const {
+ return &header_;
+ }
+
+ Elf_Shdr* GetHeader() {
+ return &header_;
+ }
+
+ Elf_Word GetSectionIndex() const {
+ DCHECK_NE(section_index_, 0u);
+ return section_index_;
+ }
+
+ void SetSectionIndex(Elf_Word section_index) {
+ section_index_ = section_index;
+ }
+
+ const std::string& GetName() const {
+ return name_;
+ }
+
+ private:
+ Elf_Shdr header_;
+ Elf_Word section_index_;
+ const std::string name_;
+ const Section* const link_;
+
+ DISALLOW_COPY_AND_ASSIGN(Section);
+ };
+
+ // Writer of .dynamic section.
+ class DynamicSection FINAL : public Section {
+ public:
+ void AddDynamicTag(Elf_Sword tag, Elf_Word value, const Section* section) {
+ DCHECK_NE(tag, static_cast<Elf_Sword>(DT_NULL));
+ dynamics_.push_back({tag, value, section});
+ }
+
+ DynamicSection(const std::string& name, Section* link)
+ : Section(name, SHT_DYNAMIC, SHF_ALLOC,
+ link, 0, kPageSize, sizeof(Elf_Dyn)) {}
+
+ Elf_Word GetSize() const OVERRIDE {
+ return (dynamics_.size() + 1 /* DT_NULL */) * sizeof(Elf_Dyn);
+ }
+
+ bool Write(File* elf_file) OVERRIDE {
+ std::vector<Elf_Dyn> buffer;
+ buffer.reserve(dynamics_.size() + 1u);
+ for (const ElfDynamicState& it : dynamics_) {
+ if (it.section_ != nullptr) {
+ // We are adding an address relative to a section.
+ buffer.push_back(
+ {it.tag_, {it.value_ + it.section_->GetHeader()->sh_addr}});
+ } else {
+ buffer.push_back({it.tag_, {it.value_}});
+ }
+ }
+ buffer.push_back({DT_NULL, {0}});
+ return WriteArray(elf_file, buffer.data(), buffer.size());
+ }
+
+ private:
+ struct ElfDynamicState {
+ Elf_Sword tag_;
+ Elf_Word value_;
+ const Section* section_;
+ };
+ std::vector<ElfDynamicState> dynamics_;
+ };
+
+ using PatchFn = void (*)(const std::vector<uintptr_t>& patch_locations,
+ Elf_Addr buffer_address,
+ Elf_Addr base_address,
+ std::vector<uint8_t>* buffer);
+
+ // Section with content based on simple memory buffer.
+ // The buffer can be optionally patched before writing.
+ class RawSection FINAL : public Section {
+ public:
+ RawSection(const std::string& name, Elf_Word type, Elf_Word flags,
+ const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize,
+ PatchFn patch = nullptr, const Section* patch_base_section = nullptr)
+ : Section(name, type, flags, link, info, align, entsize),
+ patched_(false), patch_(patch), patch_base_section_(patch_base_section) {
+ }
+
+ RawSection(const std::string& name, Elf_Word type)
+ : RawSection(name, type, 0, nullptr, 0, 1, 0, nullptr, nullptr) {
+ }
+
+ Elf_Word GetSize() const OVERRIDE {
+ return buffer_.size();
+ }
+
+ bool Write(File* elf_file) OVERRIDE {
+ if (!patch_locations_.empty()) {
+ DCHECK(!patched_); // Do not patch twice.
+ DCHECK(patch_ != nullptr);
+ DCHECK(patch_base_section_ != nullptr);
+ patch_(patch_locations_,
+ this->GetHeader()->sh_addr,
+ patch_base_section_->GetHeader()->sh_addr,
+ &buffer_);
+ patched_ = true;
+ }
+ return WriteArray(elf_file, buffer_.data(), buffer_.size());
+ }
+
+ bool IsEmpty() const {
+ return buffer_.size() == 0;
+ }
+
+ std::vector<uint8_t>* GetBuffer() {
+ return &buffer_;
+ }
+
+ void SetBuffer(const std::vector<uint8_t>& buffer) {
+ buffer_ = buffer;
+ }
+
+ std::vector<uintptr_t>* GetPatchLocations() {
+ return &patch_locations_;
+ }
+
+ private:
+ std::vector<uint8_t> buffer_;
+ std::vector<uintptr_t> patch_locations_;
+ bool patched_;
+ // User-provided function to do the actual patching.
+ PatchFn patch_;
+ // The section that we patch against (usually .text).
+ const Section* patch_base_section_;
+ };
+
+ // Writer of .rodata section or .text section.
+ // The write is done lazily using the provided CodeOutput.
+ class OatSection FINAL : public Section {
+ public:
+ OatSection(const std::string& name, Elf_Word type, Elf_Word flags,
+ const Section* link, Elf_Word info, Elf_Word align,
+ Elf_Word entsize, Elf_Word size, CodeOutput* code_output)
+ : Section(name, type, flags, link, info, align, entsize),
+ size_(size), code_output_(code_output) {
+ }
+
+ Elf_Word GetSize() const OVERRIDE {
+ return size_;
+ }
+
+ bool Write(File* elf_file) OVERRIDE {
+ // The BufferedOutputStream class contains the buffer as field,
+ // therefore it is too big to allocate on the stack.
+ std::unique_ptr<BufferedOutputStream> output_stream(
+ new BufferedOutputStream(new FileOutputStream(elf_file)));
+ return code_output_->Write(output_stream.get());
+ }
+
+ private:
+ Elf_Word size_;
+ CodeOutput* code_output_;
+ };
+
+ // Writer of .bss section.
+ class NoBitsSection FINAL : public Section {
+ public:
+ NoBitsSection(const std::string& name, Elf_Word size)
+ : Section(name, SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
+ size_(size) {
+ }
+
+ Elf_Word GetSize() const OVERRIDE {
+ return size_;
+ }
+
+ bool Write(File* elf_file ATTRIBUTE_UNUSED) OVERRIDE {
+ LOG(ERROR) << "This section should not be written to the ELF file";
+ return false;
+ }
+
+ private:
+ Elf_Word size_;
+ };
+
+ // Writer of .dynstr .strtab and .shstrtab sections.
+ class StrtabSection FINAL : public Section {
+ public:
+ StrtabSection(const std::string& name, Elf_Word flags)
+ : Section(name, SHT_STRTAB, flags, nullptr, 0, 1, 0) {
+ buffer_.reserve(4 * KB);
+ // The first entry of strtab must be empty string.
+ buffer_ += '\0';
+ }
+
+ Elf_Word AddName(const std::string& name) {
+ Elf_Word offset = buffer_.size();
+ buffer_ += name;
+ buffer_ += '\0';
+ return offset;
+ }
+
+ Elf_Word GetSize() const OVERRIDE {
+ return buffer_.size();
+ }
+
+ bool Write(File* elf_file) OVERRIDE {
+ return WriteArray(elf_file, buffer_.data(), buffer_.size());
+ }
+
+ private:
+ std::string buffer_;
+ };
+
+ class HashSection;
+
+ // Writer of .dynsym and .symtab sections.
+ class SymtabSection FINAL : public Section {
+ public:
+ // Add a symbol with given name to this symtab. The symbol refers to
+ // 'relative_addr' within the given section and has the given attributes.
+ void AddSymbol(const std::string& name, const Section* section,
+ Elf_Addr addr, bool is_relative, Elf_Word size,
+ uint8_t binding, uint8_t type, uint8_t other = 0) {
+ CHECK(section != nullptr);
+ Elf_Word name_idx = strtab_->AddName(name);
+ symbols_.push_back({ name, section, addr, size, is_relative,
+ MakeStInfo(binding, type), other, name_idx });
+ }
+
+ SymtabSection(const std::string& name, Elf_Word type, Elf_Word flags,
+ StrtabSection* strtab)
+ : Section(name, type, flags, strtab, 0, sizeof(Elf_Off), sizeof(Elf_Sym)),
+ strtab_(strtab) {
+ }
+
+ bool IsEmpty() const {
+ return symbols_.empty();
+ }
+
+ Elf_Word GetSize() const OVERRIDE {
+ return (1 /* NULL */ + symbols_.size()) * sizeof(Elf_Sym);
+ }
+
+ bool Write(File* elf_file) OVERRIDE {
+ std::vector<Elf_Sym> buffer;
+ buffer.reserve(1u + symbols_.size());
+ buffer.push_back(Elf_Sym()); // NULL.
+ for (const ElfSymbolState& it : symbols_) {
+ Elf_Sym sym = Elf_Sym();
+ sym.st_name = it.name_idx_;
+ if (it.is_relative_) {
+ sym.st_value = it.addr_ + it.section_->GetHeader()->sh_addr;
+ } else {
+ sym.st_value = it.addr_;
+ }
+ sym.st_size = it.size_;
+ sym.st_other = it.other_;
+ sym.st_shndx = it.section_->GetSectionIndex();
+ sym.st_info = it.info_;
+ buffer.push_back(sym);
+ }
+ return WriteArray(elf_file, buffer.data(), buffer.size());
+ }
+
+ private:
+ struct ElfSymbolState {
+ const std::string name_;
+ const Section* section_;
+ Elf_Addr addr_;
+ Elf_Word size_;
+ bool is_relative_;
+ uint8_t info_;
+ uint8_t other_;
+ Elf_Word name_idx_; // index in the strtab.
+ };
+
+ static inline constexpr uint8_t MakeStInfo(uint8_t binding, uint8_t type) {
+ return ((binding) << 4) + ((type) & 0xf);
+ }
+
+ // The symbols in the same order they will be in the symbol table.
+ std::vector<ElfSymbolState> symbols_;
+ StrtabSection* strtab_;
+
+ friend class HashSection;
+ };
+
+ // TODO: Consider removing.
+ // We use it only for the dynsym section which has only 5 symbols.
+ // We do not use it for symtab, and we probably do not have to
+ // since we use those symbols only to print backtraces.
+ class HashSection FINAL : public Section {
+ public:
+ HashSection(const std::string& name, Elf_Word flags, SymtabSection* symtab)
+ : Section(name, SHT_HASH, flags, symtab,
+ 0, sizeof(Elf_Word), sizeof(Elf_Word)),
+ symtab_(symtab) {
+ }
+
+ Elf_Word GetSize() const OVERRIDE {
+ Elf_Word nbuckets = GetNumBuckets();
+ Elf_Word chain_size = symtab_->symbols_.size() + 1 /* NULL */;
+ return (2 /* header */ + nbuckets + chain_size) * sizeof(Elf_Word);
+ }
+
+ bool Write(File* const elf_file) OVERRIDE {
+ // Here is how The ELF hash table works.
+ // There are 3 arrays to worry about.
+ // * The symbol table where the symbol information is.
+ // * The bucket array which is an array of indexes into the symtab and chain.
+ // * The chain array which is also an array of indexes into the symtab and chain.
+ //
+ // Lets say the state is something like this.
+ // +--------+ +--------+ +-----------+
+ // | symtab | | bucket | | chain |
+ // | null | | 1 | | STN_UNDEF |
+ // | <sym1> | | 4 | | 2 |
+ // | <sym2> | | | | 5 |
+ // | <sym3> | | | | STN_UNDEF |
+ // | <sym4> | | | | 3 |
+ // | <sym5> | | | | STN_UNDEF |
+ // +--------+ +--------+ +-----------+
+ //
+ // The lookup process (in python psudocode) is
+ //
+ // def GetSym(name):
+ // # NB STN_UNDEF == 0
+ // indx = bucket[elfhash(name) % num_buckets]
+ // while indx != STN_UNDEF:
+ // if GetSymbolName(symtab[indx]) == name:
+ // return symtab[indx]
+ // indx = chain[indx]
+ // return SYMBOL_NOT_FOUND
+ //
+ // Between bucket and chain arrays every symtab index must be present exactly
+ // once (except for STN_UNDEF, which must be present 1 + num_bucket times).
+ const auto& symbols = symtab_->symbols_;
+ // Select number of buckets.
+ // This is essentially arbitrary.
+ Elf_Word nbuckets = GetNumBuckets();
+ // 1 is for the implicit NULL symbol.
+ Elf_Word chain_size = (symbols.size() + 1);
+ std::vector<Elf_Word> hash;
+ hash.push_back(nbuckets);
+ hash.push_back(chain_size);
+ uint32_t bucket_offset = hash.size();
+ uint32_t chain_offset = bucket_offset + nbuckets;
+ hash.resize(hash.size() + nbuckets + chain_size, 0);
+
+ Elf_Word* buckets = hash.data() + bucket_offset;
+ Elf_Word* chain = hash.data() + chain_offset;
+
+ // Set up the actual hash table.
+ for (Elf_Word i = 0; i < symbols.size(); i++) {
+ // Add 1 since we need to have the null symbol that is not in the symbols
+ // list.
+ Elf_Word index = i + 1;
+ Elf_Word hash_val = static_cast<Elf_Word>(elfhash(symbols[i].name_.c_str())) % nbuckets;
+ if (buckets[hash_val] == 0) {
+ buckets[hash_val] = index;
+ } else {
+ hash_val = buckets[hash_val];
+ CHECK_LT(hash_val, chain_size);
+ while (chain[hash_val] != 0) {
+ hash_val = chain[hash_val];
+ CHECK_LT(hash_val, chain_size);
+ }
+ chain[hash_val] = index;
+ // Check for loops. Works because if this is non-empty then there must be
+ // another cell which already contains the same symbol index as this one,
+ // which means some symbol has more then one name, which isn't allowed.
+ CHECK_EQ(chain[index], static_cast<Elf_Word>(0));
+ }
+ }
+ return WriteArray(elf_file, hash.data(), hash.size());
+ }
+
+ private:
+ Elf_Word GetNumBuckets() const {
+ const auto& symbols = symtab_->symbols_;
+ if (symbols.size() < 8) {
+ return 2;
+ } else if (symbols.size() < 32) {
+ return 4;
+ } else if (symbols.size() < 256) {
+ return 16;
+ } else {
+ // Have about 32 ids per bucket.
+ return RoundUp(symbols.size()/32, 2);
+ }
+ }
+
+ // from bionic
+ static inline unsigned elfhash(const char *_name) {
+ const unsigned char *name = (const unsigned char *) _name;
+ unsigned h = 0, g;
+
+ while (*name) {
+ h = (h << 4) + *name++;
+ g = h & 0xf0000000;
+ h ^= g;
+ h ^= g >> 24;
+ }
+ return h;
+ }
+
+ SymtabSection* symtab_;
+
+ DISALLOW_COPY_AND_ASSIGN(HashSection);
+ };
+
+ ElfBuilder(InstructionSet isa,
+ Elf_Word rodata_size, CodeOutput* rodata_writer,
+ Elf_Word text_size, CodeOutput* text_writer,
+ Elf_Word bss_size)
+ : isa_(isa),
+ dynstr_(".dynstr", SHF_ALLOC),
+ dynsym_(".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_),
+ hash_(".hash", SHF_ALLOC, &dynsym_),
+ rodata_(".rodata", SHT_PROGBITS, SHF_ALLOC,
+ nullptr, 0, kPageSize, 0, rodata_size, rodata_writer),
+ text_(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
+ nullptr, 0, kPageSize, 0, text_size, text_writer),
+ bss_(".bss", bss_size),
+ dynamic_(".dynamic", &dynstr_),
+ strtab_(".strtab", 0),
+ symtab_(".symtab", SHT_SYMTAB, 0, &strtab_),
+ shstrtab_(".shstrtab", 0) {
+ }
+ ~ElfBuilder() {}
+
+ OatSection* GetText() { return &text_; }
+ SymtabSection* GetSymtab() { return &symtab_; }
+
+ bool Write(File* elf_file) {
+ // Since the .text section of an oat file contains relative references to .rodata
+ // and (optionally) .bss, we keep these 2 or 3 sections together. This creates
+ // a non-traditional layout where the .bss section is mapped independently of the
+ // .dynamic section and needs its own program header with LOAD RW.
+ //
+ // The basic layout of the elf file. Order may be different in final output.
+ // +-------------------------+
+ // | Elf_Ehdr |
+ // +-------------------------+
+ // | Elf_Phdr PHDR |
+ // | Elf_Phdr LOAD R | .dynsym .dynstr .hash .rodata
+ // | Elf_Phdr LOAD R X | .text
+ // | Elf_Phdr LOAD RW | .bss (Optional)
+ // | Elf_Phdr LOAD RW | .dynamic
+ // | Elf_Phdr DYNAMIC | .dynamic
+ // | Elf_Phdr LOAD R | .eh_frame .eh_frame_hdr
+ // | Elf_Phdr EH_FRAME R | .eh_frame_hdr
+ // +-------------------------+
+ // | .dynsym |
+ // | Elf_Sym STN_UNDEF |
+ // | Elf_Sym oatdata |
+ // | Elf_Sym oatexec |
+ // | Elf_Sym oatlastword |
+ // | Elf_Sym oatbss | (Optional)
+ // | Elf_Sym oatbsslastword | (Optional)
+ // +-------------------------+
+ // | .dynstr |
+ // | names for .dynsym |
+ // +-------------------------+
+ // | .hash |
+ // | hashtable for dynsym |
+ // +-------------------------+
+ // | .rodata |
+ // | oatdata..oatexec-4 |
+ // +-------------------------+
+ // | .text |
+ // | oatexec..oatlastword |
+ // +-------------------------+
+ // | .dynamic |
+ // | Elf_Dyn DT_HASH |
+ // | Elf_Dyn DT_STRTAB |
+ // | Elf_Dyn DT_SYMTAB |
+ // | Elf_Dyn DT_SYMENT |
+ // | Elf_Dyn DT_STRSZ |
+ // | Elf_Dyn DT_SONAME |
+ // | Elf_Dyn DT_NULL |
+ // +-------------------------+ (Optional)
+ // | .symtab | (Optional)
+ // | program symbols | (Optional)
+ // +-------------------------+ (Optional)
+ // | .strtab | (Optional)
+ // | names for .symtab | (Optional)
+ // +-------------------------+ (Optional)
+ // | .eh_frame | (Optional)
+ // +-------------------------+ (Optional)
+ // | .eh_frame_hdr | (Optional)
+ // +-------------------------+ (Optional)
+ // | .debug_info | (Optional)
+ // +-------------------------+ (Optional)
+ // | .debug_abbrev | (Optional)
+ // +-------------------------+ (Optional)
+ // | .debug_str | (Optional)
+ // +-------------------------+ (Optional)
+ // | .debug_line | (Optional)
+ // +-------------------------+
+ // | .shstrtab |
+ // | names of sections |
+ // +-------------------------+
+ // | Elf_Shdr null |
+ // | Elf_Shdr .dynsym |
+ // | Elf_Shdr .dynstr |
+ // | Elf_Shdr .hash |
+ // | Elf_Shdr .rodata |
+ // | Elf_Shdr .text |
+ // | Elf_Shdr .bss | (Optional)
+ // | Elf_Shdr .dynamic |
+ // | Elf_Shdr .symtab | (Optional)
+ // | Elf_Shdr .strtab | (Optional)
+ // | Elf_Shdr .eh_frame | (Optional)
+ // | Elf_Shdr .eh_frame_hdr | (Optional)
+ // | Elf_Shdr .debug_info | (Optional)
+ // | Elf_Shdr .debug_abbrev | (Optional)
+ // | Elf_Shdr .debug_str | (Optional)
+ // | Elf_Shdr .debug_line | (Optional)
+ // | Elf_Shdr .oat_patches | (Optional)
+ // | Elf_Shdr .shstrtab |
+ // +-------------------------+
+ constexpr bool debug_logging_ = false;
+
+ // Create a list of all section which we want to write.
+ // This is the order in which they will be written.
+ std::vector<Section*> sections;
+ sections.push_back(&dynsym_);
+ sections.push_back(&dynstr_);
+ sections.push_back(&hash_);
+ sections.push_back(&rodata_);
+ sections.push_back(&text_);
+ if (bss_.GetSize() != 0u) {
+ sections.push_back(&bss_);
+ }
+ sections.push_back(&dynamic_);
+ if (!symtab_.IsEmpty()) {
+ sections.push_back(&symtab_);
+ sections.push_back(&strtab_);
+ }
+ for (Section* section : other_sections_) {
+ sections.push_back(section);
+ }
+ sections.push_back(&shstrtab_);
+ for (size_t i = 0; i < sections.size(); i++) {
+ // The first section index is 1. Index 0 is reserved for NULL.
+ // Section index is used for relative symbols and for section links.
+ sections[i]->SetSectionIndex(i + 1);
+ // Add section name to .shstrtab.
+ Elf_Word name_offset = shstrtab_.AddName(sections[i]->GetName());
+ sections[i]->GetHeader()->sh_name = name_offset;
+ }
+
+ // The running program does not have access to section headers
+ // and the loader is not supposed to use them either.
+ // The dynamic sections therefore replicates some of the layout
+ // information like the address and size of .rodata and .text.
+ // It also contains other metadata like the SONAME.
+ // The .dynamic section is found using the PT_DYNAMIC program header.
+ BuildDynsymSection();
+ BuildDynamicSection(elf_file->GetPath());
+
+ // We do not know the number of headers until the final stages of write.
+ // It is easiest to just reserve a fixed amount of space for them.
+ constexpr size_t kMaxProgramHeaders = 8;
+ constexpr size_t kProgramHeadersOffset = sizeof(Elf_Ehdr);
+
+ // Layout of all sections - determine the final file offsets and addresses.
+ // This must be done after we have built all sections and know their size.
+ Elf_Off file_offset = kProgramHeadersOffset + sizeof(Elf_Phdr) * kMaxProgramHeaders;
+ Elf_Addr load_address = file_offset;
+ std::vector<Elf_Shdr> section_headers;
+ section_headers.reserve(1u + sections.size());
+ section_headers.push_back(Elf_Shdr()); // NULL at index 0.
+ for (auto* section : sections) {
+ Elf_Shdr* header = section->GetHeader();
+ Elf_Off alignment = header->sh_addralign > 0 ? header->sh_addralign : 1;
+ header->sh_size = section->GetSize();
+ header->sh_link = section->GetLink();
+ // Allocate memory for the section in the file.
+ if (header->sh_type != SHT_NOBITS) {
+ header->sh_offset = RoundUp(file_offset, alignment);
+ file_offset = header->sh_offset + header->sh_size;
+ }
+ // Allocate memory for the section during program execution.
+ if ((header->sh_flags & SHF_ALLOC) != 0) {
+ header->sh_addr = RoundUp(load_address, alignment);
+ load_address = header->sh_addr + header->sh_size;
+ }
+ if (debug_logging_) {
+ LOG(INFO) << "Section " << section->GetName() << ":" << std::hex
+ << " offset=0x" << header->sh_offset
+ << " addr=0x" << header->sh_addr
+ << " size=0x" << header->sh_size;
+ }
+ // Collect section headers into continuous array for convenience.
+ section_headers.push_back(*header);
+ }
+ Elf_Off section_headers_offset = RoundUp(file_offset, sizeof(Elf_Off));
+
+ // Create program headers now that we know the layout of the whole file.
+ // Each segment contains one or more sections which are mapped together.
+ // Not all sections are mapped during the execution of the program.
+ // PT_LOAD does the mapping. Other PT_* types allow the program to locate
+ // interesting parts of memory and their addresses overlap with PT_LOAD.
+ std::vector<Elf_Phdr> program_headers;
+ program_headers.push_back(Elf_Phdr()); // Placeholder for PT_PHDR.
+ // Create the main LOAD R segment which spans all sections up to .rodata.
+ const Elf_Shdr* rodata = rodata_.GetHeader();
+ program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R,
+ 0, rodata->sh_offset + rodata->sh_size, rodata->sh_addralign));
+ program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_X, text_));
+ if (bss_.GetHeader()->sh_size != 0u) {
+ program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_W, bss_));
+ }
+ program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_W, dynamic_));
+ program_headers.push_back(MakeProgramHeader(PT_DYNAMIC, PF_R | PF_W, dynamic_));
+ const Section* eh_frame = FindSection(".eh_frame");
+ if (eh_frame != nullptr) {
+ program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R, *eh_frame));
+ const Section* eh_frame_hdr = FindSection(".eh_frame_hdr");
+ if (eh_frame_hdr != nullptr) {
+ // Check layout: eh_frame is before eh_frame_hdr and there is no gap.
+ CHECK_LE(eh_frame->GetHeader()->sh_offset, eh_frame_hdr->GetHeader()->sh_offset);
+ CHECK_EQ(eh_frame->GetHeader()->sh_offset + eh_frame->GetHeader()->sh_size,
+ eh_frame_hdr->GetHeader()->sh_offset);
+ // Extend the PT_LOAD of .eh_frame to include the .eh_frame_hdr as well.
+ program_headers.back().p_filesz += eh_frame_hdr->GetHeader()->sh_size;
+ program_headers.back().p_memsz += eh_frame_hdr->GetHeader()->sh_size;
+ program_headers.push_back(MakeProgramHeader(PT_GNU_EH_FRAME, PF_R, *eh_frame_hdr));
+ }
+ }
+ DCHECK_EQ(program_headers[0].p_type, 0u); // Check placeholder.
+ program_headers[0] = MakeProgramHeader(PT_PHDR, PF_R,
+ kProgramHeadersOffset, program_headers.size() * sizeof(Elf_Phdr), sizeof(Elf_Off));
+ CHECK_LE(program_headers.size(), kMaxProgramHeaders);
+
+ // Create the main ELF header.
+ Elf_Ehdr elf_header = MakeElfHeader(isa_);
+ elf_header.e_phoff = kProgramHeadersOffset;
+ elf_header.e_shoff = section_headers_offset;
+ elf_header.e_phnum = program_headers.size();
+ elf_header.e_shnum = section_headers.size();
+ elf_header.e_shstrndx = shstrtab_.GetSectionIndex();
+
+ // Write all headers and section content to the file.
+ // Depending on the implementations of Section::Write, this
+ // might be just memory copies or some more elaborate operations.
+ if (!WriteArray(elf_file, &elf_header, 1)) {
+ LOG(INFO) << "Failed to write the ELF header";
+ return false;
+ }
+ if (!WriteArray(elf_file, program_headers.data(), program_headers.size())) {
+ LOG(INFO) << "Failed to write the program headers";
+ return false;
+ }
+ for (Section* section : sections) {
+ const Elf_Shdr* header = section->GetHeader();
+ if (header->sh_type != SHT_NOBITS) {
+ if (!SeekTo(elf_file, header->sh_offset) || !section->Write(elf_file)) {
+ LOG(INFO) << "Failed to write section " << section->GetName();
+ return false;
+ }
+ Elf_Word current_offset = lseek(elf_file->Fd(), 0, SEEK_CUR);
+ CHECK_EQ(current_offset, header->sh_offset + header->sh_size)
+ << "The number of bytes written does not match GetSize()";
+ }
+ }
+ if (!SeekTo(elf_file, section_headers_offset) ||
+ !WriteArray(elf_file, section_headers.data(), section_headers.size())) {
+ LOG(INFO) << "Failed to write the section headers";
+ return false;
+ }
+ return true;
+ }
+
+ // Adds the given section to the builder. It does not take ownership.
+ void RegisterSection(Section* section) {
+ other_sections_.push_back(section);
+ }
+
+ const Section* FindSection(const char* name) {
+ for (const auto* section : other_sections_) {
+ if (section->GetName() == name) {
+ return section;
+ }
+ }
+ return nullptr;
+ }
+
+ private:
+ static bool SeekTo(File* elf_file, Elf_Word offset) {
+ DCHECK_LE(lseek(elf_file->Fd(), 0, SEEK_CUR), static_cast<off_t>(offset))
+ << "Seeking backwards";
+ if (static_cast<off_t>(offset) != lseek(elf_file->Fd(), offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek in file " << elf_file->GetPath();
+ return false;
+ }
+ return true;
+ }
+
+ template<typename T>
+ static bool WriteArray(File* elf_file, const T* data, size_t count) {
+ if (count != 0) {
+ DCHECK(data != nullptr);
+ if (!elf_file->WriteFully(data, count * sizeof(T))) {
+ PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Helper - create segment header based on memory range.
+ static Elf_Phdr MakeProgramHeader(Elf_Word type, Elf_Word flags,
+ Elf_Off offset, Elf_Word size, Elf_Word align) {
+ Elf_Phdr phdr = Elf_Phdr();
+ phdr.p_type = type;
+ phdr.p_flags = flags;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = offset;
+ phdr.p_paddr = offset;
+ phdr.p_filesz = size;
+ phdr.p_memsz = size;
+ phdr.p_align = align;
+ return phdr;
+ }
+
+ // Helper - create segment header based on section header.
+ static Elf_Phdr MakeProgramHeader(Elf_Word type, Elf_Word flags,
+ const Section& section) {
+ const Elf_Shdr* shdr = section.GetHeader();
+ // Only run-time allocated sections should be in segment headers.
+ CHECK_NE(shdr->sh_flags & SHF_ALLOC, 0u);
+ Elf_Phdr phdr = Elf_Phdr();
+ phdr.p_type = type;
+ phdr.p_flags = flags;
+ phdr.p_offset = shdr->sh_offset;
+ phdr.p_vaddr = shdr->sh_addr;
+ phdr.p_paddr = shdr->sh_addr;
+ phdr.p_filesz = shdr->sh_type != SHT_NOBITS ? shdr->sh_size : 0u;
+ phdr.p_memsz = shdr->sh_size;
+ phdr.p_align = shdr->sh_addralign;
+ return phdr;
+ }
+
+ static Elf_Ehdr MakeElfHeader(InstructionSet isa) {
+ Elf_Ehdr elf_header = Elf_Ehdr();
+ switch (isa) {
+ case kArm:
+ // Fall through.
+ case kThumb2: {
+ elf_header.e_machine = EM_ARM;
+ elf_header.e_flags = EF_ARM_EABI_VER5;
+ break;
+ }
+ case kArm64: {
+ elf_header.e_machine = EM_AARCH64;
+ elf_header.e_flags = 0;
+ break;
+ }
+ case kX86: {
+ elf_header.e_machine = EM_386;
+ elf_header.e_flags = 0;
+ break;
+ }
+ case kX86_64: {
+ elf_header.e_machine = EM_X86_64;
+ elf_header.e_flags = 0;
+ break;
+ }
+ case kMips: {
+ elf_header.e_machine = EM_MIPS;
+ elf_header.e_flags = (EF_MIPS_NOREORDER |
+ EF_MIPS_PIC |
+ EF_MIPS_CPIC |
+ EF_MIPS_ABI_O32 |
+ EF_MIPS_ARCH_32R2);
+ break;
+ }
+ case kMips64: {
+ elf_header.e_machine = EM_MIPS;
+ elf_header.e_flags = (EF_MIPS_NOREORDER |
+ EF_MIPS_PIC |
+ EF_MIPS_CPIC |
+ EF_MIPS_ARCH_64R6);
+ break;
+ }
+ case kNone: {
+ LOG(FATAL) << "No instruction set";
+ }
+ }
+
+ elf_header.e_ident[EI_MAG0] = ELFMAG0;
+ elf_header.e_ident[EI_MAG1] = ELFMAG1;
+ elf_header.e_ident[EI_MAG2] = ELFMAG2;
+ elf_header.e_ident[EI_MAG3] = ELFMAG3;
+ elf_header.e_ident[EI_CLASS] = (sizeof(Elf_Addr) == sizeof(Elf32_Addr))
+ ? ELFCLASS32 : ELFCLASS64;;
+ elf_header.e_ident[EI_DATA] = ELFDATA2LSB;
+ elf_header.e_ident[EI_VERSION] = EV_CURRENT;
+ elf_header.e_ident[EI_OSABI] = ELFOSABI_LINUX;
+ elf_header.e_ident[EI_ABIVERSION] = 0;
+ elf_header.e_type = ET_DYN;
+ elf_header.e_version = 1;
+ elf_header.e_entry = 0;
+ elf_header.e_ehsize = sizeof(Elf_Ehdr);
+ elf_header.e_phentsize = sizeof(Elf_Phdr);
+ elf_header.e_shentsize = sizeof(Elf_Shdr);
+ elf_header.e_phoff = sizeof(Elf_Ehdr);
+ return elf_header;
+ }
+
+ void BuildDynamicSection(const std::string& elf_file_path) {
+ std::string soname(elf_file_path);
+ size_t directory_separator_pos = soname.rfind('/');
+ if (directory_separator_pos != std::string::npos) {
+ soname = soname.substr(directory_separator_pos + 1);
+ }
+ // NB: We must add the name before adding DT_STRSZ.
+ Elf_Word soname_offset = dynstr_.AddName(soname);
+
+ dynamic_.AddDynamicTag(DT_HASH, 0, &hash_);
+ dynamic_.AddDynamicTag(DT_STRTAB, 0, &dynstr_);
+ dynamic_.AddDynamicTag(DT_SYMTAB, 0, &dynsym_);
+ dynamic_.AddDynamicTag(DT_SYMENT, sizeof(Elf_Sym), nullptr);
+ dynamic_.AddDynamicTag(DT_STRSZ, dynstr_.GetSize(), nullptr);
+ dynamic_.AddDynamicTag(DT_SONAME, soname_offset, nullptr);
+ }
+
+ void BuildDynsymSection() {
+ dynsym_.AddSymbol("oatdata", &rodata_, 0, true,
+ rodata_.GetSize(), STB_GLOBAL, STT_OBJECT);
+ dynsym_.AddSymbol("oatexec", &text_, 0, true,
+ text_.GetSize(), STB_GLOBAL, STT_OBJECT);
+ dynsym_.AddSymbol("oatlastword", &text_, text_.GetSize() - 4,
+ true, 4, STB_GLOBAL, STT_OBJECT);
+ if (bss_.GetSize() != 0u) {
+ dynsym_.AddSymbol("oatbss", &bss_, 0, true,
+ bss_.GetSize(), STB_GLOBAL, STT_OBJECT);
+ dynsym_.AddSymbol("oatbsslastword", &bss_, bss_.GetSize() - 4,
+ true, 4, STB_GLOBAL, STT_OBJECT);
+ }
+ }
+
+ InstructionSet isa_;
+ StrtabSection dynstr_;
+ SymtabSection dynsym_;
+ HashSection hash_;
+ OatSection rodata_;
+ OatSection text_;
+ NoBitsSection bss_;
+ DynamicSection dynamic_;
+ StrtabSection strtab_;
+ SymtabSection symtab_;
+ std::vector<Section*> other_sections_;
+ StrtabSection shstrtab_;
+
+ DISALLOW_COPY_AND_ASSIGN(ElfBuilder);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_ELF_BUILDER_H_