Merge "Major refactoring of ElfBuilder."
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index 022fac2..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 typename ElfBuilder<ElfTypes>::ElfRawSectionBuilder 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 9c173f8..90b99bc 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,9 +17,10 @@
#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"
@@ -28,15 +29,20 @@
class CodeOutput {
public:
- virtual void SetCodeOffset(size_t offset) = 0;
virtual bool Write(OutputStream* out) = 0;
virtual ~CodeOutput() {}
};
+// Writes ELF file.
+// The main complication is that the sections often want to reference
+// each other. We solve this by writing the ELF file in two stages:
+// * Sections are asked about their size, and overall layout is calculated.
+// * Sections do the actual writes which may use offsets of other sections.
template <typename ElfTypes>
class ElfBuilder FINAL {
public:
using Elf_Addr = typename ElfTypes::Addr;
+ using Elf_Off = typename ElfTypes::Off;
using Elf_Word = typename ElfTypes::Word;
using Elf_Sword = typename ElfTypes::Sword;
using Elf_Ehdr = typename ElfTypes::Ehdr;
@@ -45,36 +51,43 @@
using Elf_Phdr = typename ElfTypes::Phdr;
using Elf_Dyn = typename ElfTypes::Dyn;
- class ElfSectionBuilder : public ValueObject {
+ // Base class of all sections.
+ class Section {
public:
- ElfSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
- const ElfSectionBuilder *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;
+ 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;
}
- ElfSectionBuilder(const ElfSectionBuilder&) = default;
+ virtual ~Section() {}
- ~ElfSectionBuilder() {}
+ // 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_->section_index_ : 0;
+ return (link_ != nullptr) ? link_->GetSectionIndex() : 0;
}
- const Elf_Shdr* GetSection() const {
- return §ion_;
+ const Elf_Shdr* GetHeader() const {
+ return &header_;
}
- Elf_Shdr* GetSection() {
- return §ion_;
+ Elf_Shdr* GetHeader() {
+ return &header_;
}
Elf_Word GetSectionIndex() const {
+ DCHECK_NE(section_index_, 0u);
return section_index_;
}
@@ -87,171 +100,303 @@
}
private:
- Elf_Shdr section_;
+ Elf_Shdr header_;
Elf_Word section_index_;
const std::string name_;
- const ElfSectionBuilder* const link_;
+ const Section* const link_;
+
+ DISALLOW_COPY_AND_ASSIGN(Section);
};
- class ElfDynamicBuilder FINAL : public ElfSectionBuilder {
+ // Writer of .dynamic section.
+ class DynamicSection FINAL : public Section {
public:
- 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 value, const Section* section) {
+ DCHECK_NE(tag, static_cast<Elf_Sword>(DT_NULL));
+ dynamics_.push_back({tag, value, section});
}
- void AddDynamicTag(Elf_Sword tag, Elf_Word d_un,
- const ElfSectionBuilder* section) {
- if (tag == DT_NULL) {
- return;
- }
- dynamics_.push_back({section, tag, d_un});
+ 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);
}
- ElfDynamicBuilder(const std::string& sec_name,
- ElfSectionBuilder *link)
- : ElfSectionBuilder(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) {
+ 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.
- ret.push_back(
- {it->tag_, {it->off_ + it->section_->GetSection()->sh_addr}});
+ buffer.push_back(
+ {it.tag_, {it.value_ + it.section_->GetHeader()->sh_addr}});
} else {
- ret.push_back({it->tag_, {it->off_}});
+ buffer.push_back({it.tag_, {it.value_}});
}
}
- ret.push_back({DT_STRSZ, {strsz}});
- ret.push_back({DT_SONAME, {soname}});
- ret.push_back({DT_NULL, {0}});
- return ret;
+ buffer.push_back({DT_NULL, {0}});
+ return WriteArray(elf_file, buffer.data(), buffer.size());
}
private:
struct ElfDynamicState {
- const ElfSectionBuilder* section_;
Elf_Sword tag_;
- Elf_Word off_;
+ Elf_Word value_;
+ const Section* section_;
};
std::vector<ElfDynamicState> dynamics_;
};
- class ElfRawSectionBuilder FINAL : public ElfSectionBuilder {
+ // 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:
- ElfRawSectionBuilder(const std::string& sec_name, Elf_Word type, Elf_Word flags,
- const ElfSectionBuilder* link, Elf_Word info,
- Elf_Word align, Elf_Word entsize)
- : ElfSectionBuilder(sec_name, type, flags, link, info, align, entsize) {
+ 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) {
}
- ElfRawSectionBuilder(const ElfRawSectionBuilder&) = default;
- ~ElfRawSectionBuilder() {}
+ 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 &buf_;
+ return &buffer_;
}
- void SetBuffer(const std::vector<uint8_t>& buf) {
- buf_ = buf;
+ void SetBuffer(const std::vector<uint8_t>& buffer) {
+ buffer_ = buffer;
+ }
+
+ std::vector<uintptr_t>* GetPatchLocations() {
+ return &patch_locations_;
}
private:
- std::vector<uint8_t> buf_;
+ 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_;
};
- class ElfOatSectionBuilder FINAL : public ElfSectionBuilder {
+ // Writer of .rodata section or .text section.
+ // The write is done lazily using the provided CodeOutput.
+ class OatSection FINAL : public Section {
public:
- ElfOatSectionBuilder(const std::string& sec_name, Elf_Word size, Elf_Word offset,
- Elf_Word type, Elf_Word flags)
- : ElfSectionBuilder(sec_name, type, flags, nullptr, 0, kPageSize, 0),
- offset_(offset), size_(size) {
+ 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) {
}
- ~ElfOatSectionBuilder() {}
-
- Elf_Word GetOffset() const {
- return offset_;
- }
-
- Elf_Word GetSize() const {
+ 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:
- // Offset of the content within the file.
- Elf_Word offset_;
- // Size of the content within the file.
+ 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_;
};
- 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;
+ // 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';
}
- return h;
- }
- class ElfSymtabBuilder FINAL : public ElfSectionBuilder {
+ 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 ElfSectionBuilder* 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);
+ 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 });
}
- ElfSymtabBuilder(const std::string& sec_name, Elf_Word type,
- const std::string& str_name, Elf_Word str_type, bool alloc)
- : ElfSectionBuilder(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) {
+ 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) {
}
- ~ElfSymtabBuilder() {}
+ bool IsEmpty() const {
+ return symbols_.empty();
+ }
- std::vector<Elf_Word> GenerateHashContents() const {
+ 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.
@@ -282,21 +427,12 @@
//
// 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;
- 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);
- }
+ 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);
@@ -308,11 +444,11 @@
Elf_Word* chain = hash.data() + chain_offset;
// Set up the actual hash table.
- for (Elf_Word i = 0; i < symbols_.size(); i++) {
+ 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;
+ 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 {
@@ -329,251 +465,67 @@
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* GetStrTab() {
- return &strtab_;
+ return WriteArray(elf_file, hash.data(), hash.size());
}
private:
- struct ElfSymbolState {
- const std::string name_;
- const ElfSectionBuilder* 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 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_;
- };
-
- 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;
+ 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);
}
}
- 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);
- }
+ // from bionic
+ static inline unsigned elfhash(const char *_name) {
+ const unsigned char *name = (const unsigned char *) _name;
+ unsigned h = 0, g;
- 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);
+ 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& GetTextBuilder() const {
- return text_builder_;
- }
+ OatSection* GetText() { return &text_; }
+ SymtabSection* GetSymtab() { return &symtab_; }
- ElfSymtabBuilder* 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
@@ -600,21 +552,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] |
+ // | hashtable for dynsym |
// +-------------------------+
// | .eh_frame | (Optional)
// +-------------------------+
@@ -627,38 +568,19 @@
// | 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)
// | .debug_info | (Optional)
// +-------------------------+ (Optional)
@@ -667,574 +589,280 @@
// | .debug_str | (Optional)
// +-------------------------+ (Optional)
// | .debug_line | (Optional)
- // +-------------------------+ (Optional)
+ // +-------------------------+
+ // | .shstrtab |
+ // | names of sections |
+ // +-------------------------+
// | Elf_Shdr null |
// | Elf_Shdr .dynsym |
// | Elf_Shdr .dynstr |
// | Elf_Shdr .hash |
+ // | Elf_Shdr .eh_frame | (Optional)
+ // | Elf_Shdr .eh_frame_hdr | (Optional)
// | Elf_Shdr .rodata |
// | Elf_Shdr .text |
// | Elf_Shdr .bss | (Optional)
// | Elf_Shdr .dynamic |
- // | Elf_Shdr .shstrtab |
- // | Elf_Shdr .eh_frame | (Optional)
- // | Elf_Shdr .eh_frame_hdr | (Optional)
+ // | Elf_Shdr .symtab | (Optional)
+ // | Elf_Shdr .strtab | (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;
- }
- // 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;
- }
-
- 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);
-
- 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;
-
- 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 .eh_frame and .eh_frame_hdr
- for (auto* builder : other_builders_) {
- if ((builder->GetSection()->sh_flags & SHF_ALLOC) != 0) {
- section_ptrs_.push_back(builder->GetSection());
- AssignSectionStr(builder, &shstrtab_);
- builder->SetSectionIndex(section_index_);
- section_index_++;
+ // 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_);
+ for (Section* section : other_sections_) {
+ if ((section->GetHeader()->sh_flags & SHF_ALLOC) != 0) {
+ sections.push_back(section);
}
}
-
- // 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_++;
+ sections.push_back(&rodata_);
+ sections.push_back(&text_);
+ if (bss_.GetSize() != 0u) {
+ sections.push_back(&bss_);
}
-
- // 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);
+ sections.push_back(&dynamic_);
+ if (!symtab_.IsEmpty()) {
+ sections.push_back(&symtab_);
+ sections.push_back(&strtab_);
}
-
- 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();
+ for (Section* section : other_sections_) {
+ if ((section->GetHeader()->sh_flags & SHF_ALLOC) == 0) {
+ sections.push_back(section);
}
}
- // If the sections exist, check that they have been handled.
- const auto* eh_frame = FindRawSection(".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);
+ 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;
}
- // 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();
+ // 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());
- // 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);
+ // 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 = 7;
+ constexpr size_t kProgramHeadersOffset = sizeof(Elf_Ehdr);
+ constexpr size_t kProgramHeadersSize = sizeof(Elf_Phdr) * kMaxProgramHeaders;
- // 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();
+ // 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) << "strtab size (bytes) =" << strtab.size()
- << std::hex << " " << strtab.size();
- LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
- << std::hex << " " << symtab_builder_.GetSize();
+ LOG(INFO) << "Section " << section->GetName() << ":" << std::hex
+ << " offset=0x" << header->sh_offset
+ << " addr=0x" << header->sh_addr
+ << " size=0x" << header->sh_size;
}
+ // Collect section headers into continuous array for convenience.
+ section_headers.push_back(*header);
}
+ Elf_Off section_headers_offset = RoundUp(file_offset, sizeof(Elf_Word));
- // Setup all the other sections.
- for (auto* builder : other_builders_) {
- if ((builder->GetSection()->sh_flags & SHF_ALLOC) == 0) {
- section_ptrs_.push_back(builder->GetSection());
- AssignSectionStr(builder, &shstrtab_);
- builder->SetSectionIndex(section_index_);
- section_index_++;
- }
+ // 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_));
}
-
- // 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");
+ 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_hdr = FindSection(".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.
+ const Section* eh_frame = FindSection(".eh_frame");
+ // Check layout: eh_frame is before eh_frame_hdr and there is 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;
+ 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);
+ program_headers.push_back(MakeProgramHeader(PT_GNU_EH_FRAME, PF_R, *eh_frame_hdr));
}
+ CHECK_LE(program_headers.size(), kMaxProgramHeaders);
- // Finish setup of the Ehdr values.
- elf_header_.e_phoff = PHDR_OFFSET;
- elf_header_.e_shoff = sections_offset;
- elf_header_.e_phnum = PH_NUM - (bss_builder_.GetSection()->sh_size == 0u ? 1 : 0)
- - (eh_frame_hdr == nullptr ? 1 : 0);
- elf_header_.e_shnum = section_ptrs_.size();
- elf_header_.e_shstrndx = shstrtab_builder_.GetSectionIndex();
+ // 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();
- // 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 = (elf_header_.e_phnum - PH_LOAD_RW_BSS) * 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* 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* 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 |
@@ -1242,147 +870,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* 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 text_builder_;
- ElfOatSectionBuilder rodata_builder_;
- ElfOatSectionBuilder bss_builder_;
- ElfSymtabBuilder dynsym_builder_;
- ElfSymtabBuilder symtab_builder_;
- ElfSectionBuilder hash_builder_;
- ElfDynamicBuilder dynamic_builder_;
- ElfSectionBuilder shstrtab_builder_;
- std::vector<ElfRawSectionBuilder*> 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 9ff94e9..d679468 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,82 @@
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 typename ElfBuilder<ElfTypes>::ElfRawSectionBuilder 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 int pointer_size = GetInstructionSetPointerSize(isa);
+ 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, pointer_size, 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 +201,7 @@
}
}
- auto* 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 +211,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/oatdump/oatdump.cc b/oatdump/oatdump.cc
index e142742..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;
}
- auto* 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;