summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Srbecky <dsrbecky@google.com>2015-04-22 19:40:27 +0100
committerDavid Srbecky <dsrbecky@google.com>2015-04-30 12:29:29 +0100
commitbc90fd09e09a845ae6ea0d84ad67560575a94142 (patch)
tree400ccfd60a231ce9bf03fcbad025d724da63a48e
parent0c5bbc11a6af7b4f83b3929bc99de690635095c0 (diff)
downloadandroid_art-bc90fd09e09a845ae6ea0d84ad67560575a94142.tar.gz
android_art-bc90fd09e09a845ae6ea0d84ad67560575a94142.tar.bz2
android_art-bc90fd09e09a845ae6ea0d84ad67560575a94142.zip
Major refactoring of ElfBuilder.
Simplify ElfBuilder by removing duplicated or redundant code. Many of the repeated code patterns were replaced by just looping over the list of all sections. Methods Init() and Write() have been merged into one. The split between those was rather arbitrary, but it was there for a reason. It allowed creation of raw sections between the calls which may have depended on layout decisions done in Init(), but not in Write() (e.g. knowing of offset of .text). This has been replaced by more generic solution. All sections are asked about their size first and complete file layout is calculated. Then the sections are asked to write their content (potentially using the layout information). This should be pure refactoring CL - the compiler should produce bit for bit identical output as before. Change-Id: I281d13d469801bd8288b36b360d200d98a3e92d7
-rw-r--r--compiler/dwarf/dwarf_test.h43
-rw-r--r--compiler/elf_builder.h1645
-rw-r--r--compiler/elf_writer_quick.cc205
-rw-r--r--compiler/oat_writer.cc36
-rw-r--r--compiler/oat_writer.h7
-rw-r--r--oatdump/oatdump.cc91
6 files changed, 779 insertions, 1248 deletions
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h
index 022fac27e1..230ebe3a79 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/dwarf/dwarf_test.h
@@ -57,44 +57,41 @@ class DwarfTest : public CommonRuntimeTest {
// 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 @@ class DwarfTest : public CommonRuntimeTest {
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 9c173f8885..90b99bc6f8 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 @@ namespace art {
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 @@ class ElfBuilder FINAL {
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(&section_, 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() {}
+ 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_->section_index_ : 0;
+ return (link_ != nullptr) ? link_->GetSectionIndex() : 0;
}
- const Elf_Shdr* GetSection() const {
- return &section_;
+ const Elf_Shdr* GetHeader() const {
+ return &header_;
}
- Elf_Shdr* GetSection() {
- return &section_;
+ Elf_Shdr* GetHeader() {
+ return &header_;
}
Elf_Word GetSectionIndex() const {
+ DCHECK_NE(section_index_, 0u);
return section_index_;
}
@@ -87,171 +100,303 @@ class ElfBuilder FINAL {
}
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)) {}
- 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;
+ Elf_Word GetSize() const OVERRIDE {
+ return (dynamics_.size() + 1 /* DT_NULL */) * sizeof(Elf_Dyn);
}
- // 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) {
+ }
+
+ 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());
}
- ElfRawSectionBuilder(const ElfRawSectionBuilder&) = default;
- ~ElfRawSectionBuilder() {}
+ 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) {
+ }
+
+ 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());
}
- ~ElfOatSectionBuilder() {}
+ private:
+ Elf_Word size_;
+ CodeOutput* code_output_;
+ };
- Elf_Word GetOffset() const {
- return offset_;
+ // 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 {
+ 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:
- // 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);
- }
+ // 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';
+ }
- // from bionic
- static inline unsigned elfhash(const char *_name) {
- const unsigned char *name = (const unsigned char *) _name;
- unsigned h = 0, g;
+ Elf_Word AddName(const std::string& name) {
+ Elf_Word offset = buffer_.size();
+ buffer_ += name;
+ buffer_ += '\0';
+ return offset;
+ }
- while (*name) {
- h = (h << 4) + *name++;
- g = h & 0xf0000000;
- h ^= g;
- h ^= g >> 24;
+ Elf_Word GetSize() const OVERRIDE {
+ return buffer_.size();
}
- return h;
- }
- class ElfSymtabBuilder FINAL : public ElfSectionBuilder {
+ 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 });
+ }
+
+ 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);
}
- 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) {
+ // 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) {
}
- ~ElfSymtabBuilder() {}
+ 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);
+ }
- std::vector<Elf_Word> GenerateHashContents() const {
+ 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 @@ class ElfBuilder FINAL {
//
// 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 @@ class ElfBuilder FINAL {
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 @@ class ElfBuilder FINAL {
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;
+ 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 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_;
+ // from bionic
+ static inline unsigned elfhash(const char *_name) {
+ const unsigned char *name = (const unsigned char *) _name;
+ unsigned h = 0, g;
- 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;
+ while (*name) {
+ h = (h << 4) + *name++;
+ g = h & 0xf0000000;
+ h ^= g;
+ h ^= g >> 24;
}
-
- return true;
+ return h;
}
- const char* GetDescription() const OVERRIDE {
- return dbg_name_.c_str();
- }
+ SymtabSection* symtab_;
- private:
- const std::string& dbg_name_;
- const void *data_;
- Elf_Word size_;
+ DISALLOW_COPY_AND_ASSIGN(HashSection);
};
- 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);
- }
-
- 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);
+ 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_;
- }
-
- ElfSymtabBuilder* GetSymtabBuilder() {
- return &symtab_builder_;
- }
+ OatSection* GetText() { return &text_; }
+ SymtabSection* GetSymtab() { return &symtab_; }
- 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 @@ class ElfBuilder FINAL {
// | 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 @@ class ElfBuilder FINAL {
// | 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 @@ class ElfBuilder FINAL {
// | .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 |
// +-------------------------+
-
- 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_++;
+ constexpr bool debug_logging_ = false;
+
+ // Create a list of all section which we want to write.
+ // This is the order in which they will be written.
+ std::vector<Section*> sections;
+ sections.push_back(&dynsym_);
+ sections.push_back(&dynstr_);
+ sections.push_back(&hash_);
+ 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);
- }
-
- // 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();
+ sections.push_back(&shstrtab_);
+ for (size_t i = 0; i < sections.size(); i++) {
+ // The first section index is 1. Index 0 is reserved for NULL.
+ // Section index is used for relative symbols and for section links.
+ sections[i]->SetSectionIndex(i + 1);
+ // Add section name to .shstrtab.
+ Elf_Word name_offset = shstrtab_.AddName(sections[i]->GetName());
+ sections[i]->GetHeader()->sh_name = name_offset;
+ }
+
+ // The running program does not have access to section headers
+ // and the loader is not supposed to use them either.
+ // The dynamic sections therefore replicates some of the layout
+ // information like the address and size of .rodata and .text.
+ // It also contains other metadata like the SONAME.
+ // The .dynamic section is found using the PT_DYNAMIC program header.
+ BuildDynsymSection();
+ BuildDynamicSection(elf_file->GetPath());
+
+ // We do not know the number of headers until the final stages of write.
+ // It is easiest to just reserve a fixed amount of space for them.
+ constexpr size_t kMaxProgramHeaders = 7;
+ constexpr size_t kProgramHeadersOffset = sizeof(Elf_Ehdr);
+ constexpr size_t kProgramHeadersSize = sizeof(Elf_Phdr) * kMaxProgramHeaders;
+
+ // 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;
}
- }
-
- // 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_++;
+ // 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;
}
- }
-
- // 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;
+ 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));
+
+ // 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_hdr = FindSection(".eh_frame_hdr");
+ if (eh_frame_hdr != nullptr) {
+ 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->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);
+
+ // Create the main ELF header.
+ Elf_Ehdr elf_header = MakeElfHeader(isa_);
+ elf_header.e_phoff = kProgramHeadersOffset;
+ elf_header.e_shoff = section_headers_offset;
+ elf_header.e_phnum = program_headers.size();
+ elf_header.e_shnum = section_headers.size();
+ elf_header.e_shstrndx = shstrtab_.GetSectionIndex();
+
+ // Write all headers and section content to the file.
+ // Depending on the implementations of Section::Write, this
+ // might be just memory copies or some more elaborate operations.
+ if (!WriteArray(elf_file, &elf_header, 1)) {
+ LOG(INFO) << "Failed to write the ELF header";
+ return false;
}
-
- // 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;
+ 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()";
}
}
-
- // 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);
+ 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;
+ }
- // 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;
- }
+ // Adds the given section to the builder. It does not take ownership.
+ void RegisterSection(Section* section) {
+ other_sections_.push_back(section);
+ }
- // 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();
-
- // 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)));
+ const Section* FindSection(const char* name) {
+ for (const auto* section : other_sections_) {
+ if (section->GetName() == name) {
+ return section;
+ }
}
+ return nullptr;
+ }
- // 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()));
+ private:
+ static bool SeekTo(File* elf_file, Elf_Word offset) {
+ DCHECK_LE(lseek(elf_file->Fd(), 0, SEEK_CUR), static_cast<off_t>(offset))
+ << "Seeking backwards";
+ if (static_cast<off_t>(offset) != lseek(elf_file->Fd(), offset, SEEK_SET)) {
+ PLOG(ERROR) << "Failed to seek in file " << elf_file->GetPath();
+ return false;
}
+ return true;
+ }
- if (!WriteOutFile(pieces)) {
- LOG(ERROR) << "Unable to write to file " << elf_file_->GetPath();
-
- STLDeleteElements(&pieces); // Have to manually clean pieces.
+ 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;
}
-
- STLDeleteElements(&pieces); // Have to manually clean pieces.
return true;
}
- // Adds the given raw section to the builder. It does not take ownership.
- void RegisterRawSection(ElfRawSectionBuilder* bld) {
- other_builders_.push_back(bld);
+ // 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;
}
- const ElfRawSectionBuilder* FindRawSection(const char* name) {
- for (const auto* other_builder : other_builders_) {
- if (other_builder->GetName() == name) {
- return other_builder;
- }
- }
- return nullptr;
+ // 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;
}
- private:
- void SetISA(InstructionSet isa) {
+ 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 @@ class ElfBuilder FINAL {
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);
- }
-
- // 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));
+ 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 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 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);
- 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;
- }
+ 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);
}
-
- // 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;
- }
+ 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);
}
- 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 9ff94e943a..d679468315 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 @@ bool ElfWriterQuick<ElfTypes>::Create(File* elf_file,
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 @@ void ElfWriterQuick<ElfTypes>::EncodeOatPatches(
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 @@ bool ElfWriterQuick<ElfTypes>::Write(
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();
-
- OatWriterWrapper wrapper(oat_writer);
-
+ const InstructionSet isa = compiler_driver_->GetInstructionSet();
+
+ // 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));
-
- 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);
- 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);
+ isa, rodata_size, &rodata_writer, text_size, &text_writer, bss_size));
+
+ // 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);
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);
- }
-
- // 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());
+ builder->RegisterSection(&oat_patches);
}
- 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 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writ
}
}
- 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 @@ static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder, OatWriter* oat_writ
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 d2d38da49f..15b4017816 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1112,13 +1112,14 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
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 @@ bool OatWriter::Write(OutputStream* out) {
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 @@ bool OatWriter::Write(OutputStream* out) {
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::WriteMaps(OutputStream* out, const size_t file_offset, size_t
}
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 8c79b44153..6f1b4ec15a 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -118,11 +118,8 @@ class OatWriter {
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 e1427425ae..b9a3d37584 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -76,41 +76,38 @@ const char* image_roots_descriptions_[] = {
"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();
+ bool Write(OutputStream* out) OVERRIDE {
+ const size_t rodata_size = oat_file_->GetOatHeader().GetExecutableOffset();
+ return out->WriteFully(oat_file_->Begin(), rodata_size);
+ }
- 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();
+ private:
+ const OatFile* oat_file_;
+ };
- elf_output_ = OS::CreateEmptyFile(output_name_.c_str());
+ class TextWriter FINAL : public CodeOutput {
+ public:
+ explicit TextWriter(const OatFile* oat_file) : oat_file_(oat_file) {}
- 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();
+ const uint8_t* text_begin = oat_file_->Begin() + rodata_size;
+ return out->WriteFully(text_begin, oat_file_->End() - text_begin);
}
- return true;
+ 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 @@ class OatSymbolizer FINAL : public CodeOutput {
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 @@ class OatSymbolizer FINAL : public CodeOutput {
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 @@ class OatSymbolizer FINAL : public CodeOutput {
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 @@ class OatSymbolizer FINAL : public CodeOutput {
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 @@ static int SymbolizeOat(const char* oat_filename, std::string& output_name) {
}
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;