diff options
author | 2016-02-17 17:46:30 +0000 | |
---|---|---|
committer | 2016-02-17 17:46:31 +0000 | |
commit | f0b04803ec4cdd8d76aadb6f02ae2511c46b20b5 (patch) | |
tree | 90390c57c73168102a2c1aaa3c6d828115e33b17 /compiler/elf_builder.h | |
parent | 9ee1f0c6a67729cabcf3697fc68fe4e98da55f64 (diff) | |
parent | 45724f9a0cc38dbb3071beb3eeab96499868b49c (diff) |
Merge "Revert "Allow method references across oat files for multi-image.""
Diffstat (limited to 'compiler/elf_builder.h')
-rw-r--r-- | compiler/elf_builder.h | 298 |
1 files changed, 74 insertions, 224 deletions
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index f7da609e5d..b673eeb3b6 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -86,24 +86,12 @@ class ElfBuilder FINAL { // Base class of all sections. class Section : public OutputStream { public: - Section(ElfBuilder<ElfTypes>* owner, - const std::string& name, - Elf_Word type, - Elf_Word flags, - const Section* link, - Elf_Word info, - Elf_Word align, - Elf_Word entsize) - : OutputStream(name), - owner_(owner), - header_(), - section_index_(0), - name_(name), - link_(link), - started_(false), - finished_(false), - phdr_flags_(PF_R), - phdr_type_(0) { + Section(ElfBuilder<ElfTypes>* owner, const std::string& name, + Elf_Word type, Elf_Word flags, const Section* link, + Elf_Word info, Elf_Word align, Elf_Word entsize) + : OutputStream(name), owner_(owner), header_(), + section_index_(0), name_(name), link_(link), + started_(false), finished_(false), phdr_flags_(PF_R), phdr_type_(0) { DCHECK_GE(align, 1u); header_.sh_type = type; header_.sh_flags = flags; @@ -240,84 +228,12 @@ class ElfBuilder FINAL { DISALLOW_COPY_AND_ASSIGN(Section); }; - class CachedSection : public Section { - public: - CachedSection(ElfBuilder<ElfTypes>* owner, - const std::string& name, - Elf_Word type, - Elf_Word flags, - const Section* link, - Elf_Word info, - Elf_Word align, - Elf_Word entsize) - : Section(owner, name, type, flags, link, info, align, entsize), cache_() { } - - Elf_Word Add(const void* data, size_t length) { - Elf_Word offset = cache_.size(); - const uint8_t* d = reinterpret_cast<const uint8_t*>(data); - cache_.insert(cache_.end(), d, d + length); - return offset; - } - - Elf_Word GetCacheSize() { - return cache_.size(); - } - - void Write() { - this->WriteFully(cache_.data(), cache_.size()); - cache_.clear(); - cache_.shrink_to_fit(); - } - - void WriteCachedSection() { - this->Start(); - Write(); - this->End(); - } - - private: - std::vector<uint8_t> cache_; - }; - - // Writer of .dynstr section. - class CachedStringSection FINAL : public CachedSection { - public: - CachedStringSection(ElfBuilder<ElfTypes>* owner, - const std::string& name, - Elf_Word flags, - Elf_Word align) - : CachedSection(owner, - name, - SHT_STRTAB, - flags, - /* link */ nullptr, - /* info */ 0, - align, - /* entsize */ 0) { } - - Elf_Word Add(const std::string& name) { - if (CachedSection::GetCacheSize() == 0u) { - DCHECK(name.empty()); - } - return CachedSection::Add(name.c_str(), name.length() + 1); - } - }; - - // Writer of .strtab and .shstrtab sections. + // Writer of .dynstr .strtab and .shstrtab sections. class StringSection FINAL : public Section { public: - StringSection(ElfBuilder<ElfTypes>* owner, - const std::string& name, - Elf_Word flags, - Elf_Word align) - : Section(owner, - name, - SHT_STRTAB, - flags, - /* link */ nullptr, - /* info */ 0, - align, - /* entsize */ 0), + StringSection(ElfBuilder<ElfTypes>* owner, const std::string& name, + Elf_Word flags, Elf_Word align) + : Section(owner, name, SHT_STRTAB, flags, nullptr, 0, align, 0), current_offset_(0) { } @@ -336,60 +252,42 @@ class ElfBuilder FINAL { }; // Writer of .dynsym and .symtab sections. - class SymbolSection FINAL : public CachedSection { + class SymbolSection FINAL : public Section { public: - SymbolSection(ElfBuilder<ElfTypes>* owner, - const std::string& name, - Elf_Word type, - Elf_Word flags, - Section* strtab) - : CachedSection(owner, - name, - type, - flags, - strtab, - /* info */ 0, - sizeof(Elf_Off), - sizeof(Elf_Sym)) { - // The symbol table always has to start with NULL symbol. - Elf_Sym null_symbol = Elf_Sym(); - CachedSection::Add(&null_symbol, sizeof(null_symbol)); + SymbolSection(ElfBuilder<ElfTypes>* owner, const std::string& name, + Elf_Word type, Elf_Word flags, StringSection* strtab) + : Section(owner, name, type, flags, strtab, 0, + sizeof(Elf_Off), sizeof(Elf_Sym)) { } // Buffer symbol for this section. It will be written later. // If the symbol's section is null, it will be considered absolute (SHN_ABS). // (we use this in JIT to reference code which is stored outside the debug ELF file) - void Add(Elf_Word name, - const Section* section, - Elf_Addr addr, - bool is_relative, - Elf_Word size, - uint8_t binding, - uint8_t type, - uint8_t other = 0) { - DCHECK(section != nullptr || !is_relative); - Elf_Addr abs_addr = addr + (is_relative ? section->GetAddress() : 0); - Elf_Word section_index = - (section != nullptr) ? section->GetSectionIndex() : static_cast<Elf_Word>(SHN_ABS); - Add(name, section_index, abs_addr, size, binding, type, other); - } - - void Add(Elf_Word name, - Elf_Word section_index, - Elf_Addr addr, - Elf_Word size, - uint8_t binding, - uint8_t type, - uint8_t other = 0) { + void Add(Elf_Word name, const Section* section, + Elf_Addr addr, bool is_relative, Elf_Word size, + uint8_t binding, uint8_t type, uint8_t other = 0) { Elf_Sym sym = Elf_Sym(); sym.st_name = name; - sym.st_value = addr; + sym.st_value = addr + (is_relative ? section->GetAddress() : 0); sym.st_size = size; sym.st_other = other; - sym.st_shndx = section_index; + sym.st_shndx = (section != nullptr ? section->GetSectionIndex() + : static_cast<Elf_Word>(SHN_ABS)); sym.st_info = (binding << 4) + (type & 0xf); - CachedSection::Add(&sym, sizeof(sym)); + symbols_.push_back(sym); + } + + void Write() { + // The symbol table always has to start with NULL symbol. + Elf_Sym null_symbol = Elf_Sym(); + this->WriteFully(&null_symbol, sizeof(null_symbol)); + this->WriteFully(symbols_.data(), symbols_.size() * sizeof(symbols_[0])); + symbols_.clear(); + symbols_.shrink_to_fit(); } + + private: + std::vector<Elf_Sym> symbols_; }; ElfBuilder(InstructionSet isa, OutputStream* output) @@ -411,8 +309,6 @@ class ElfBuilder FINAL { debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0), shstrtab_(this, ".shstrtab", 0, 1), started_(false), - write_program_headers_(false), - loaded_size_(0u), virtual_address_(0) { text_.phdr_flags_ = PF_R | PF_X; bss_.phdr_flags_ = PF_R | PF_W; @@ -484,14 +380,6 @@ class ElfBuilder FINAL { void End() { DCHECK(started_); - // Note: loaded_size_ == 0 for tests that don't write .rodata, .text, .bss, - // .dynstr, dynsym, .hash and .dynamic. These tests should not read loaded_size_. - // TODO: Either refactor the .eh_frame creation so that it counts towards loaded_size_, - // or remove all support for .eh_frame. (The currently unused .eh_frame counts towards - // the virtual_address_ but we don't consider it for loaded_size_.) - CHECK(loaded_size_ == 0 || loaded_size_ == RoundUp(virtual_address_, kPageSize)) - << loaded_size_ << " " << virtual_address_; - // Write section names and finish the section headers. shstrtab_.Start(); shstrtab_.Write(""); @@ -546,58 +434,45 @@ class ElfBuilder FINAL { // 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. - void PrepareDynamicSection(const std::string& elf_file_path, - Elf_Word rodata_size, - Elf_Word text_size, - Elf_Word bss_size) { + void WriteDynamicSection(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); } - // Calculate addresses of .text, .bss and .dynstr. - DCHECK_EQ(rodata_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); - DCHECK_EQ(text_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); - DCHECK_EQ(bss_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); - DCHECK_EQ(dynstr_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); - Elf_Word rodata_address = rodata_.GetAddress(); - Elf_Word text_address = RoundUp(rodata_address + rodata_size, kPageSize); - Elf_Word bss_address = RoundUp(text_address + text_size, kPageSize); - Elf_Word dynstr_address = RoundUp(bss_address + bss_size, kPageSize); - - // Cache .dynstr, .dynsym and .hash data. - dynstr_.Add(""); // dynstr should start with empty string. - Elf_Word rodata_index = rodata_.GetSectionIndex(); - Elf_Word oatdata = dynstr_.Add("oatdata"); - dynsym_.Add(oatdata, rodata_index, rodata_address, rodata_size, STB_GLOBAL, STT_OBJECT); - if (text_size != 0u) { - Elf_Word text_index = rodata_index + 1u; - Elf_Word oatexec = dynstr_.Add("oatexec"); - dynsym_.Add(oatexec, text_index, text_address, text_size, STB_GLOBAL, STT_OBJECT); - Elf_Word oatlastword = dynstr_.Add("oatlastword"); - Elf_Word oatlastword_address = text_address + text_size - 4; - dynsym_.Add(oatlastword, text_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT); - } else if (rodata_size != 0) { + dynstr_.Start(); + dynstr_.Write(""); // dynstr should start with empty string. + dynsym_.Add(dynstr_.Write("oatdata"), &rodata_, 0, true, + rodata_.GetSize(), STB_GLOBAL, STT_OBJECT); + if (text_.GetSize() != 0u) { + dynsym_.Add(dynstr_.Write("oatexec"), &text_, 0, true, + text_.GetSize(), STB_GLOBAL, STT_OBJECT); + dynsym_.Add(dynstr_.Write("oatlastword"), &text_, text_.GetSize() - 4, + true, 4, STB_GLOBAL, STT_OBJECT); + } else if (rodata_.GetSize() != 0) { // rodata_ can be size 0 for dwarf_test. - Elf_Word oatlastword = dynstr_.Add("oatlastword"); - Elf_Word oatlastword_address = rodata_address + rodata_size - 4; - dynsym_.Add(oatlastword, rodata_index, oatlastword_address, 4, STB_GLOBAL, STT_OBJECT); + dynsym_.Add(dynstr_.Write("oatlastword"), &rodata_, rodata_.GetSize() - 4, + true, 4, STB_GLOBAL, STT_OBJECT); } - if (bss_size != 0u) { - Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u); - Elf_Word oatbss = dynstr_.Add("oatbss"); - dynsym_.Add(oatbss, bss_index, bss_address, bss_size, STB_GLOBAL, STT_OBJECT); - Elf_Word oatbsslastword = dynstr_.Add("oatbsslastword"); - Elf_Word bsslastword_address = bss_address + bss_size - 4; - dynsym_.Add(oatbsslastword, bss_index, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT); + if (bss_.finished_) { + dynsym_.Add(dynstr_.Write("oatbss"), &bss_, + 0, true, bss_.GetSize(), STB_GLOBAL, STT_OBJECT); + dynsym_.Add(dynstr_.Write("oatbsslastword"), &bss_, + bss_.GetSize() - 4, true, 4, STB_GLOBAL, STT_OBJECT); } - Elf_Word soname_offset = dynstr_.Add(soname); + Elf_Word soname_offset = dynstr_.Write(soname); + dynstr_.End(); + + dynsym_.Start(); + dynsym_.Write(); + dynsym_.End(); // We do not really need a hash-table since there is so few entries. // However, the hash-table is the only way the linker can actually // determine the number of symbols in .dynsym so it is required. - int count = dynsym_.GetCacheSize() / sizeof(Elf_Sym); // Includes NULL. + hash_.Start(); + int count = dynsym_.GetSize() / sizeof(Elf_Sym); // Includes NULL. std::vector<Elf_Word> hash; hash.push_back(1); // Number of buckets. hash.push_back(count); // Number of chains. @@ -609,44 +484,21 @@ class ElfBuilder FINAL { hash.push_back(i + 1); // Each symbol points to the next one. } hash.push_back(0); // Last symbol terminates the chain. - hash_.Add(hash.data(), hash.size() * sizeof(hash[0])); - - // Calculate addresses of .dynsym, .hash and .dynamic. - DCHECK_EQ(dynstr_.header_.sh_flags, dynsym_.header_.sh_flags); - DCHECK_EQ(dynsym_.header_.sh_flags, hash_.header_.sh_flags); - Elf_Word dynsym_address = - RoundUp(dynstr_address + dynstr_.GetCacheSize(), dynsym_.header_.sh_addralign); - Elf_Word hash_address = - RoundUp(dynsym_address + dynsym_.GetCacheSize(), hash_.header_.sh_addralign); - DCHECK_EQ(dynamic_.header_.sh_addralign, static_cast<Elf_Word>(kPageSize)); - Elf_Word dynamic_address = RoundUp(hash_address + dynsym_.GetCacheSize(), kPageSize); + hash_.WriteFully(hash.data(), hash.size() * sizeof(hash[0])); + hash_.End(); + dynamic_.Start(); Elf_Dyn dyns[] = { - { DT_HASH, { hash_address } }, - { DT_STRTAB, { dynstr_address } }, - { DT_SYMTAB, { dynsym_address } }, + { DT_HASH, { hash_.GetAddress() } }, + { DT_STRTAB, { dynstr_.GetAddress() } }, + { DT_SYMTAB, { dynsym_.GetAddress() } }, { DT_SYMENT, { sizeof(Elf_Sym) } }, - { DT_STRSZ, { dynstr_.GetCacheSize() } }, + { DT_STRSZ, { dynstr_.GetSize() } }, { DT_SONAME, { soname_offset } }, { DT_NULL, { 0 } }, }; - dynamic_.Add(&dyns, sizeof(dyns)); - - loaded_size_ = RoundUp(dynamic_address + dynamic_.GetCacheSize(), kPageSize); - } - - void WriteDynamicSection() { - dynstr_.WriteCachedSection(); - dynsym_.WriteCachedSection(); - hash_.WriteCachedSection(); - dynamic_.WriteCachedSection(); - - CHECK_EQ(loaded_size_, RoundUp(dynamic_.GetAddress() + dynamic_.GetSize(), kPageSize)); - } - - Elf_Word GetLoadedSize() { - CHECK_NE(loaded_size_, 0u); - return loaded_size_; + dynamic_.WriteFully(&dyns, sizeof(dyns)); + dynamic_.End(); } // Returns true if all writes and seeks on the output stream succeeded. @@ -824,10 +676,10 @@ class ElfBuilder FINAL { Section rodata_; Section text_; Section bss_; - CachedStringSection dynstr_; + StringSection dynstr_; SymbolSection dynsym_; - CachedSection hash_; - CachedSection dynamic_; + Section hash_; + Section dynamic_; Section eh_frame_; Section eh_frame_hdr_; StringSection strtab_; @@ -842,14 +694,12 @@ class ElfBuilder FINAL { std::vector<Section*> sections_; bool started_; - bool write_program_headers_; - - // The size of the memory taken by the ELF file when loaded. - size_t loaded_size_; // Used for allocation of virtual address space. Elf_Addr virtual_address_; + size_t write_program_headers_; + DISALLOW_COPY_AND_ASSIGN(ElfBuilder); }; |