Merge "Change invalid root from LOG(ERROR) to LOG(INTERNAL_FATAL)"
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index 99b8e79..230ebe3 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/dwarf/dwarf_test.h
@@ -57,44 +57,41 @@
// Pretty-print the generated DWARF data using objdump.
template<typename ElfTypes>
- std::vector<std::string> Objdump(bool is64bit, const char* args) {
+ std::vector<std::string> Objdump(const char* args) {
// Write simple elf file with just the DWARF sections.
+ InstructionSet isa = (sizeof(typename ElfTypes::Addr) == 8) ? kX86_64 : kX86;
class NoCode : public CodeOutput {
- virtual void SetCodeOffset(size_t) { }
- virtual bool Write(OutputStream*) { return true; }
- } code;
- ScratchFile file;
- InstructionSet isa = is64bit ? kX86_64 : kX86;
- ElfBuilder<ElfTypes> builder(
- &code, file.GetFile(), isa, 0, 0, 0, 0, 0, 0, false, false);
- typedef ElfRawSectionBuilder<ElfTypes> Section;
- Section debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- Section debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- Section debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- Section debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- Section eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
+ bool Write(OutputStream*) OVERRIDE { return true; } // NOLINT
+ } no_code;
+ ElfBuilder<ElfTypes> builder(isa, 0, &no_code, 0, &no_code, 0);
+ typedef typename ElfBuilder<ElfTypes>::RawSection RawSection;
+ RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0);
if (!debug_info_data_.empty()) {
debug_info.SetBuffer(debug_info_data_);
- builder.RegisterRawSection(&debug_info);
+ builder.RegisterSection(&debug_info);
}
if (!debug_abbrev_data_.empty()) {
debug_abbrev.SetBuffer(debug_abbrev_data_);
- builder.RegisterRawSection(&debug_abbrev);
+ builder.RegisterSection(&debug_abbrev);
}
if (!debug_str_data_.empty()) {
debug_str.SetBuffer(debug_str_data_);
- builder.RegisterRawSection(&debug_str);
+ builder.RegisterSection(&debug_str);
}
if (!debug_line_data_.empty()) {
debug_line.SetBuffer(debug_line_data_);
- builder.RegisterRawSection(&debug_line);
+ builder.RegisterSection(&debug_line);
}
if (!eh_frame_data_.empty()) {
eh_frame.SetBuffer(eh_frame_data_);
- builder.RegisterRawSection(&eh_frame);
+ builder.RegisterSection(&eh_frame);
}
- builder.Init();
- builder.Write();
+ ScratchFile file;
+ builder.Write(file.GetFile());
// Read the elf file back using objdump.
std::vector<std::string> lines;
@@ -123,9 +120,9 @@
std::vector<std::string> Objdump(bool is64bit, const char* args) {
if (is64bit) {
- return Objdump<ElfTypes64>(is64bit, args);
+ return Objdump<ElfTypes64>(args);
} else {
- return Objdump<ElfTypes32>(is64bit, args);
+ return Objdump<ElfTypes32>(args);
}
}
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 32c8cce..07976e8 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -17,535 +17,32 @@
#ifndef ART_COMPILER_ELF_BUILDER_H_
#define ART_COMPILER_ELF_BUILDER_H_
+#include <vector>
+
#include "arch/instruction_set.h"
-#include "base/stl_util.h"
-#include "base/value_object.h"
+#include "base/unix_file/fd_file.h"
#include "buffered_output_stream.h"
#include "elf_utils.h"
#include "file_output_stream.h"
namespace art {
-template <typename ElfTypes>
-class ElfSectionBuilder : public ValueObject {
- public:
- using Elf_Word = typename ElfTypes::Word;
- using Elf_Shdr = typename ElfTypes::Shdr;
-
- ElfSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
- const ElfSectionBuilder<ElfTypes> *link, Elf_Word info,
- Elf_Word align, Elf_Word entsize)
- : section_index_(0), name_(sec_name), link_(link) {
- memset(§ion_, 0, sizeof(section_));
- section_.sh_type = type;
- section_.sh_flags = flags;
- section_.sh_info = info;
- section_.sh_addralign = align;
- section_.sh_entsize = entsize;
- }
- ElfSectionBuilder(const ElfSectionBuilder&) = default;
-
- ~ElfSectionBuilder() {}
-
- Elf_Word GetLink() const {
- return (link_ != nullptr) ? link_->section_index_ : 0;
- }
-
- const Elf_Shdr* GetSection() const {
- return §ion_;
- }
-
- Elf_Shdr* GetSection() {
- return §ion_;
- }
-
- Elf_Word GetSectionIndex() const {
- return section_index_;
- }
-
- void SetSectionIndex(Elf_Word section_index) {
- section_index_ = section_index;
- }
-
- const std::string& GetName() const {
- return name_;
- }
-
- private:
- Elf_Shdr section_;
- Elf_Word section_index_;
- const std::string name_;
- const ElfSectionBuilder* const link_;
-};
-
-template <typename ElfTypes>
-class ElfDynamicBuilder FINAL : public ElfSectionBuilder<ElfTypes> {
- public:
- using Elf_Word = typename ElfTypes::Word;
- using Elf_Sword = typename ElfTypes::Sword;
- using Elf_Shdr = typename ElfTypes::Shdr;
- using Elf_Dyn = typename ElfTypes::Dyn;
-
- void AddDynamicTag(Elf_Sword tag, Elf_Word d_un) {
- if (tag == DT_NULL) {
- return;
- }
- dynamics_.push_back({nullptr, tag, d_un});
- }
-
- void AddDynamicTag(Elf_Sword tag, Elf_Word d_un,
- const ElfSectionBuilder<ElfTypes>* section) {
- if (tag == DT_NULL) {
- return;
- }
- dynamics_.push_back({section, tag, d_un});
- }
-
- ElfDynamicBuilder(const std::string& sec_name,
- ElfSectionBuilder<ElfTypes> *link)
- : ElfSectionBuilder<ElfTypes>(sec_name, SHT_DYNAMIC, SHF_ALLOC | SHF_ALLOC,
- link, 0, kPageSize, sizeof(Elf_Dyn)) {}
- ~ElfDynamicBuilder() {}
-
- Elf_Word GetSize() const {
- // Add 1 for the DT_NULL, 1 for DT_STRSZ, and 1 for DT_SONAME. All of
- // these must be added when we actually put the file together because
- // their values are very dependent on state.
- return dynamics_.size() + 3;
- }
-
- // Create the actual dynamic vector. strsz should be the size of the .dynstr
- // table and soname_off should be the offset of the soname in .dynstr.
- // Since niether can be found prior to final layout we will wait until here
- // to add them.
- std::vector<Elf_Dyn> GetDynamics(Elf_Word strsz, Elf_Word soname) const {
- std::vector<Elf_Dyn> ret;
- for (auto it = dynamics_.cbegin(); it != dynamics_.cend(); ++it) {
- if (it->section_ != nullptr) {
- // We are adding an address relative to a section.
- ret.push_back(
- {it->tag_, {it->off_ + it->section_->GetSection()->sh_addr}});
- } else {
- ret.push_back({it->tag_, {it->off_}});
- }
- }
- ret.push_back({DT_STRSZ, {strsz}});
- ret.push_back({DT_SONAME, {soname}});
- ret.push_back({DT_NULL, {0}});
- return ret;
- }
-
- private:
- struct ElfDynamicState {
- const ElfSectionBuilder<ElfTypes>* section_;
- Elf_Sword tag_;
- Elf_Word off_;
- };
- std::vector<ElfDynamicState> dynamics_;
-};
-
-template <typename ElfTypes>
-class ElfRawSectionBuilder FINAL : public ElfSectionBuilder<ElfTypes> {
- public:
- using Elf_Word = typename ElfTypes::Word;
-
- ElfRawSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
- const ElfSectionBuilder<ElfTypes>* link, Elf_Word info,
- Elf_Word align, Elf_Word entsize)
- : ElfSectionBuilder<ElfTypes>(sec_name, type, flags, link, info, align, entsize) {
- }
- ElfRawSectionBuilder(const ElfRawSectionBuilder&) = default;
-
- ~ElfRawSectionBuilder() {}
-
- std::vector<uint8_t>* GetBuffer() {
- return &buf_;
- }
-
- void SetBuffer(const std::vector<uint8_t>& buf) {
- buf_ = buf;
- }
-
- private:
- std::vector<uint8_t> buf_;
-};
-
-template <typename ElfTypes>
-class ElfOatSectionBuilder FINAL : public ElfSectionBuilder<ElfTypes> {
- public:
- using Elf_Word = typename ElfTypes::Word;
-
- ElfOatSectionBuilder(const std::string& sec_name, Elf_Word size, Elf_Word offset,
- Elf_Word type, Elf_Word flags)
- : ElfSectionBuilder<ElfTypes>(sec_name, type, flags, nullptr, 0, kPageSize, 0),
- offset_(offset), size_(size) {
- }
-
- ~ElfOatSectionBuilder() {}
-
- Elf_Word GetOffset() const {
- return offset_;
- }
-
- Elf_Word GetSize() const {
- return size_;
- }
-
- private:
- // Offset of the content within the file.
- Elf_Word offset_;
- // Size of the content within the file.
- Elf_Word size_;
-};
-
-static inline constexpr uint8_t MakeStInfo(uint8_t binding, uint8_t type) {
- return ((binding) << 4) + ((type) & 0xf);
-}
-
-// 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;
-}
-
-template <typename ElfTypes>
-class ElfSymtabBuilder FINAL : public ElfSectionBuilder<ElfTypes> {
- public:
- using Elf_Addr = typename ElfTypes::Addr;
- using Elf_Word = typename ElfTypes::Word;
- using Elf_Sym = typename ElfTypes::Sym;
-
- // 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 ElfSectionBuilder<ElfTypes>* section,
- Elf_Addr addr,
- bool is_relative,
- Elf_Word size,
- uint8_t binding,
- uint8_t type,
- uint8_t other = 0) {
- CHECK(section);
- ElfSymtabBuilder::ElfSymbolState state {name, section, addr, size, is_relative,
- MakeStInfo(binding, type), other, 0};
- symbols_.push_back(state);
- }
-
- ElfSymtabBuilder(const std::string& sec_name, Elf_Word type,
- const std::string& str_name, Elf_Word str_type, bool alloc)
- : ElfSectionBuilder<ElfTypes>(sec_name, type, ((alloc) ? SHF_ALLOC : 0U),
- &strtab_, 0, sizeof(Elf_Word),
- sizeof(Elf_Sym)), str_name_(str_name),
- str_type_(str_type),
- strtab_(str_name,
- str_type,
- ((alloc) ? SHF_ALLOC : 0U),
- nullptr, 0, 1, 1) {
- }
-
- ~ElfSymtabBuilder() {}
-
- std::vector<Elf_Word> GenerateHashContents() const {
- // 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).
-
- // Select number of buckets.
- // This is essentially arbitrary.
- Elf_Word nbuckets;
- Elf_Word chain_size = GetSize();
- if (symbols_.size() < 8) {
- nbuckets = 2;
- } else if (symbols_.size() < 32) {
- nbuckets = 4;
- } else if (symbols_.size() < 256) {
- nbuckets = 16;
- } else {
- // Have about 32 ids per bucket.
- nbuckets = RoundUp(symbols_.size()/32, 2);
- }
- 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 hash;
- }
-
- std::string GenerateStrtab() {
- std::string tab;
- tab += '\0';
- for (auto it = symbols_.begin(); it != symbols_.end(); ++it) {
- it->name_idx_ = tab.size();
- tab += it->name_;
- tab += '\0';
- }
- strtab_.GetSection()->sh_size = tab.size();
- return tab;
- }
-
- std::vector<Elf_Sym> GenerateSymtab() {
- std::vector<Elf_Sym> ret;
- Elf_Sym undef_sym;
- memset(&undef_sym, 0, sizeof(undef_sym));
- undef_sym.st_shndx = SHN_UNDEF;
- ret.push_back(undef_sym);
-
- for (auto it = symbols_.cbegin(); it != symbols_.cend(); ++it) {
- Elf_Sym sym;
- memset(&sym, 0, sizeof(sym));
- sym.st_name = it->name_idx_;
- if (it->is_relative_) {
- sym.st_value = it->addr_ + it->section_->GetSection()->sh_offset;
- } 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_;
-
- ret.push_back(sym);
- }
- return ret;
- }
-
- Elf_Word GetSize() const {
- // 1 is for the implicit null symbol.
- return symbols_.size() + 1;
- }
-
- ElfSectionBuilder<ElfTypes>* GetStrTab() {
- return &strtab_;
- }
-
- private:
- struct ElfSymbolState {
- const std::string name_;
- const ElfSectionBuilder<ElfTypes>* section_;
- Elf_Addr addr_;
- Elf_Word size_;
- bool is_relative_;
- uint8_t info_;
- uint8_t other_;
- // Used during Write() to temporarially hold name index in the strtab.
- Elf_Word name_idx_;
- };
-
- // Information for the strsym for dynstr sections.
- const std::string str_name_;
- Elf_Word str_type_;
- // The symbols in the same order they will be in the symbol table.
- std::vector<ElfSymbolState> symbols_;
- ElfSectionBuilder<ElfTypes> strtab_;
-};
-
-template <typename Elf_Word>
-class ElfFilePiece {
- public:
- virtual ~ElfFilePiece() {}
-
- virtual bool Write(File* elf_file) {
- if (static_cast<off_t>(offset_) != lseek(elf_file->Fd(), offset_, SEEK_SET)) {
- PLOG(ERROR) << "Failed to seek to " << GetDescription() << " offset " << offset_ << " for "
- << elf_file->GetPath();
- return false;
- }
-
- return DoActualWrite(elf_file);
- }
-
- static bool Compare(ElfFilePiece* a, ElfFilePiece* b) {
- return a->offset_ < b->offset_;
- }
-
- protected:
- explicit ElfFilePiece(Elf_Word offset) : offset_(offset) {}
-
- Elf_Word GetOffset() const {
- return offset_;
- }
-
- virtual const char* GetDescription() const = 0;
- virtual bool DoActualWrite(File* elf_file) = 0;
-
- private:
- const Elf_Word offset_;
-
- DISALLOW_COPY_AND_ASSIGN(ElfFilePiece);
-};
-
-template <typename Elf_Word>
-class ElfFileMemoryPiece FINAL : public ElfFilePiece<Elf_Word> {
- public:
- ElfFileMemoryPiece(const std::string& name, Elf_Word offset, const void* data, Elf_Word size)
- : ElfFilePiece<Elf_Word>(offset), dbg_name_(name), data_(data), size_(size) {}
-
- protected:
- bool DoActualWrite(File* elf_file) OVERRIDE {
- DCHECK(data_ != nullptr || size_ == 0U) << dbg_name_ << " " << size_;
-
- if (!elf_file->WriteFully(data_, size_)) {
- PLOG(ERROR) << "Failed to write " << dbg_name_ << " for " << elf_file->GetPath();
- return false;
- }
-
- return true;
- }
-
- const char* GetDescription() const OVERRIDE {
- return dbg_name_.c_str();
- }
-
- private:
- const std::string& dbg_name_;
- const void *data_;
- Elf_Word size_;
-};
-
class CodeOutput {
public:
- virtual void SetCodeOffset(size_t offset) = 0;
virtual bool Write(OutputStream* out) = 0;
virtual ~CodeOutput() {}
};
-template <typename Elf_Word>
-class ElfFileRodataPiece FINAL : public ElfFilePiece<Elf_Word> {
- public:
- ElfFileRodataPiece(Elf_Word offset, CodeOutput* output) : ElfFilePiece<Elf_Word>(offset),
- output_(output) {}
-
- protected:
- bool DoActualWrite(File* elf_file) OVERRIDE {
- output_->SetCodeOffset(this->GetOffset());
- std::unique_ptr<BufferedOutputStream> output_stream(
- new BufferedOutputStream(new FileOutputStream(elf_file)));
- if (!output_->Write(output_stream.get())) {
- PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file->GetPath();
- return false;
- }
-
- return true;
- }
-
- const char* GetDescription() const OVERRIDE {
- return ".rodata";
- }
-
- private:
- CodeOutput* const output_;
-
- DISALLOW_COPY_AND_ASSIGN(ElfFileRodataPiece);
-};
-
-template <typename Elf_Word>
-class ElfFileOatTextPiece FINAL : public ElfFilePiece<Elf_Word> {
- public:
- ElfFileOatTextPiece(Elf_Word offset, CodeOutput* output) : ElfFilePiece<Elf_Word>(offset),
- output_(output) {}
-
- protected:
- bool DoActualWrite(File* elf_file ATTRIBUTE_UNUSED) OVERRIDE {
- // All data is written by the ElfFileRodataPiece right now, as the oat writer writes in one
- // piece. This is for future flexibility.
- UNUSED(output_);
- return true;
- }
-
- const char* GetDescription() const OVERRIDE {
- return ".text";
- }
-
- private:
- CodeOutput* const output_;
-
- DISALLOW_COPY_AND_ASSIGN(ElfFileOatTextPiece);
-};
-
-template <typename Elf_Word>
-static bool WriteOutFile(const std::vector<ElfFilePiece<Elf_Word>*>& pieces, File* elf_file) {
- // TODO It would be nice if this checked for overlap.
- for (auto it = pieces.begin(); it != pieces.end(); ++it) {
- if (!(*it)->Write(elf_file)) {
- return false;
- }
- }
- return true;
-}
-
-template <typename Elf_Word, typename Elf_Shdr>
-static inline constexpr Elf_Word NextOffset(const Elf_Shdr& cur, const Elf_Shdr& prev) {
- return RoundUp(prev.sh_size + prev.sh_offset, cur.sh_addralign);
-}
-
+// 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;
@@ -554,47 +51,481 @@
using Elf_Phdr = typename ElfTypes::Phdr;
using Elf_Dyn = typename ElfTypes::Dyn;
- ElfBuilder(CodeOutput* oat_writer,
- File* elf_file,
- InstructionSet isa,
- Elf_Word rodata_relative_offset,
- Elf_Word rodata_size,
- Elf_Word text_relative_offset,
- Elf_Word text_size,
- Elf_Word bss_relative_offset,
- Elf_Word bss_size,
- const bool add_symbols,
- bool debug = false)
- : oat_writer_(oat_writer),
- elf_file_(elf_file),
- add_symbols_(add_symbols),
- debug_logging_(debug),
- text_builder_(".text", text_size, text_relative_offset, SHT_PROGBITS,
- SHF_ALLOC | SHF_EXECINSTR),
- rodata_builder_(".rodata", rodata_size, rodata_relative_offset, SHT_PROGBITS, SHF_ALLOC),
- bss_builder_(".bss", bss_size, bss_relative_offset, SHT_NOBITS, SHF_ALLOC),
- dynsym_builder_(".dynsym", SHT_DYNSYM, ".dynstr", SHT_STRTAB, true),
- symtab_builder_(".symtab", SHT_SYMTAB, ".strtab", SHT_STRTAB, false),
- hash_builder_(".hash", SHT_HASH, SHF_ALLOC, &dynsym_builder_, 0, sizeof(Elf_Word),
- sizeof(Elf_Word)),
- dynamic_builder_(".dynamic", &dynsym_builder_),
- shstrtab_builder_(".shstrtab", SHT_STRTAB, 0, nullptr, 0, 1, 1) {
- SetupEhdr();
- SetupDynamic();
- SetupRequiredSymbols();
- SetISA(isa);
+ // 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_;
+ };
+
+ // Section with content based on simple memory buffer.
+ // The buffer can be optionally patched before writing.
+ // The resulting address can be either absolute memory
+ // address or offset relative to the pointer location.
+ 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,
+ const Section* patch_base = nullptr, bool patch_relative = false,
+ bool patch_64bit = (sizeof(Elf_Addr) == sizeof(Elf64_Addr)))
+ : Section(name, type, flags, link, info, align, entsize),
+ patched(false), patch_base_(patch_base),
+ patch_relative_(patch_relative), patch_64bit_(patch_64bit) {
+ }
+
+ Elf_Word GetSize() const OVERRIDE {
+ return buffer_.size();
+ }
+
+ bool Write(File* elf_file) OVERRIDE {
+ if (!patch_locations_.empty()) {
+ DCHECK(patch_base_ != nullptr);
+ DCHECK(!patched); // Do not patch twice.
+ if (patch_relative_) {
+ if (patch_64bit_) {
+ Patch<true, uint64_t>();
+ } else {
+ Patch<true, uint32_t>();
+ }
+ } else {
+ if (patch_64bit_) {
+ Patch<false, uint64_t>();
+ } else {
+ Patch<false, uint32_t>();
+ }
+ }
+ 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:
+ template <bool RelativeAddress = false, typename PatchedAddress = Elf_Addr>
+ void Patch() {
+ Elf_Addr base_addr = patch_base_->GetHeader()->sh_addr;
+ Elf_Addr addr = this->GetHeader()->sh_addr;
+ for (uintptr_t patch_location : patch_locations_) {
+ typedef __attribute__((__aligned__(1))) PatchedAddress UnalignedAddress;
+ auto* to_patch = reinterpret_cast<UnalignedAddress*>(buffer_.data() + patch_location);
+ *to_patch = (base_addr + *to_patch) - (RelativeAddress ? (addr + patch_location) : 0);
+ }
+ }
+
+ std::vector<uint8_t> buffer_;
+ std::vector<uintptr_t> patch_locations_;
+ bool patched;
+ const Section* patch_base_;
+ bool patch_relative_;
+ bool patch_64bit_;
+ };
+
+ // 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, 1) {
+ 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_Word), 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", &dynsym_),
+ strtab_(".strtab", 0),
+ symtab_(".symtab", SHT_SYMTAB, 0, &strtab_),
+ shstrtab_(".shstrtab", 0) {
}
~ElfBuilder() {}
- const ElfOatSectionBuilder<ElfTypes>& GetTextBuilder() const {
- return text_builder_;
- }
+ OatSection* GetText() { return &text_; }
+ SymtabSection* GetSymtab() { return &symtab_; }
- ElfSymtabBuilder<ElfTypes>* GetSymtabBuilder() {
- return &symtab_builder_;
- }
-
- bool Init() {
+ 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
@@ -605,11 +536,12 @@
// | Elf_Ehdr |
// +-------------------------+
// | Elf_Phdr PHDR |
- // | Elf_Phdr LOAD R | .dynsym .dynstr .hash .eh_frame .eh_frame_hdr .rodata
+ // | 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 |
@@ -621,25 +553,10 @@
// | Elf_Sym oatbsslastword | (Optional)
// +-------------------------+
// | .dynstr |
- // | \0 |
- // | oatdata\0 |
- // | oatexec\0 |
- // | oatlastword\0 |
- // | boot.oat\0 |
+ // | names for .dynsym |
// +-------------------------+
// | .hash |
- // | Elf_Word nbucket = b |
- // | Elf_Word nchain = c |
- // | Elf_Word bucket[0] |
- // | ... |
- // | Elf_Word bucket[b - 1] |
- // | Elf_Word chain[0] |
- // | ... |
- // | Elf_Word chain[c - 1] |
- // +-------------------------+
- // | .eh_frame | (Optional)
- // +-------------------------+
- // | .eh_frame_hdr | (Optional)
+ // | hashtable for dynsym |
// +-------------------------+
// | .rodata |
// | oatdata..oatexec-4 |
@@ -648,38 +565,23 @@
// | oatexec..oatlastword |
// +-------------------------+
// | .dynamic |
- // | Elf_Dyn DT_SONAME |
// | Elf_Dyn DT_HASH |
+ // | Elf_Dyn DT_STRTAB |
// | Elf_Dyn DT_SYMTAB |
// | Elf_Dyn DT_SYMENT |
- // | Elf_Dyn DT_STRTAB |
// | Elf_Dyn DT_STRSZ |
+ // | Elf_Dyn DT_SONAME |
// | Elf_Dyn DT_NULL |
// +-------------------------+ (Optional)
- // | .strtab | (Optional)
- // | program symbol names | (Optional)
- // +-------------------------+ (Optional)
// | .symtab | (Optional)
// | program symbols | (Optional)
- // +-------------------------+
- // | .shstrtab |
- // | \0 |
- // | .dynamic\0 |
- // | .dynsym\0 |
- // | .dynstr\0 |
- // | .hash\0 |
- // | .rodata\0 |
- // | .text\0 |
- // | .bss\0 | (Optional)
- // | .shstrtab\0 |
- // | .symtab\0 | (Optional)
- // | .strtab\0 | (Optional)
- // | .eh_frame\0 | (Optional)
- // | .eh_frame_hdr\0 | (Optional)
- // | .debug_info\0 | (Optional)
- // | .debug_abbrev\0 | (Optional)
- // | .debug_str\0 | (Optional)
- // | .debug_line\0 | (Optional)
+ // +-------------------------+ (Optional)
+ // | .strtab | (Optional)
+ // | names for .symtab | (Optional)
+ // +-------------------------+ (Optional)
+ // | .eh_frame | (Optional)
+ // +-------------------------+ (Optional)
+ // | .eh_frame_hdr | (Optional)
// +-------------------------+ (Optional)
// | .debug_info | (Optional)
// +-------------------------+ (Optional)
@@ -688,7 +590,10 @@
// | .debug_str | (Optional)
// +-------------------------+ (Optional)
// | .debug_line | (Optional)
- // +-------------------------+ (Optional)
+ // +-------------------------+
+ // | .shstrtab |
+ // | names of sections |
+ // +-------------------------+
// | Elf_Shdr null |
// | Elf_Shdr .dynsym |
// | Elf_Shdr .dynstr |
@@ -697,552 +602,266 @@
// | Elf_Shdr .text |
// | Elf_Shdr .bss | (Optional)
// | Elf_Shdr .dynamic |
- // | Elf_Shdr .shstrtab |
+ // | 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;
- if (fatal_error_) {
- return 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_);
}
- // Step 1. Figure out all the offsets.
-
- if (debug_logging_) {
- LOG(INFO) << "phdr_offset=" << PHDR_OFFSET << std::hex << " " << PHDR_OFFSET;
- LOG(INFO) << "phdr_size=" << PHDR_SIZE << std::hex << " " << PHDR_SIZE;
+ 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;
}
- memset(&program_headers_, 0, sizeof(program_headers_));
- program_headers_[PH_PHDR].p_type = PT_PHDR;
- program_headers_[PH_PHDR].p_offset = PHDR_OFFSET;
- program_headers_[PH_PHDR].p_vaddr = PHDR_OFFSET;
- program_headers_[PH_PHDR].p_paddr = PHDR_OFFSET;
- program_headers_[PH_PHDR].p_filesz = sizeof(program_headers_);
- program_headers_[PH_PHDR].p_memsz = sizeof(program_headers_);
- program_headers_[PH_PHDR].p_flags = PF_R;
- program_headers_[PH_PHDR].p_align = sizeof(Elf_Word);
+ // 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());
- program_headers_[PH_LOAD_R__].p_type = PT_LOAD;
- program_headers_[PH_LOAD_R__].p_offset = 0;
- program_headers_[PH_LOAD_R__].p_vaddr = 0;
- program_headers_[PH_LOAD_R__].p_paddr = 0;
- program_headers_[PH_LOAD_R__].p_flags = PF_R;
+ // 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);
+ constexpr size_t kProgramHeadersSize = sizeof(Elf_Phdr) * kMaxProgramHeaders;
- program_headers_[PH_LOAD_R_X].p_type = PT_LOAD;
- program_headers_[PH_LOAD_R_X].p_flags = PF_R | PF_X;
-
- program_headers_[PH_LOAD_RW_BSS].p_type = PT_LOAD;
- program_headers_[PH_LOAD_RW_BSS].p_flags = PF_R | PF_W;
-
- program_headers_[PH_LOAD_RW_DYNAMIC].p_type = PT_LOAD;
- program_headers_[PH_LOAD_RW_DYNAMIC].p_flags = PF_R | PF_W;
-
- program_headers_[PH_DYNAMIC].p_type = PT_DYNAMIC;
- program_headers_[PH_DYNAMIC].p_flags = PF_R | PF_W;
-
- program_headers_[PH_EH_FRAME_HDR].p_type = PT_NULL;
- program_headers_[PH_EH_FRAME_HDR].p_flags = PF_R;
-
- // Get the dynstr string.
- dynstr_ = dynsym_builder_.GenerateStrtab();
-
- // Add the SONAME to the dynstr.
- dynstr_soname_offset_ = dynstr_.size();
- std::string file_name(elf_file_->GetPath());
- size_t directory_separator_pos = file_name.rfind('/');
- if (directory_separator_pos != std::string::npos) {
- file_name = file_name.substr(directory_separator_pos + 1);
- }
- dynstr_ += file_name;
- dynstr_ += '\0';
- if (debug_logging_) {
- LOG(INFO) << "dynstr size (bytes) =" << dynstr_.size()
- << std::hex << " " << dynstr_.size();
- LOG(INFO) << "dynsym size (elements)=" << dynsym_builder_.GetSize()
- << std::hex << " " << dynsym_builder_.GetSize();
- }
-
- // Get the section header string table.
- shstrtab_ += '\0';
-
- // Setup sym_undef
- memset(&null_hdr_, 0, sizeof(null_hdr_));
- null_hdr_.sh_type = SHT_NULL;
- null_hdr_.sh_link = SHN_UNDEF;
- section_ptrs_.push_back(&null_hdr_);
-
- section_index_ = 1;
-
- // setup .dynsym
- section_ptrs_.push_back(dynsym_builder_.GetSection());
- AssignSectionStr(&dynsym_builder_, &shstrtab_);
- dynsym_builder_.SetSectionIndex(section_index_);
- section_index_++;
-
- // Setup .dynstr
- section_ptrs_.push_back(dynsym_builder_.GetStrTab()->GetSection());
- AssignSectionStr(dynsym_builder_.GetStrTab(), &shstrtab_);
- dynsym_builder_.GetStrTab()->SetSectionIndex(section_index_);
- section_index_++;
-
- // Setup .hash
- section_ptrs_.push_back(hash_builder_.GetSection());
- AssignSectionStr(&hash_builder_, &shstrtab_);
- hash_builder_.SetSectionIndex(section_index_);
- section_index_++;
-
- // Setup .rodata
- section_ptrs_.push_back(rodata_builder_.GetSection());
- AssignSectionStr(&rodata_builder_, &shstrtab_);
- rodata_builder_.SetSectionIndex(section_index_);
- section_index_++;
-
- // Setup .text
- section_ptrs_.push_back(text_builder_.GetSection());
- AssignSectionStr(&text_builder_, &shstrtab_);
- text_builder_.SetSectionIndex(section_index_);
- section_index_++;
-
- // Setup .bss
- if (bss_builder_.GetSize() != 0u) {
- section_ptrs_.push_back(bss_builder_.GetSection());
- AssignSectionStr(&bss_builder_, &shstrtab_);
- bss_builder_.SetSectionIndex(section_index_);
- section_index_++;
- }
-
- // Setup .dynamic
- section_ptrs_.push_back(dynamic_builder_.GetSection());
- AssignSectionStr(&dynamic_builder_, &shstrtab_);
- dynamic_builder_.SetSectionIndex(section_index_);
- section_index_++;
-
- // Fill in the hash section.
- hash_ = dynsym_builder_.GenerateHashContents();
-
- if (debug_logging_) {
- LOG(INFO) << ".hash size (bytes)=" << hash_.size() * sizeof(Elf_Word)
- << std::hex << " " << hash_.size() * sizeof(Elf_Word);
- }
-
- Elf_Word base_offset = sizeof(Elf_Ehdr) + sizeof(program_headers_);
-
- // Get the layout in the sections.
- //
- // Get the layout of the dynsym section.
- dynsym_builder_.GetSection()->sh_offset =
- RoundUp(base_offset, dynsym_builder_.GetSection()->sh_addralign);
- dynsym_builder_.GetSection()->sh_addr = dynsym_builder_.GetSection()->sh_offset;
- dynsym_builder_.GetSection()->sh_size = dynsym_builder_.GetSize() * sizeof(Elf_Sym);
- dynsym_builder_.GetSection()->sh_link = dynsym_builder_.GetLink();
-
- // Get the layout of the dynstr section.
- dynsym_builder_.GetStrTab()->GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*dynsym_builder_.GetStrTab()->GetSection(),
- *dynsym_builder_.GetSection());
- dynsym_builder_.GetStrTab()->GetSection()->sh_addr =
- dynsym_builder_.GetStrTab()->GetSection()->sh_offset;
- dynsym_builder_.GetStrTab()->GetSection()->sh_size = dynstr_.size();
- dynsym_builder_.GetStrTab()->GetSection()->sh_link = dynsym_builder_.GetStrTab()->GetLink();
-
- // Get the layout of the hash section
- hash_builder_.GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*hash_builder_.GetSection(),
- *dynsym_builder_.GetStrTab()->GetSection());
- hash_builder_.GetSection()->sh_addr = hash_builder_.GetSection()->sh_offset;
- hash_builder_.GetSection()->sh_size = hash_.size() * sizeof(Elf_Word);
- hash_builder_.GetSection()->sh_link = hash_builder_.GetLink();
-
- // Get the layout of the extra sections with SHF_ALLOC flag.
- // This will deal with .eh_frame and .eh_frame_hdr.
- // .eh_frame contains relative pointers to .text which we
- // want to fixup between the calls to Init() and Write().
- // Therefore we handle those sections here as opposed to Write().
- // It also has the nice side effect of including .eh_frame
- // with the rest of LOAD_R segment. It must come before .rodata
- // because .rodata and .text must be next to each other.
- Elf_Shdr* prev = hash_builder_.GetSection();
- for (auto* it : other_builders_) {
- if ((it->GetSection()->sh_flags & SHF_ALLOC) != 0) {
- it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
- it->GetSection()->sh_addr = it->GetSection()->sh_offset;
- it->GetSection()->sh_size = it->GetBuffer()->size();
- it->GetSection()->sh_link = it->GetLink();
- prev = it->GetSection();
+ // 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 + kProgramHeadersSize;
+ 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);
}
- // If the sections exist, check that they have been handled.
- const auto* eh_frame = FindRawSection(".eh_frame");
+ Elf_Off section_headers_offset = RoundUp(file_offset, sizeof(Elf_Word));
+
+ // 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(MakeProgramHeader(PT_PHDR, PF_R,
+ kProgramHeadersOffset, kProgramHeadersSize, sizeof(Elf_Word)));
+ // 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) {
- DCHECK_NE(eh_frame->GetSection()->sh_offset, 0u);
- }
- const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr");
- if (eh_frame_hdr != nullptr) {
- DCHECK_NE(eh_frame_hdr->GetSection()->sh_offset, 0u);
- }
-
- // Get the layout of the rodata section.
- rodata_builder_.GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*rodata_builder_.GetSection(), *prev);
- rodata_builder_.GetSection()->sh_addr = rodata_builder_.GetSection()->sh_offset;
- rodata_builder_.GetSection()->sh_size = rodata_builder_.GetSize();
- rodata_builder_.GetSection()->sh_link = rodata_builder_.GetLink();
-
- // Get the layout of the text section.
- text_builder_.GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*text_builder_.GetSection(),
- *rodata_builder_.GetSection());
- text_builder_.GetSection()->sh_addr = text_builder_.GetSection()->sh_offset;
- text_builder_.GetSection()->sh_size = text_builder_.GetSize();
- text_builder_.GetSection()->sh_link = text_builder_.GetLink();
- CHECK_ALIGNED(rodata_builder_.GetSection()->sh_offset +
- rodata_builder_.GetSection()->sh_size, kPageSize);
-
- // Get the layout of the .bss section.
- bss_builder_.GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*bss_builder_.GetSection(),
- *text_builder_.GetSection());
- bss_builder_.GetSection()->sh_addr = bss_builder_.GetSection()->sh_offset;
- bss_builder_.GetSection()->sh_size = bss_builder_.GetSize();
- bss_builder_.GetSection()->sh_link = bss_builder_.GetLink();
-
- // Get the layout of the dynamic section.
- CHECK(IsAlignedParam(bss_builder_.GetSection()->sh_offset,
- dynamic_builder_.GetSection()->sh_addralign));
- dynamic_builder_.GetSection()->sh_offset = bss_builder_.GetSection()->sh_offset;
- dynamic_builder_.GetSection()->sh_addr =
- NextOffset<Elf_Word, Elf_Shdr>(*dynamic_builder_.GetSection(), *bss_builder_.GetSection());
- dynamic_builder_.GetSection()->sh_size = dynamic_builder_.GetSize() * sizeof(Elf_Dyn);
- dynamic_builder_.GetSection()->sh_link = dynamic_builder_.GetLink();
-
- if (debug_logging_) {
- LOG(INFO) << "dynsym off=" << dynsym_builder_.GetSection()->sh_offset
- << " dynsym size=" << dynsym_builder_.GetSection()->sh_size;
- LOG(INFO) << "dynstr off=" << dynsym_builder_.GetStrTab()->GetSection()->sh_offset
- << " dynstr size=" << dynsym_builder_.GetStrTab()->GetSection()->sh_size;
- LOG(INFO) << "hash off=" << hash_builder_.GetSection()->sh_offset
- << " hash size=" << hash_builder_.GetSection()->sh_size;
- LOG(INFO) << "rodata off=" << rodata_builder_.GetSection()->sh_offset
- << " rodata size=" << rodata_builder_.GetSection()->sh_size;
- LOG(INFO) << "text off=" << text_builder_.GetSection()->sh_offset
- << " text size=" << text_builder_.GetSection()->sh_size;
- LOG(INFO) << "dynamic off=" << dynamic_builder_.GetSection()->sh_offset
- << " dynamic size=" << dynamic_builder_.GetSection()->sh_size;
- }
-
- return true;
- }
-
- bool Write() {
- std::vector<ElfFilePiece<Elf_Word>*> pieces;
- Elf_Shdr* prev = dynamic_builder_.GetSection();
- std::string strtab;
-
- if (IncludingDebugSymbols()) {
- // Setup .symtab
- section_ptrs_.push_back(symtab_builder_.GetSection());
- AssignSectionStr(&symtab_builder_, &shstrtab_);
- symtab_builder_.SetSectionIndex(section_index_);
- section_index_++;
-
- // Setup .strtab
- section_ptrs_.push_back(symtab_builder_.GetStrTab()->GetSection());
- AssignSectionStr(symtab_builder_.GetStrTab(), &shstrtab_);
- symtab_builder_.GetStrTab()->SetSectionIndex(section_index_);
- section_index_++;
-
- strtab = symtab_builder_.GenerateStrtab();
- if (debug_logging_) {
- LOG(INFO) << "strtab size (bytes) =" << strtab.size()
- << std::hex << " " << strtab.size();
- LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
- << std::hex << " " << symtab_builder_.GetSize();
+ 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));
}
}
+ CHECK_LE(program_headers.size(), kMaxProgramHeaders);
- // Setup all the other sections.
- for (auto* builder : other_builders_) {
- section_ptrs_.push_back(builder->GetSection());
- AssignSectionStr(builder, &shstrtab_);
- builder->SetSectionIndex(section_index_);
- section_index_++;
- }
+ // 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();
- // Setup shstrtab
- section_ptrs_.push_back(shstrtab_builder_.GetSection());
- AssignSectionStr(&shstrtab_builder_, &shstrtab_);
- shstrtab_builder_.SetSectionIndex(section_index_);
- section_index_++;
-
- if (debug_logging_) {
- LOG(INFO) << ".shstrtab size (bytes) =" << shstrtab_.size()
- << std::hex << " " << shstrtab_.size();
- LOG(INFO) << "section list size (elements)=" << section_ptrs_.size()
- << std::hex << " " << section_ptrs_.size();
- }
-
- if (IncludingDebugSymbols()) {
- // Get the layout of the symtab section.
- symtab_builder_.GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*symtab_builder_.GetSection(),
- *dynamic_builder_.GetSection());
- symtab_builder_.GetSection()->sh_addr = 0;
- // Add to leave space for the null symbol.
- symtab_builder_.GetSection()->sh_size = symtab_builder_.GetSize() * sizeof(Elf_Sym);
- symtab_builder_.GetSection()->sh_link = symtab_builder_.GetLink();
-
- // Get the layout of the dynstr section.
- symtab_builder_.GetStrTab()->GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*symtab_builder_.GetStrTab()->GetSection(),
- *symtab_builder_.GetSection());
- symtab_builder_.GetStrTab()->GetSection()->sh_addr = 0;
- symtab_builder_.GetStrTab()->GetSection()->sh_size = strtab.size();
- symtab_builder_.GetStrTab()->GetSection()->sh_link = symtab_builder_.GetStrTab()->GetLink();
-
- prev = symtab_builder_.GetStrTab()->GetSection();
- if (debug_logging_) {
- LOG(INFO) << "symtab off=" << symtab_builder_.GetSection()->sh_offset
- << " symtab size=" << symtab_builder_.GetSection()->sh_size;
- LOG(INFO) << "strtab off=" << symtab_builder_.GetStrTab()->GetSection()->sh_offset
- << " strtab size=" << symtab_builder_.GetStrTab()->GetSection()->sh_size;
- }
- }
-
- // Get the layout of the extra sections without SHF_ALLOC flag.
- // (This will deal with the debug sections if they are there)
- for (auto* it : other_builders_) {
- if ((it->GetSection()->sh_flags & SHF_ALLOC) == 0) {
- it->GetSection()->sh_offset = NextOffset<Elf_Word, Elf_Shdr>(*it->GetSection(), *prev);
- it->GetSection()->sh_addr = 0;
- it->GetSection()->sh_size = it->GetBuffer()->size();
- it->GetSection()->sh_link = it->GetLink();
-
- // We postpone adding an ElfFilePiece to keep the order in "pieces."
-
- prev = it->GetSection();
- if (debug_logging_) {
- LOG(INFO) << it->GetName() << " off=" << it->GetSection()->sh_offset
- << " size=" << it->GetSection()->sh_size;
- }
- }
- }
-
- // Get the layout of the shstrtab section
- shstrtab_builder_.GetSection()->sh_offset =
- NextOffset<Elf_Word, Elf_Shdr>(*shstrtab_builder_.GetSection(), *prev);
- shstrtab_builder_.GetSection()->sh_addr = 0;
- shstrtab_builder_.GetSection()->sh_size = shstrtab_.size();
- shstrtab_builder_.GetSection()->sh_link = shstrtab_builder_.GetLink();
- if (debug_logging_) {
- LOG(INFO) << "shstrtab off=" << shstrtab_builder_.GetSection()->sh_offset
- << " shstrtab size=" << shstrtab_builder_.GetSection()->sh_size;
- }
-
- // The section list comes after come after.
- Elf_Word sections_offset = RoundUp(
- shstrtab_builder_.GetSection()->sh_offset + shstrtab_builder_.GetSection()->sh_size,
- sizeof(Elf_Word));
-
- // Setup the actual symbol arrays.
- std::vector<Elf_Sym> dynsym = dynsym_builder_.GenerateSymtab();
- CHECK_EQ(dynsym.size() * sizeof(Elf_Sym), dynsym_builder_.GetSection()->sh_size);
- std::vector<Elf_Sym> symtab;
- if (IncludingDebugSymbols()) {
- symtab = symtab_builder_.GenerateSymtab();
- CHECK_EQ(symtab.size() * sizeof(Elf_Sym), symtab_builder_.GetSection()->sh_size);
- }
-
- // Setup the dynamic section.
- // This will add the 2 values we cannot know until now time, namely the size
- // and the soname_offset.
- std::vector<Elf_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr_.size(),
- dynstr_soname_offset_);
- CHECK_EQ(dynamic.size() * sizeof(Elf_Dyn), dynamic_builder_.GetSection()->sh_size);
-
- // Finish setup of the program headers now that we know the layout of the
- // whole file.
- Elf_Word load_r_size =
- rodata_builder_.GetSection()->sh_offset + rodata_builder_.GetSection()->sh_size;
- program_headers_[PH_LOAD_R__].p_filesz = load_r_size;
- program_headers_[PH_LOAD_R__].p_memsz = load_r_size;
- program_headers_[PH_LOAD_R__].p_align = rodata_builder_.GetSection()->sh_addralign;
-
- Elf_Word load_rx_size = text_builder_.GetSection()->sh_size;
- program_headers_[PH_LOAD_R_X].p_offset = text_builder_.GetSection()->sh_offset;
- program_headers_[PH_LOAD_R_X].p_vaddr = text_builder_.GetSection()->sh_offset;
- program_headers_[PH_LOAD_R_X].p_paddr = text_builder_.GetSection()->sh_offset;
- program_headers_[PH_LOAD_R_X].p_filesz = load_rx_size;
- program_headers_[PH_LOAD_R_X].p_memsz = load_rx_size;
- program_headers_[PH_LOAD_R_X].p_align = text_builder_.GetSection()->sh_addralign;
-
- program_headers_[PH_LOAD_RW_BSS].p_offset = bss_builder_.GetSection()->sh_offset;
- program_headers_[PH_LOAD_RW_BSS].p_vaddr = bss_builder_.GetSection()->sh_offset;
- program_headers_[PH_LOAD_RW_BSS].p_paddr = bss_builder_.GetSection()->sh_offset;
- program_headers_[PH_LOAD_RW_BSS].p_filesz = 0;
- program_headers_[PH_LOAD_RW_BSS].p_memsz = bss_builder_.GetSection()->sh_size;
- program_headers_[PH_LOAD_RW_BSS].p_align = bss_builder_.GetSection()->sh_addralign;
-
- program_headers_[PH_LOAD_RW_DYNAMIC].p_offset = dynamic_builder_.GetSection()->sh_offset;
- program_headers_[PH_LOAD_RW_DYNAMIC].p_vaddr = dynamic_builder_.GetSection()->sh_addr;
- program_headers_[PH_LOAD_RW_DYNAMIC].p_paddr = dynamic_builder_.GetSection()->sh_addr;
- program_headers_[PH_LOAD_RW_DYNAMIC].p_filesz = dynamic_builder_.GetSection()->sh_size;
- program_headers_[PH_LOAD_RW_DYNAMIC].p_memsz = dynamic_builder_.GetSection()->sh_size;
- program_headers_[PH_LOAD_RW_DYNAMIC].p_align = dynamic_builder_.GetSection()->sh_addralign;
-
- program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.GetSection()->sh_offset;
- program_headers_[PH_DYNAMIC].p_vaddr = dynamic_builder_.GetSection()->sh_addr;
- program_headers_[PH_DYNAMIC].p_paddr = dynamic_builder_.GetSection()->sh_addr;
- program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.GetSection()->sh_size;
- program_headers_[PH_DYNAMIC].p_memsz = dynamic_builder_.GetSection()->sh_size;
- program_headers_[PH_DYNAMIC].p_align = dynamic_builder_.GetSection()->sh_addralign;
-
- const auto* eh_frame_hdr = FindRawSection(".eh_frame_hdr");
- if (eh_frame_hdr != nullptr) {
- const auto* eh_frame = FindRawSection(".eh_frame");
- // Check layout:
- // 1) eh_frame is before eh_frame_hdr.
- // 2) There's no gap.
- CHECK(eh_frame != nullptr);
- CHECK_LE(eh_frame->GetSection()->sh_offset, eh_frame_hdr->GetSection()->sh_offset);
- CHECK_EQ(eh_frame->GetSection()->sh_offset + eh_frame->GetSection()->sh_size,
- eh_frame_hdr->GetSection()->sh_offset);
-
- program_headers_[PH_EH_FRAME_HDR].p_type = PT_GNU_EH_FRAME;
- program_headers_[PH_EH_FRAME_HDR].p_offset = eh_frame_hdr->GetSection()->sh_offset;
- program_headers_[PH_EH_FRAME_HDR].p_vaddr = eh_frame_hdr->GetSection()->sh_addr;
- program_headers_[PH_EH_FRAME_HDR].p_paddr = eh_frame_hdr->GetSection()->sh_addr;
- program_headers_[PH_EH_FRAME_HDR].p_filesz = eh_frame_hdr->GetSection()->sh_size;
- program_headers_[PH_EH_FRAME_HDR].p_memsz = eh_frame_hdr->GetSection()->sh_size;
- program_headers_[PH_EH_FRAME_HDR].p_align = eh_frame_hdr->GetSection()->sh_addralign;
- }
-
- // Finish setup of the Ehdr values.
- elf_header_.e_phoff = PHDR_OFFSET;
- elf_header_.e_shoff = sections_offset;
- elf_header_.e_phnum = (bss_builder_.GetSection()->sh_size != 0u) ? PH_NUM : PH_NUM - 1;
- elf_header_.e_shnum = section_ptrs_.size();
- elf_header_.e_shstrndx = shstrtab_builder_.GetSectionIndex();
-
- // Add the rest of the pieces to the list.
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Elf Header", 0, &elf_header_,
- sizeof(elf_header_)));
- if (bss_builder_.GetSection()->sh_size != 0u) {
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers", PHDR_OFFSET,
- &program_headers_[0],
- elf_header_.e_phnum * sizeof(Elf_Phdr)));
- } else {
- // Skip PH_LOAD_RW_BSS.
- Elf_Word part1_size = PH_LOAD_RW_BSS * sizeof(Elf_Phdr);
- Elf_Word part2_size = (PH_NUM - PH_LOAD_RW_BSS - 1) * sizeof(Elf_Phdr);
- CHECK_EQ(part1_size + part2_size, elf_header_.e_phnum * sizeof(Elf_Phdr));
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers", PHDR_OFFSET,
- &program_headers_[0], part1_size));
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("Program headers part 2",
- PHDR_OFFSET + part1_size,
- &program_headers_[PH_LOAD_RW_BSS + 1],
- part2_size));
- }
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynamic",
- dynamic_builder_.GetSection()->sh_offset,
- dynamic.data(),
- dynamic_builder_.GetSection()->sh_size));
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynsym", dynsym_builder_.GetSection()->sh_offset,
- dynsym.data(),
- dynsym.size() * sizeof(Elf_Sym)));
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".dynstr",
- dynsym_builder_.GetStrTab()->GetSection()->sh_offset,
- dynstr_.c_str(), dynstr_.size()));
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".hash", hash_builder_.GetSection()->sh_offset,
- hash_.data(),
- hash_.size() * sizeof(Elf_Word)));
- pieces.push_back(new ElfFileRodataPiece<Elf_Word>(rodata_builder_.GetSection()->sh_offset,
- oat_writer_));
- pieces.push_back(new ElfFileOatTextPiece<Elf_Word>(text_builder_.GetSection()->sh_offset,
- oat_writer_));
- if (IncludingDebugSymbols()) {
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".symtab",
- symtab_builder_.GetSection()->sh_offset,
- symtab.data(),
- symtab.size() * sizeof(Elf_Sym)));
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".strtab",
- symtab_builder_.GetStrTab()->GetSection()->sh_offset,
- strtab.c_str(), strtab.size()));
- }
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(".shstrtab",
- shstrtab_builder_.GetSection()->sh_offset,
- &shstrtab_[0], shstrtab_.size()));
- for (uint32_t i = 0; i < section_ptrs_.size(); ++i) {
- // Just add all the sections in induvidually since they are all over the
- // place on the heap/stack.
- Elf_Word cur_off = sections_offset + i * sizeof(Elf_Shdr);
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>("section table piece", cur_off,
- section_ptrs_[i], sizeof(Elf_Shdr)));
- }
-
- // Postponed debug info.
- for (auto* it : other_builders_) {
- pieces.push_back(new ElfFileMemoryPiece<Elf_Word>(it->GetName(), it->GetSection()->sh_offset,
- it->GetBuffer()->data(),
- it->GetBuffer()->size()));
- }
-
- if (!WriteOutFile(pieces)) {
- LOG(ERROR) << "Unable to write to file " << elf_file_->GetPath();
-
- STLDeleteElements(&pieces); // Have to manually clean pieces.
+ // 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;
}
-
- STLDeleteElements(&pieces); // Have to manually clean pieces.
+ 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 raw section to the builder. It does not take ownership.
- void RegisterRawSection(ElfRawSectionBuilder<ElfTypes>* bld) {
- other_builders_.push_back(bld);
+ // Adds the given section to the builder. It does not take ownership.
+ void RegisterSection(Section* section) {
+ other_sections_.push_back(section);
}
- const ElfRawSectionBuilder<ElfTypes>* FindRawSection(const char* name) {
- for (const auto* other_builder : other_builders_) {
- if (other_builder->GetName() == name) {
- return other_builder;
+ const Section* FindSection(const char* name) {
+ for (const auto* section : other_sections_) {
+ if (section->GetName() == name) {
+ return section;
}
}
return nullptr;
}
private:
- void SetISA(InstructionSet isa) {
+ 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) {
+ 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;
+ 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;
+ 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;
+ 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;
+ 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 |
+ elf_header.e_machine = EM_MIPS;
+ elf_header.e_flags = (EF_MIPS_NOREORDER |
EF_MIPS_PIC |
EF_MIPS_CPIC |
EF_MIPS_ABI_O32 |
@@ -1250,147 +869,82 @@
break;
}
case kMips64: {
- elf_header_.e_machine = EM_MIPS;
- elf_header_.e_flags = (EF_MIPS_NOREORDER |
+ elf_header.e_machine = EM_MIPS;
+ elf_header.e_flags = (EF_MIPS_NOREORDER |
EF_MIPS_PIC |
EF_MIPS_CPIC |
EF_MIPS_ARCH_64R6);
break;
}
- default: {
- fatal_error_ = true;
- LOG(FATAL) << "Unknown instruction set: " << isa;
- break;
+ case kNone: {
+ LOG(FATAL) << "No instruction set";
}
}
- }
- void SetupEhdr() {
- memset(&elf_header_, 0, sizeof(elf_header_));
- 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))
+ 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);
+ 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;
}
- // Sets up a bunch of the required Dynamic Section entries.
- // Namely it will initialize all the mandatory ones that it can.
- // Specifically:
- // DT_HASH
- // DT_STRTAB
- // DT_SYMTAB
- // DT_SYMENT
- //
- // Some such as DT_SONAME, DT_STRSZ and DT_NULL will be put in later.
- void SetupDynamic() {
- dynamic_builder_.AddDynamicTag(DT_HASH, 0, &hash_builder_);
- dynamic_builder_.AddDynamicTag(DT_STRTAB, 0, dynsym_builder_.GetStrTab());
- dynamic_builder_.AddDynamicTag(DT_SYMTAB, 0, &dynsym_builder_);
- dynamic_builder_.AddDynamicTag(DT_SYMENT, sizeof(Elf_Sym));
+ 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);
}
- // Sets up the basic dynamic symbols that are needed, namely all those we
- // can know already.
- //
- // Specifically adds:
- // oatdata
- // oatexec
- // oatlastword
- void SetupRequiredSymbols() {
- dynsym_builder_.AddSymbol("oatdata", &rodata_builder_, 0, true,
- rodata_builder_.GetSize(), STB_GLOBAL, STT_OBJECT);
- dynsym_builder_.AddSymbol("oatexec", &text_builder_, 0, true,
- text_builder_.GetSize(), STB_GLOBAL, STT_OBJECT);
- dynsym_builder_.AddSymbol("oatlastword", &text_builder_, text_builder_.GetSize() - 4,
- true, 4, STB_GLOBAL, STT_OBJECT);
- if (bss_builder_.GetSize() != 0u) {
- dynsym_builder_.AddSymbol("oatbss", &bss_builder_, 0, true,
- bss_builder_.GetSize(), STB_GLOBAL, STT_OBJECT);
- dynsym_builder_.AddSymbol("oatbsslastword", &bss_builder_, bss_builder_.GetSize() - 4,
- true, 4, STB_GLOBAL, STT_OBJECT);
+ 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);
}
}
- void AssignSectionStr(ElfSectionBuilder<ElfTypes>* builder, std::string* strtab) {
- builder->GetSection()->sh_name = strtab->size();
- *strtab += builder->GetName();
- *strtab += '\0';
- if (debug_logging_) {
- LOG(INFO) << "adding section name \"" << builder->GetName() << "\" "
- << "to shstrtab at offset " << builder->GetSection()->sh_name;
- }
- }
-
-
- // Write each of the pieces out to the file.
- bool WriteOutFile(const std::vector<ElfFilePiece<Elf_Word>*>& pieces) {
- for (auto it = pieces.begin(); it != pieces.end(); ++it) {
- if (!(*it)->Write(elf_file_)) {
- return false;
- }
- }
- return true;
- }
-
- bool IncludingDebugSymbols() const {
- return add_symbols_ && symtab_builder_.GetSize() > 1;
- }
-
- CodeOutput* const oat_writer_;
- File* const elf_file_;
- const bool add_symbols_;
- const bool debug_logging_;
-
- bool fatal_error_ = false;
-
- // What phdr is.
- static const uint32_t PHDR_OFFSET = sizeof(Elf_Ehdr);
- enum : uint8_t {
- PH_PHDR = 0,
- PH_LOAD_R__ = 1,
- PH_LOAD_R_X = 2,
- PH_LOAD_RW_BSS = 3,
- PH_LOAD_RW_DYNAMIC = 4,
- PH_DYNAMIC = 5,
- PH_EH_FRAME_HDR = 6,
- PH_NUM = 7,
- };
- static const uint32_t PHDR_SIZE = sizeof(Elf_Phdr) * PH_NUM;
- Elf_Phdr program_headers_[PH_NUM];
-
- Elf_Ehdr elf_header_;
-
- Elf_Shdr null_hdr_;
- std::string shstrtab_;
- // The index of the current section being built. The first being 1.
- uint32_t section_index_;
- std::string dynstr_;
- uint32_t dynstr_soname_offset_;
- std::vector<const Elf_Shdr*> section_ptrs_;
- std::vector<Elf_Word> hash_;
-
- ElfOatSectionBuilder<ElfTypes> text_builder_;
- ElfOatSectionBuilder<ElfTypes> rodata_builder_;
- ElfOatSectionBuilder<ElfTypes> bss_builder_;
- ElfSymtabBuilder<ElfTypes> dynsym_builder_;
- ElfSymtabBuilder<ElfTypes> symtab_builder_;
- ElfSectionBuilder<ElfTypes> hash_builder_;
- ElfDynamicBuilder<ElfTypes> dynamic_builder_;
- ElfSectionBuilder<ElfTypes> shstrtab_builder_;
- std::vector<ElfRawSectionBuilder<ElfTypes>*> other_builders_;
+ 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);
};
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 3b2ca94..178aa03 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -21,7 +21,6 @@
#include "base/logging.h"
#include "base/unix_file/fd_file.h"
-#include "buffered_output_stream.h"
#include "compiled_method.h"
#include "dex_file-inl.h"
#include "driver/compiler_driver.h"
@@ -30,7 +29,6 @@
#include "elf_file.h"
#include "elf_utils.h"
#include "elf_writer_debug.h"
-#include "file_output_stream.h"
#include "globals.h"
#include "leb128.h"
#include "oat.h"
@@ -50,20 +48,6 @@
return elf_writer.Write(oat_writer, dex_files, android_root, is_host);
}
-class OatWriterWrapper FINAL : public CodeOutput {
- public:
- explicit OatWriterWrapper(OatWriter* oat_writer) : oat_writer_(oat_writer) {}
-
- void SetCodeOffset(size_t offset) {
- oat_writer_->SetOatDataOffset(offset);
- }
- bool Write(OutputStream* out) OVERRIDE {
- return oat_writer_->Write(out);
- }
- private:
- OatWriter* const oat_writer_;
-};
-
template <typename ElfTypes>
static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer);
@@ -99,18 +83,29 @@
buffer->push_back(0); // End of sections.
}
-template<typename AddressType, bool SubtractPatchLocation = false>
-static void PatchAddresses(const std::vector<uintptr_t>* patch_locations,
- AddressType delta, std::vector<uint8_t>* buffer) {
- // Addresses in .debug_* sections are unaligned.
- typedef __attribute__((__aligned__(1))) AddressType UnalignedAddressType;
- if (patch_locations != nullptr) {
- for (uintptr_t patch_location : *patch_locations) {
- *reinterpret_cast<UnalignedAddressType*>(buffer->data() + patch_location) +=
- delta - (SubtractPatchLocation ? patch_location : 0);
- }
+class RodataWriter FINAL : public CodeOutput {
+ public:
+ explicit RodataWriter(OatWriter* oat_writer) : oat_writer_(oat_writer) {}
+
+ bool Write(OutputStream* out) OVERRIDE {
+ return oat_writer_->WriteRodata(out);
}
-}
+
+ private:
+ OatWriter* oat_writer_;
+};
+
+class TextWriter FINAL : public CodeOutput {
+ public:
+ explicit TextWriter(OatWriter* oat_writer) : oat_writer_(oat_writer) {}
+
+ bool Write(OutputStream* out) OVERRIDE {
+ return oat_writer_->WriteCode(out);
+ }
+
+ private:
+ OatWriter* oat_writer_;
+};
template <typename ElfTypes>
bool ElfWriterQuick<ElfTypes>::Write(
@@ -118,106 +113,81 @@
const std::vector<const DexFile*>& dex_files_unused ATTRIBUTE_UNUSED,
const std::string& android_root_unused ATTRIBUTE_UNUSED,
bool is_host_unused ATTRIBUTE_UNUSED) {
- constexpr bool debug = false;
- const OatHeader& oat_header = oat_writer->GetOatHeader();
- typename ElfTypes::Word oat_data_size = oat_header.GetExecutableOffset();
- uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size;
- uint32_t oat_bss_size = oat_writer->GetBssSize();
+ const InstructionSet isa = compiler_driver_->GetInstructionSet();
- OatWriterWrapper wrapper(oat_writer);
-
+ // Setup the builder with the main OAT sections (.rodata .text .bss).
+ const size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
+ const size_t text_size = oat_writer->GetSize() - rodata_size;
+ const size_t bss_size = oat_writer->GetBssSize();
+ RodataWriter rodata_writer(oat_writer);
+ TextWriter text_writer(oat_writer);
std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(
- &wrapper,
- elf_file_,
- compiler_driver_->GetInstructionSet(),
- 0,
- oat_data_size,
- oat_data_size,
- oat_exec_size,
- RoundUp(oat_data_size + oat_exec_size, kPageSize),
- oat_bss_size,
- compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(),
- debug));
+ isa, rodata_size, &rodata_writer, text_size, &text_writer, bss_size));
- InstructionSet isa = compiler_driver_->GetInstructionSet();
- int alignment = GetInstructionSetPointerSize(isa);
- typedef ElfRawSectionBuilder<ElfTypes> RawSection;
- RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, alignment, 0);
- RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
- RawSection debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- RawSection debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- RawSection debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ // Add debug sections.
+ // They are stack allocated here (in the same scope as the builder),
+ // but they are registred with the builder only if they are used.
+ using RawSection = typename ElfBuilder<ElfTypes>::RawSection;
+ const auto* text = builder->GetText();
+ constexpr bool absolute = false; // patch to make absolute addresses.
+ constexpr bool relative = true; // patch to make relative addresses.
+ const bool is64bit = Is64BitInstructionSet(isa);
+ RawSection eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC,
+ nullptr, 0, kPageSize, 0, text, relative, is64bit);
+ RawSection eh_frame_hdr(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC,
+ nullptr, 0, 4, 0);
+ RawSection debug_info(".debug_info", SHT_PROGBITS, 0,
+ nullptr, 0, 1, 0, text, absolute, false /* 32bit */);
+ RawSection debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0,
+ nullptr, 0, 1, 0);
+ RawSection debug_str(".debug_str", SHT_PROGBITS, 0,
+ nullptr, 0, 1, 0);
+ RawSection debug_line(".debug_line", SHT_PROGBITS, 0,
+ nullptr, 0, 1, 0, text, absolute, false /* 32bit */);
+ if (!oat_writer->GetMethodDebugInfo().empty()) {
+ if (compiler_driver_->GetCompilerOptions().GetIncludeCFI()) {
+ dwarf::WriteEhFrame(
+ compiler_driver_, oat_writer, dwarf::DW_EH_PE_pcrel,
+ eh_frame.GetBuffer(), eh_frame.GetPatchLocations(),
+ eh_frame_hdr.GetBuffer());
+ builder->RegisterSection(&eh_frame);
+ builder->RegisterSection(&eh_frame_hdr);
+ }
+ if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
+ // Add methods to .symtab.
+ WriteDebugSymbols(builder.get(), oat_writer);
+ // Generate DWARF .debug_* sections.
+ dwarf::WriteDebugSections(
+ compiler_driver_, oat_writer,
+ debug_info.GetBuffer(), debug_info.GetPatchLocations(),
+ debug_abbrev.GetBuffer(),
+ debug_str.GetBuffer(),
+ debug_line.GetBuffer(), debug_line.GetPatchLocations());
+ builder->RegisterSection(&debug_info);
+ builder->RegisterSection(&debug_abbrev);
+ builder->RegisterSection(&debug_str);
+ builder->RegisterSection(&debug_line);
+ *oat_writer->GetAbsolutePatchLocationsFor(".debug_info") =
+ *debug_info.GetPatchLocations();
+ *oat_writer->GetAbsolutePatchLocationsFor(".debug_line") =
+ *debug_line.GetPatchLocations();
+ }
+ }
+
+ // Add relocation section.
RawSection oat_patches(".oat_patches", SHT_OAT_PATCH, 0, nullptr, 0, 1, 0);
-
- // Do not add to .oat_patches since we will make the addresses relative.
- std::vector<uintptr_t> eh_frame_patches;
- if (compiler_driver_->GetCompilerOptions().GetIncludeCFI() &&
- !oat_writer->GetMethodDebugInfo().empty()) {
- dwarf::WriteEhFrame(compiler_driver_, oat_writer,
- dwarf::DW_EH_PE_pcrel,
- eh_frame.GetBuffer(), &eh_frame_patches,
- eh_frame_hdr.GetBuffer());
- builder->RegisterRawSection(&eh_frame);
- builder->RegisterRawSection(&eh_frame_hdr);
- }
-
- // Must be done after .eh_frame is created since it is used in the Elf layout.
- if (!builder->Init()) {
- return false;
- }
-
- std::vector<uintptr_t>* debug_info_patches = nullptr;
- std::vector<uintptr_t>* debug_line_patches = nullptr;
- if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols() &&
- !oat_writer->GetMethodDebugInfo().empty()) {
- // Add methods to .symtab.
- WriteDebugSymbols(builder.get(), oat_writer);
- // Generate DWARF .debug_* sections.
- debug_info_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_info");
- debug_line_patches = oat_writer->GetAbsolutePatchLocationsFor(".debug_line");
- dwarf::WriteDebugSections(compiler_driver_, oat_writer,
- debug_info.GetBuffer(), debug_info_patches,
- debug_abbrev.GetBuffer(),
- debug_str.GetBuffer(),
- debug_line.GetBuffer(), debug_line_patches);
- builder->RegisterRawSection(&debug_info);
- builder->RegisterRawSection(&debug_abbrev);
- builder->RegisterRawSection(&debug_str);
- builder->RegisterRawSection(&debug_line);
- }
-
if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation() ||
// ElfWriter::Fixup will be called regardless and it needs to be able
// to patch debug sections so we have to include patches for them.
compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
EncodeOatPatches(oat_writer->GetAbsolutePatchLocations(), oat_patches.GetBuffer());
- builder->RegisterRawSection(&oat_patches);
+ builder->RegisterSection(&oat_patches);
}
- // We know where .text and .eh_frame will be located, so patch the addresses.
- typename ElfTypes::Addr text_addr = builder->GetTextBuilder().GetSection()->sh_addr;
- // TODO: Simplify once we use Elf64 - we can use ElfTypes::Addr instead of branching.
- if (Is64BitInstructionSet(compiler_driver_->GetInstructionSet())) {
- // relative_address = (text_addr + address) - (eh_frame_addr + patch_location);
- PatchAddresses<uint64_t, true>(&eh_frame_patches,
- text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer());
- PatchAddresses<uint64_t>(debug_info_patches, text_addr, debug_info.GetBuffer());
- PatchAddresses<uint64_t>(debug_line_patches, text_addr, debug_line.GetBuffer());
- } else {
- // relative_address = (text_addr + address) - (eh_frame_addr + patch_location);
- PatchAddresses<uint32_t, true>(&eh_frame_patches,
- text_addr - eh_frame.GetSection()->sh_addr, eh_frame.GetBuffer());
- PatchAddresses<uint32_t>(debug_info_patches, text_addr, debug_info.GetBuffer());
- PatchAddresses<uint32_t>(debug_line_patches, text_addr, debug_line.GetBuffer());
- }
-
- return builder->Write();
+ return builder->Write(elf_file_);
}
template <typename ElfTypes>
-// Do not inline to avoid Clang stack frame problems. b/18738594
-NO_INLINE
static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writer) {
const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetMethodDebugInfo();
@@ -230,7 +200,7 @@
}
}
- ElfSymtabBuilder<ElfTypes>* symtab = builder->GetSymtabBuilder();
+ auto* symtab = builder->GetSymtab();
for (auto it = method_info.begin(); it != method_info.end(); ++it) {
std::string name = PrettyMethod(it->dex_method_index_, *it->dex_file_, true);
if (deduped_addresses.find(it->low_pc_) != deduped_addresses.end()) {
@@ -240,13 +210,13 @@
uint32_t low_pc = it->low_pc_;
// Add in code delta, e.g., thumb bit 0 for Thumb2 code.
low_pc += it->compiled_method_->CodeDelta();
- symtab->AddSymbol(name, &builder->GetTextBuilder(), low_pc,
+ symtab->AddSymbol(name, builder->GetText(), low_pc,
true, it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC);
// Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
// instructions, so that disassembler tools can correctly disassemble.
if (it->compiled_method_->GetInstructionSet() == kThumb2) {
- symtab->AddSymbol("$t", &builder->GetTextBuilder(), it->low_pc_ & ~1, true,
+ symtab->AddSymbol("$t", builder->GetText(), it->low_pc_ & ~1, true,
0, STB_LOCAL, STT_NOTYPE);
}
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index d2d38da..15b4017 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1112,13 +1112,14 @@
return offset;
}
-bool OatWriter::Write(OutputStream* out) {
+bool OatWriter::WriteRodata(OutputStream* out) {
const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
if (raw_file_offset == (off_t) -1) {
LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
return false;
}
const size_t file_offset = static_cast<size_t>(raw_file_offset);
+ oat_data_offset_ = file_offset;
// Reserve space for header. It will be written last - after updating the checksum.
size_t header_size = oat_header_->GetHeaderSize();
@@ -1146,6 +1147,27 @@
return false;
}
+ // Write padding.
+ off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
+ relative_offset += size_executable_offset_alignment_;
+ DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
+ size_t expected_file_offset = file_offset + relative_offset;
+ if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
+ PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
+ << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
+ return 0;
+ }
+ DCHECK_OFFSET();
+
+ return true;
+}
+
+bool OatWriter::WriteCode(OutputStream* out) {
+ size_t header_size = oat_header_->GetHeaderSize();
+ const size_t file_offset = oat_data_offset_;
+ size_t relative_offset = oat_header_->GetExecutableOffset();
+ DCHECK_OFFSET();
+
relative_offset = WriteCode(out, file_offset, relative_offset);
if (relative_offset == 0) {
LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
@@ -1215,7 +1237,7 @@
PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
return false;
}
- DCHECK_EQ(raw_file_offset, out->Seek(0, kSeekCurrent));
+ DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
if (!out->WriteFully(oat_header_, header_size)) {
PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
return false;
@@ -1290,16 +1312,6 @@
}
size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
- off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
- relative_offset += size_executable_offset_alignment_;
- DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
- size_t expected_file_offset = file_offset + relative_offset;
- if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
- PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
- << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
- return 0;
- }
- DCHECK_OFFSET();
if (compiler_driver_->IsImage()) {
InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 8c79b44..6f1b4ec 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -118,11 +118,8 @@
return it.first->second.get();
}
- void SetOatDataOffset(size_t oat_data_offset) {
- oat_data_offset_ = oat_data_offset;
- }
-
- bool Write(OutputStream* out);
+ bool WriteRodata(OutputStream* out);
+ bool WriteCode(OutputStream* out);
~OatWriter();
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index dc3124b..8ea8f3c 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -170,7 +170,8 @@
}
}
- // Ensure the uses of `instruction` are defined in a block of the graph.
+ // Ensure the uses of `instruction` are defined in a block of the graph,
+ // and the entry in the use list is consistent.
for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
!use_it.Done(); use_it.Advance()) {
HInstruction* use = use_it.Current()->GetUser();
@@ -184,6 +185,27 @@
use->GetId(),
instruction->GetId()));
}
+ size_t use_index = use_it.Current()->GetIndex();
+ if ((use_index >= use->InputCount()) || (use->InputAt(use_index) != instruction)) {
+ AddError(StringPrintf("User %s:%d of instruction %d has a wrong "
+ "UseListNode index.",
+ use->DebugName(),
+ use->GetId(),
+ instruction->GetId()));
+ }
+ }
+
+ // Ensure the environment uses entries are consistent.
+ for (HUseIterator<HEnvironment*> use_it(instruction->GetEnvUses());
+ !use_it.Done(); use_it.Advance()) {
+ HEnvironment* use = use_it.Current()->GetUser();
+ size_t use_index = use_it.Current()->GetIndex();
+ if ((use_index >= use->Size()) || (use->GetInstructionAt(use_index) != instruction)) {
+ AddError(StringPrintf("Environment user of %s:%d has a wrong "
+ "UseListNode index.",
+ instruction->DebugName(),
+ instruction->GetId()));
+ }
}
// Ensure 'instruction' has pointers to its inputs' use entries.
@@ -191,7 +213,11 @@
HUserRecord<HInstruction*> input_record = instruction->InputRecordAt(i);
HInstruction* input = input_record.GetInstruction();
HUseListNode<HInstruction*>* use_node = input_record.GetUseNode();
- if (use_node == nullptr || !input->GetUses().Contains(use_node)) {
+ size_t use_index = use_node->GetIndex();
+ if ((use_node == nullptr)
+ || !input->GetUses().Contains(use_node)
+ || (use_index >= e)
+ || (use_index != i)) {
AddError(StringPrintf("Instruction %s:%d has an invalid pointer to use entry "
"at input %u (%s:%d).",
instruction->DebugName(),
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index f07f4c7..d3ee770 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -712,6 +712,9 @@
void HPhi::RemoveInputAt(size_t index) {
RemoveAsUserOfInput(index);
inputs_.DeleteAt(index);
+ for (size_t i = index, e = InputCount(); i < e; ++i) {
+ InputRecordAt(i).GetUseNode()->SetIndex(i);
+ }
}
#define DEFINE_ACCEPT(name, super) \
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 50eecff..63f3c95 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -850,13 +850,14 @@
HUseListNode* GetNext() const { return next_; }
T GetUser() const { return user_; }
size_t GetIndex() const { return index_; }
+ void SetIndex(size_t index) { index_ = index; }
private:
HUseListNode(T user, size_t index)
: user_(user), index_(index), prev_(nullptr), next_(nullptr) {}
T const user_;
- const size_t index_;
+ size_t index_;
HUseListNode<T>* prev_;
HUseListNode<T>* next_;
@@ -1090,7 +1091,7 @@
GrowableArray<HUserRecord<HEnvironment*> > vregs_;
- friend HInstruction;
+ friend class HInstruction;
DISALLOW_COPY_AND_ASSIGN(HEnvironment);
};
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index f2e35af..b9a3d37 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -76,41 +76,38 @@
"kClassRoots",
};
-class OatSymbolizer FINAL : public CodeOutput {
+class OatSymbolizer FINAL {
public:
- explicit OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
- oat_file_(oat_file), builder_(nullptr), elf_output_(nullptr),
- output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
- }
+ class RodataWriter FINAL : public CodeOutput {
+ public:
+ explicit RodataWriter(const OatFile* oat_file) : oat_file_(oat_file) {}
- bool Init() {
- Elf32_Word oat_data_size = oat_file_->GetOatHeader().GetExecutableOffset();
-
- uint32_t diff = static_cast<uint32_t>(oat_file_->End() - oat_file_->Begin());
- uint32_t oat_exec_size = diff - oat_data_size;
- uint32_t oat_bss_size = oat_file_->BssSize();
-
- elf_output_ = OS::CreateEmptyFile(output_name_.c_str());
-
- builder_.reset(new ElfBuilder<ElfTypes32>(
- this,
- elf_output_,
- oat_file_->GetOatHeader().GetInstructionSet(),
- 0,
- oat_data_size,
- oat_data_size,
- oat_exec_size,
- RoundUp(oat_data_size + oat_exec_size, kPageSize),
- oat_bss_size,
- true,
- false));
-
- if (!builder_->Init()) {
- builder_.reset(nullptr);
- return false;
+ bool Write(OutputStream* out) OVERRIDE {
+ const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
+ return out->WriteFully(oat_file_->Begin(), rodata_size);
}
- return true;
+ private:
+ const OatFile* oat_file_;
+ };
+
+ class TextWriter FINAL : public CodeOutput {
+ public:
+ explicit TextWriter(const OatFile* oat_file) : oat_file_(oat_file) {}
+
+ bool Write(OutputStream* out) OVERRIDE {
+ const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
+ const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
+ return out->WriteFully(text_begin, oat_file_->End() - text_begin);
+ }
+
+ private:
+ const OatFile* oat_file_;
+ };
+
+ explicit OatSymbolizer(const OatFile* oat_file, const std::string& output_name) :
+ oat_file_(oat_file), builder_(nullptr),
+ output_name_(output_name.empty() ? "symbolized.oat" : output_name) {
}
typedef void (OatSymbolizer::*Callback)(const DexFile::ClassDef&,
@@ -122,9 +119,17 @@
uint32_t);
bool Symbolize() {
- if (builder_.get() == nullptr) {
- return false;
- }
+ Elf32_Word rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
+ uint32_t size = static_cast<uint32_t>(oat_file_->End() - oat_file_->Begin());
+ uint32_t text_size = size - rodata_size;
+ uint32_t bss_size = oat_file_->BssSize();
+ RodataWriter rodata_writer(oat_file_);
+ TextWriter text_writer(oat_file_);
+ builder_.reset(new ElfBuilder<ElfTypes32>(
+ oat_file_->GetOatHeader().GetInstructionSet(),
+ rodata_size, &rodata_writer,
+ text_size, &text_writer,
+ bss_size));
Walk(&art::OatSymbolizer::RegisterForDedup);
@@ -132,10 +137,11 @@
Walk(&art::OatSymbolizer::AddSymbol);
- bool result = builder_->Write();
+ File* elf_output = OS::CreateEmptyFile(output_name_.c_str());
+ bool result = builder_->Write(elf_output);
// Ignore I/O errors.
- UNUSED(elf_output_->FlushClose());
+ UNUSED(elf_output->FlushClose());
return result;
}
@@ -269,24 +275,14 @@
pretty_name = "[Dedup]" + pretty_name;
}
- ElfSymtabBuilder<ElfTypes32>* symtab = builder_->GetSymtabBuilder();
+ auto* symtab = builder_->GetSymtab();
- symtab->AddSymbol(pretty_name, &builder_->GetTextBuilder(),
+ symtab->AddSymbol(pretty_name, builder_->GetText(),
oat_method.GetCodeOffset() - oat_file_->GetOatHeader().GetExecutableOffset(),
true, oat_method.GetQuickCodeSize(), STB_GLOBAL, STT_FUNC);
}
}
- // Set oat data offset. Required by ElfBuilder/CodeOutput.
- void SetCodeOffset(size_t offset ATTRIBUTE_UNUSED) {
- // Nothing to do.
- }
-
- // Write oat code. Required by ElfBuilder/CodeOutput.
- bool Write(OutputStream* out) {
- return out->WriteFully(oat_file_->Begin(), oat_file_->End() - oat_file_->Begin());
- }
-
private:
static void SkipAllFields(ClassDataItemIterator* it) {
while (it->HasNextStaticField()) {
@@ -299,7 +295,6 @@
const OatFile* oat_file_;
std::unique_ptr<ElfBuilder<ElfTypes32> > builder_;
- File* elf_output_;
std::unordered_map<uint32_t, uint32_t> state_;
const std::string output_name_;
};
@@ -2203,10 +2198,6 @@
}
OatSymbolizer oat_symbolizer(oat_file, output_name);
- if (!oat_symbolizer.Init()) {
- fprintf(stderr, "Failed to initialize symbolizer\n");
- return EXIT_FAILURE;
- }
if (!oat_symbolizer.Symbolize()) {
fprintf(stderr, "Failed to symbolize\n");
return EXIT_FAILURE;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 962e821..b099088 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -82,10 +82,6 @@
static constexpr bool kSanityCheckObjects = kIsDebugBuild;
-// Do a simple class redefinition check in OpenDexFilesFromOat. This is a conservative check to
-// avoid problems with compile-time class-path != runtime class-path.
-static constexpr bool kCheckForDexCollisions = true;
-
static void ThrowNoClassDefFoundError(const char* fmt, ...)
__attribute__((__format__(__printf__, 1, 2)))
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -743,6 +739,8 @@
const char* rhsDescriptor = rhs.cached_descriptor_;
int cmp = strcmp(lhsDescriptor, rhsDescriptor);
if (cmp != 0) {
+ // Note that the order must be reversed. We want to iterate over the classes in dex files.
+ // They are sorted lexicographically. Thus, the priority-queue must be a min-queue.
return cmp > 0;
}
return dex_file_ < rhs.dex_file_;
@@ -768,6 +766,11 @@
return dex_file_;
}
+ void DeleteDexFile() {
+ delete dex_file_;
+ dex_file_ = nullptr;
+ }
+
private:
static const char* GetClassDescriptor(const DexFile* dex_file, size_t index) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(static_cast<uint16_t>(index));
@@ -799,13 +802,13 @@
}
}
-static void AddNext(const DexFileAndClassPair& original,
+static void AddNext(DexFileAndClassPair* original,
std::priority_queue<DexFileAndClassPair>* heap) {
- if (original.DexFileHasMoreClasses()) {
- heap->push(original.GetNext());
+ if (original->DexFileHasMoreClasses()) {
+ heap->push(original->GetNext());
} else {
// Need to delete the dex file.
- delete original.GetDexFile();
+ original->DeleteDexFile();
}
}
@@ -824,19 +827,17 @@
// the two elements agree on whether their dex file was from an already-loaded oat-file or the
// new oat file. Any disagreement indicates a collision.
bool ClassLinker::HasCollisions(const OatFile* oat_file, std::string* error_msg) {
- if (!kCheckForDexCollisions) {
- return false;
- }
-
// Dex files are registered late - once a class is actually being loaded. We have to compare
- // against the open oat files.
+ // against the open oat files. Take the dex_lock_ that protects oat_files_ accesses.
ReaderMutexLock mu(Thread::Current(), dex_lock_);
- std::priority_queue<DexFileAndClassPair> heap;
+ std::priority_queue<DexFileAndClassPair> queue;
// Add dex files from already loaded oat files, but skip boot.
{
- // To grab the boot oat, look at the dex files in the boot classpath.
+ // To grab the boot oat, look at the dex files in the boot classpath. Any of those is fine, as
+ // they were all compiled into the same oat file. So grab the first one, which is guaranteed to
+ // exist if the boot class-path isn't empty.
const OatFile* boot_oat = nullptr;
if (!boot_class_path_.empty()) {
const DexFile* boot_dex_file = boot_class_path_[0];
@@ -850,26 +851,26 @@
if (loaded_oat_file == boot_oat) {
continue;
}
- AddDexFilesFromOat(loaded_oat_file, true, &heap);
+ AddDexFilesFromOat(loaded_oat_file, true, &queue);
}
}
- if (heap.empty()) {
+ if (queue.empty()) {
// No other oat files, return early.
return false;
}
// Add dex files from the oat file to check.
- AddDexFilesFromOat(oat_file, false, &heap);
+ AddDexFilesFromOat(oat_file, false, &queue);
- // Now drain the heap.
- while (!heap.empty()) {
- DexFileAndClassPair compare_pop = heap.top();
- heap.pop();
+ // Now drain the queue.
+ while (!queue.empty()) {
+ DexFileAndClassPair compare_pop = queue.top();
+ queue.pop();
// Compare against the following elements.
- while (!heap.empty()) {
- DexFileAndClassPair top = heap.top();
+ while (!queue.empty()) {
+ DexFileAndClassPair top = queue.top();
if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
// Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
@@ -879,18 +880,18 @@
compare_pop.GetCachedDescriptor(),
compare_pop.GetDexFile()->GetLocation().c_str(),
top.GetDexFile()->GetLocation().c_str());
- FreeDexFilesInHeap(&heap);
+ FreeDexFilesInHeap(&queue);
return true;
}
// Pop it.
- heap.pop();
- AddNext(top, &heap);
+ queue.pop();
+ AddNext(&top, &queue);
} else {
// Something else. Done here.
break;
}
}
- AddNext(compare_pop, &heap);
+ AddNext(&compare_pop, &queue);
}
return false;
@@ -941,11 +942,10 @@
// Get the oat file on disk.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
if (oat_file.get() != nullptr) {
- // Take the file only if it has no collisions.
- if (!HasCollisions(oat_file.get(), &error_msg)) {
- source_oat_file = oat_file.release();
- RegisterOatFile(source_oat_file);
- } else {
+ // Take the file only if it has no collisions, or we must take it because of preopting.
+ bool accept_oat_file = !HasCollisions(oat_file.get(), &error_msg);
+ if (!accept_oat_file) {
+ // Failed the collision check. Print warning.
if (Runtime::Current()->IsDexFileFallbackEnabled()) {
LOG(WARNING) << "Found duplicate classes, falling back to interpreter mode for "
<< dex_location;
@@ -954,6 +954,19 @@
" load classes for " << dex_location;
}
LOG(WARNING) << error_msg;
+
+ // However, if the app was part of /system and preopted, there is no original dex file
+ // available. In that case grudgingly accept the oat file.
+ if (!DexFile::MaybeDex(dex_location)) {
+ accept_oat_file = true;
+ LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. "
+ << "Allow oat file use. This is potentially dangerous.";
+ }
+ }
+
+ if (accept_oat_file) {
+ source_oat_file = oat_file.release();
+ RegisterOatFile(source_oat_file);
}
}
}
@@ -975,8 +988,7 @@
if (Runtime::Current()->IsDexFileFallbackEnabled()) {
if (!DexFile::Open(dex_location, dex_location, &error_msg, &dex_files)) {
LOG(WARNING) << error_msg;
- error_msgs->push_back("Failed to open dex files from "
- + std::string(dex_location));
+ error_msgs->push_back("Failed to open dex files from " + std::string(dex_location));
}
} else {
error_msgs->push_back("Fallback mode disabled, skipping dex files.");
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 20098e7..dfe5a04 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -153,6 +153,31 @@
return false;
}
+static bool ContainsClassesDex(int fd, const char* filename) {
+ std::string error_msg;
+ std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, filename, &error_msg));
+ if (zip_archive.get() == nullptr) {
+ return false;
+ }
+ std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(DexFile::kClassesDex, &error_msg));
+ return (zip_entry.get() != nullptr);
+}
+
+bool DexFile::MaybeDex(const char* filename) {
+ uint32_t magic;
+ std::string error_msg;
+ ScopedFd fd(OpenAndReadMagic(filename, &magic, &error_msg));
+ if (fd.get() == -1) {
+ return false;
+ }
+ if (IsZipMagic(magic)) {
+ return ContainsClassesDex(fd.release(), filename);
+ } else if (IsDexMagic(magic)) {
+ return true;
+ }
+ return false;
+}
+
int DexFile::GetPermissions() const {
if (mem_map_.get() == nullptr) {
return 0;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 6b3f883..84eaa4a 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -388,6 +388,10 @@
static bool Open(const char* filename, const char* location, std::string* error_msg,
std::vector<std::unique_ptr<const DexFile>>* dex_files);
+ // Checks whether the given file has the dex magic, or is a zip file with a classes.dex entry.
+ // If this function returns false, Open will not succeed. The inverse is not true, however.
+ static bool MaybeDex(const char* filename);
+
// Opens .dex file, backed by existing memory
static std::unique_ptr<const DexFile> Open(const uint8_t* base, size_t size,
const std::string& location,
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ef3c6e2..ae67efb 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -501,6 +501,7 @@
uint16_t num_regs;
if (LIKELY(code_item != nullptr)) {
num_regs = code_item->registers_size_;
+ DCHECK_EQ(string_init ? num_ins - 1 : num_ins, code_item->ins_size_);
} else {
DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
num_regs = num_ins;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index eb60318..2633898 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1566,14 +1566,15 @@
// Throwing an exception may cause its class initialization. If we mark the transaction
// aborted before that, we may warn with a false alarm. Throwing the exception before
// marking the transaction aborted avoids that.
- preinitialization_transaction_->ThrowAbortError(self, false);
+ preinitialization_transaction_->ThrowAbortError(self, &abort_message);
preinitialization_transaction_->Abort(abort_message);
}
void Runtime::ThrowTransactionAbortError(Thread* self) {
DCHECK(IsAotCompiler());
DCHECK(IsActiveTransaction());
- preinitialization_transaction_->ThrowAbortError(self, true);
+ // Passing nullptr means we rethrow an exception with the earlier transaction abort message.
+ preinitialization_transaction_->ThrowAbortError(self, nullptr);
}
void Runtime::RecordWriteFieldBoolean(mirror::Object* obj, MemberOffset field_offset,
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index cc0f15f..ab821d7 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -70,13 +70,21 @@
}
}
-void Transaction::ThrowAbortError(Thread* self, bool rethrow) {
+void Transaction::ThrowAbortError(Thread* self, const std::string* abort_message) {
+ const bool rethrow = (abort_message == nullptr);
if (kIsDebugBuild && rethrow) {
CHECK(IsAborted()) << "Rethrow " << Transaction::kAbortExceptionDescriptor
<< " while transaction is not aborted";
}
- std::string abort_msg(GetAbortMessage());
- self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature, abort_msg.c_str());
+ if (rethrow) {
+ // Rethrow an exception with the earlier abort message stored in the transaction.
+ self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
+ GetAbortMessage().c_str());
+ } else {
+ // Throw an exception with the given abort message.
+ self->ThrowNewWrappedException(Transaction::kAbortExceptionSignature,
+ abort_message->c_str());
+ }
}
bool Transaction::IsAborted() {
diff --git a/runtime/transaction.h b/runtime/transaction.h
index 4d85662..030478c 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -48,7 +48,7 @@
void Abort(const std::string& abort_message)
LOCKS_EXCLUDED(log_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void ThrowAbortError(Thread* self, bool rethrow)
+ void ThrowAbortError(Thread* self, const std::string* abort_message)
LOCKS_EXCLUDED(log_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsAborted() LOCKS_EXCLUDED(log_lock_);
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 8445751..2838681 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -137,7 +137,7 @@
if (GetRegisterType(verifier, i).Equals(uninit_type)) {
line_[i] = init_type.GetId();
changed++;
- if (i != this_reg && is_string) {
+ if (is_string && i != this_reg) {
auto it = verifier->GetStringInitPcRegMap().find(dex_pc);
if (it != verifier->GetStringInitPcRegMap().end()) {
it->second.insert(i);
diff --git a/test/138-duplicate-classes-check/build b/test/138-duplicate-classes-check/build
deleted file mode 100755
index 7ddc81d..0000000
--- a/test/138-duplicate-classes-check/build
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-#
-# 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.
-
-# Stop if something fails.
-set -e
-
-mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
-
-mkdir classes-ex
-${JAVAC} -d classes-ex `find src-ex -name '*.java'`
-
-if [ ${NEED_DEX} = "true" ]; then
- ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
- zip $TEST_NAME.jar classes.dex
- ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
- zip ${TEST_NAME}-ex.jar classes.dex
-fi
diff --git a/test/483-dce-block/expected.txt b/test/483-dce-block/expected.txt
new file mode 100644
index 0000000..ef48625
--- /dev/null
+++ b/test/483-dce-block/expected.txt
@@ -0,0 +1 @@
+class Main
diff --git a/test/483-dce-block/info.txt b/test/483-dce-block/info.txt
new file mode 100644
index 0000000..3db88ab
--- /dev/null
+++ b/test/483-dce-block/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing that used to crash
+compiling the `foo` method.
diff --git a/test/483-dce-block/src/Main.java b/test/483-dce-block/src/Main.java
new file mode 100644
index 0000000..2f66a74
--- /dev/null
+++ b/test/483-dce-block/src/Main.java
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+public class Main {
+ public static void foo(Object o, int a) {
+ Object result = null;
+ if (o instanceof Main) {
+ // The compiler optimizes the type of `o` by introducing
+ // a `HBoundType` in this block.
+ while (a != 3) {
+ if (a == 2) {
+ a++;
+ result = o;
+ continue;
+ } else if (willInline()) {
+ // This block will be detected as dead after inlining.
+ result = new Object();
+ continue;
+ }
+ result = new Object();
+ }
+ // The compiler produces a phi at the back edge for `result`.
+ // Before dead block elimination, the phi has three inputs:
+ // result = (new Object(), new Object(), HBoundType)
+ //
+ // After dead block elimination, the phi has now two inputs:
+ // result = (new Object(), HBoundType)
+ //
+ // Our internal data structure for linking users and inputs expect
+ // the input index stored in that data structure to be the index
+ // in the inputs array. So the index before dead block elimination
+ // of the `HBoundType` would be 2. Dead block elimination must update
+ // that index to be 1.
+ }
+ System.out.println(result.getClass());
+ }
+
+ public static boolean willInline() {
+ return false;
+ }
+
+ public static void main(String[] args) {
+ foo(new Main(), 2);
+ }
+}