C++程序  |  946行  |  33.69 KB

/*
 * 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_