/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_ELF_BUILDER_H_ #define ART_COMPILER_ELF_BUILDER_H_ #include #include "arch/instruction_set.h" #include "base/bit_utils.h" #include "base/unix_file/fd_file.h" #include "buffered_output_stream.h" #include "elf_utils.h" #include "file_output_stream.h" namespace art { class CodeOutput { public: virtual bool Write(OutputStream* out) = 0; virtual ~CodeOutput() {} }; // Writes ELF file. // The main complication is that the sections often want to reference // each other. We solve this by writing the ELF file in two stages: // * Sections are asked about their size, and overall layout is calculated. // * Sections do the actual writes which may use offsets of other sections. template class ElfBuilder FINAL { public: using Elf_Addr = typename ElfTypes::Addr; using Elf_Off = typename ElfTypes::Off; using Elf_Word = typename ElfTypes::Word; using Elf_Sword = typename ElfTypes::Sword; using Elf_Ehdr = typename ElfTypes::Ehdr; using Elf_Shdr = typename ElfTypes::Shdr; using Elf_Sym = typename ElfTypes::Sym; using Elf_Phdr = typename ElfTypes::Phdr; using Elf_Dyn = typename ElfTypes::Dyn; // Base class of all sections. class Section { public: Section(const std::string& name, Elf_Word type, Elf_Word flags, const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize) : header_(), section_index_(0), name_(name), link_(link) { header_.sh_type = type; header_.sh_flags = flags; header_.sh_info = info; header_.sh_addralign = align; header_.sh_entsize = entsize; } virtual ~Section() {} // Returns the size of the content of this section. It is used to // calculate file offsets of all sections before doing any writes. virtual Elf_Word GetSize() const = 0; // Write the content of this section to the given file. // This must write exactly the number of bytes returned by GetSize(). // Offsets of all sections are known when this method is called. virtual bool Write(File* elf_file) = 0; Elf_Word GetLink() const { return (link_ != nullptr) ? link_->GetSectionIndex() : 0; } const Elf_Shdr* GetHeader() const { return &header_; } Elf_Shdr* GetHeader() { return &header_; } Elf_Word GetSectionIndex() const { DCHECK_NE(section_index_, 0u); return section_index_; } void SetSectionIndex(Elf_Word section_index) { section_index_ = section_index; } const std::string& GetName() const { return name_; } private: Elf_Shdr header_; Elf_Word section_index_; const std::string name_; const Section* const link_; DISALLOW_COPY_AND_ASSIGN(Section); }; // Writer of .dynamic section. class DynamicSection FINAL : public Section { public: void AddDynamicTag(Elf_Sword tag, Elf_Word value, const Section* section) { DCHECK_NE(tag, static_cast(DT_NULL)); dynamics_.push_back({tag, value, section}); } DynamicSection(const std::string& name, Section* link) : Section(name, SHT_DYNAMIC, SHF_ALLOC, link, 0, kPageSize, sizeof(Elf_Dyn)) {} Elf_Word GetSize() const OVERRIDE { return (dynamics_.size() + 1 /* DT_NULL */) * sizeof(Elf_Dyn); } bool Write(File* elf_file) OVERRIDE { std::vector buffer; buffer.reserve(dynamics_.size() + 1u); for (const ElfDynamicState& it : dynamics_) { if (it.section_ != nullptr) { // We are adding an address relative to a section. buffer.push_back( {it.tag_, {it.value_ + it.section_->GetHeader()->sh_addr}}); } else { buffer.push_back({it.tag_, {it.value_}}); } } buffer.push_back({DT_NULL, {0}}); return WriteArray(elf_file, buffer.data(), buffer.size()); } private: struct ElfDynamicState { Elf_Sword tag_; Elf_Word value_; const Section* section_; }; std::vector dynamics_; }; using PatchFn = void (*)(const std::vector& patch_locations, Elf_Addr buffer_address, Elf_Addr base_address, std::vector* buffer); // Section with content based on simple memory buffer. // The buffer can be optionally patched before writing. class RawSection FINAL : public Section { public: RawSection(const std::string& name, Elf_Word type, Elf_Word flags, const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize, PatchFn patch = nullptr, const Section* patch_base_section = nullptr) : Section(name, type, flags, link, info, align, entsize), patched_(false), patch_(patch), patch_base_section_(patch_base_section) { } RawSection(const std::string& name, Elf_Word type) : RawSection(name, type, 0, nullptr, 0, 1, 0, nullptr, nullptr) { } Elf_Word GetSize() const OVERRIDE { return buffer_.size(); } bool Write(File* elf_file) OVERRIDE { if (!patch_locations_.empty()) { DCHECK(!patched_); // Do not patch twice. DCHECK(patch_ != nullptr); DCHECK(patch_base_section_ != nullptr); patch_(patch_locations_, this->GetHeader()->sh_addr, patch_base_section_->GetHeader()->sh_addr, &buffer_); patched_ = true; } return WriteArray(elf_file, buffer_.data(), buffer_.size()); } bool IsEmpty() const { return buffer_.size() == 0; } std::vector* GetBuffer() { return &buffer_; } void SetBuffer(const std::vector& buffer) { buffer_ = buffer; } std::vector* GetPatchLocations() { return &patch_locations_; } private: std::vector buffer_; std::vector patch_locations_; bool patched_; // User-provided function to do the actual patching. PatchFn patch_; // The section that we patch against (usually .text). const Section* patch_base_section_; }; // Writer of .rodata section or .text section. // The write is done lazily using the provided CodeOutput. class OatSection FINAL : public Section { public: OatSection(const std::string& name, Elf_Word type, Elf_Word flags, const Section* link, Elf_Word info, Elf_Word align, Elf_Word entsize, Elf_Word size, CodeOutput* code_output) : Section(name, type, flags, link, info, align, entsize), size_(size), code_output_(code_output) { } Elf_Word GetSize() const OVERRIDE { return size_; } bool Write(File* elf_file) OVERRIDE { // The BufferedOutputStream class contains the buffer as field, // therefore it is too big to allocate on the stack. std::unique_ptr output_stream( new BufferedOutputStream(new FileOutputStream(elf_file))); return code_output_->Write(output_stream.get()); } private: Elf_Word size_; CodeOutput* code_output_; }; // Writer of .bss section. class NoBitsSection FINAL : public Section { public: NoBitsSection(const std::string& name, Elf_Word size) : Section(name, SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0), size_(size) { } Elf_Word GetSize() const OVERRIDE { return size_; } bool Write(File* elf_file ATTRIBUTE_UNUSED) OVERRIDE { LOG(ERROR) << "This section should not be written to the ELF file"; return false; } private: Elf_Word size_; }; // Writer of .dynstr .strtab and .shstrtab sections. class StrtabSection FINAL : public Section { public: StrtabSection(const std::string& name, Elf_Word flags) : Section(name, SHT_STRTAB, flags, nullptr, 0, 1, 0) { buffer_.reserve(4 * KB); // The first entry of strtab must be empty string. buffer_ += '\0'; } Elf_Word AddName(const std::string& name) { Elf_Word offset = buffer_.size(); buffer_ += name; buffer_ += '\0'; return offset; } Elf_Word GetSize() const OVERRIDE { return buffer_.size(); } bool Write(File* elf_file) OVERRIDE { return WriteArray(elf_file, buffer_.data(), buffer_.size()); } private: std::string buffer_; }; class HashSection; // Writer of .dynsym and .symtab sections. class SymtabSection FINAL : public Section { public: // Add a symbol with given name to this symtab. The symbol refers to // 'relative_addr' within the given section and has the given attributes. void AddSymbol(const std::string& name, const Section* section, Elf_Addr addr, bool is_relative, Elf_Word size, uint8_t binding, uint8_t type, uint8_t other = 0) { CHECK(section != nullptr); Elf_Word name_idx = strtab_->AddName(name); symbols_.push_back({ name, section, addr, size, is_relative, MakeStInfo(binding, type), other, name_idx }); } SymtabSection(const std::string& name, Elf_Word type, Elf_Word flags, StrtabSection* strtab) : Section(name, type, flags, strtab, 0, sizeof(Elf_Off), sizeof(Elf_Sym)), strtab_(strtab) { } bool IsEmpty() const { return symbols_.empty(); } Elf_Word GetSize() const OVERRIDE { return (1 /* NULL */ + symbols_.size()) * sizeof(Elf_Sym); } bool Write(File* elf_file) OVERRIDE { std::vector buffer; buffer.reserve(1u + symbols_.size()); buffer.push_back(Elf_Sym()); // NULL. for (const ElfSymbolState& it : symbols_) { Elf_Sym sym = Elf_Sym(); sym.st_name = it.name_idx_; if (it.is_relative_) { sym.st_value = it.addr_ + it.section_->GetHeader()->sh_addr; } else { sym.st_value = it.addr_; } sym.st_size = it.size_; sym.st_other = it.other_; sym.st_shndx = it.section_->GetSectionIndex(); sym.st_info = it.info_; buffer.push_back(sym); } return WriteArray(elf_file, buffer.data(), buffer.size()); } private: struct ElfSymbolState { const std::string name_; const Section* section_; Elf_Addr addr_; Elf_Word size_; bool is_relative_; uint8_t info_; uint8_t other_; Elf_Word name_idx_; // index in the strtab. }; static inline constexpr uint8_t MakeStInfo(uint8_t binding, uint8_t type) { return ((binding) << 4) + ((type) & 0xf); } // The symbols in the same order they will be in the symbol table. std::vector symbols_; StrtabSection* strtab_; friend class HashSection; }; // TODO: Consider removing. // We use it only for the dynsym section which has only 5 symbols. // We do not use it for symtab, and we probably do not have to // since we use those symbols only to print backtraces. class HashSection FINAL : public Section { public: HashSection(const std::string& name, Elf_Word flags, SymtabSection* symtab) : Section(name, SHT_HASH, flags, symtab, 0, sizeof(Elf_Word), sizeof(Elf_Word)), symtab_(symtab) { } Elf_Word GetSize() const OVERRIDE { Elf_Word nbuckets = GetNumBuckets(); Elf_Word chain_size = symtab_->symbols_.size() + 1 /* NULL */; return (2 /* header */ + nbuckets + chain_size) * sizeof(Elf_Word); } bool Write(File* const elf_file) OVERRIDE { // Here is how The ELF hash table works. // There are 3 arrays to worry about. // * The symbol table where the symbol information is. // * The bucket array which is an array of indexes into the symtab and chain. // * The chain array which is also an array of indexes into the symtab and chain. // // Lets say the state is something like this. // +--------+ +--------+ +-----------+ // | symtab | | bucket | | chain | // | null | | 1 | | STN_UNDEF | // | | | 4 | | 2 | // | | | | | 5 | // | | | | | STN_UNDEF | // | | | | | 3 | // | | | | | STN_UNDEF | // +--------+ +--------+ +-----------+ // // The lookup process (in python psudocode) is // // def GetSym(name): // # NB STN_UNDEF == 0 // indx = bucket[elfhash(name) % num_buckets] // while indx != STN_UNDEF: // if GetSymbolName(symtab[indx]) == name: // return symtab[indx] // indx = chain[indx] // return SYMBOL_NOT_FOUND // // Between bucket and chain arrays every symtab index must be present exactly // once (except for STN_UNDEF, which must be present 1 + num_bucket times). const auto& symbols = symtab_->symbols_; // Select number of buckets. // This is essentially arbitrary. Elf_Word nbuckets = GetNumBuckets(); // 1 is for the implicit NULL symbol. Elf_Word chain_size = (symbols.size() + 1); std::vector hash; hash.push_back(nbuckets); hash.push_back(chain_size); uint32_t bucket_offset = hash.size(); uint32_t chain_offset = bucket_offset + nbuckets; hash.resize(hash.size() + nbuckets + chain_size, 0); Elf_Word* buckets = hash.data() + bucket_offset; Elf_Word* chain = hash.data() + chain_offset; // Set up the actual hash table. for (Elf_Word i = 0; i < symbols.size(); i++) { // Add 1 since we need to have the null symbol that is not in the symbols // list. Elf_Word index = i + 1; Elf_Word hash_val = static_cast(elfhash(symbols[i].name_.c_str())) % nbuckets; if (buckets[hash_val] == 0) { buckets[hash_val] = index; } else { hash_val = buckets[hash_val]; CHECK_LT(hash_val, chain_size); while (chain[hash_val] != 0) { hash_val = chain[hash_val]; CHECK_LT(hash_val, chain_size); } chain[hash_val] = index; // Check for loops. Works because if this is non-empty then there must be // another cell which already contains the same symbol index as this one, // which means some symbol has more then one name, which isn't allowed. CHECK_EQ(chain[index], static_cast(0)); } } return WriteArray(elf_file, hash.data(), hash.size()); } private: Elf_Word GetNumBuckets() const { const auto& symbols = symtab_->symbols_; if (symbols.size() < 8) { return 2; } else if (symbols.size() < 32) { return 4; } else if (symbols.size() < 256) { return 16; } else { // Have about 32 ids per bucket. return RoundUp(symbols.size()/32, 2); } } // from bionic static inline unsigned elfhash(const char *_name) { const unsigned char *name = (const unsigned char *) _name; unsigned h = 0, g; while (*name) { h = (h << 4) + *name++; g = h & 0xf0000000; h ^= g; h ^= g >> 24; } return h; } SymtabSection* symtab_; DISALLOW_COPY_AND_ASSIGN(HashSection); }; ElfBuilder(InstructionSet isa, Elf_Word rodata_size, CodeOutput* rodata_writer, Elf_Word text_size, CodeOutput* text_writer, Elf_Word bss_size) : isa_(isa), dynstr_(".dynstr", SHF_ALLOC), dynsym_(".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_), hash_(".hash", SHF_ALLOC, &dynsym_), rodata_(".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0, rodata_size, rodata_writer), text_(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0, text_size, text_writer), bss_(".bss", bss_size), dynamic_(".dynamic", &dynstr_), strtab_(".strtab", 0), symtab_(".symtab", SHT_SYMTAB, 0, &strtab_), shstrtab_(".shstrtab", 0) { } ~ElfBuilder() {} OatSection* GetText() { return &text_; } SymtabSection* GetSymtab() { return &symtab_; } bool Write(File* elf_file) { // Since the .text section of an oat file contains relative references to .rodata // and (optionally) .bss, we keep these 2 or 3 sections together. This creates // a non-traditional layout where the .bss section is mapped independently of the // .dynamic section and needs its own program header with LOAD RW. // // The basic layout of the elf file. Order may be different in final output. // +-------------------------+ // | Elf_Ehdr | // +-------------------------+ // | Elf_Phdr PHDR | // | Elf_Phdr LOAD R | .dynsym .dynstr .hash .rodata // | Elf_Phdr LOAD R X | .text // | Elf_Phdr LOAD RW | .bss (Optional) // | Elf_Phdr LOAD RW | .dynamic // | Elf_Phdr DYNAMIC | .dynamic // | Elf_Phdr LOAD R | .eh_frame .eh_frame_hdr // | Elf_Phdr EH_FRAME R | .eh_frame_hdr // +-------------------------+ // | .dynsym | // | Elf_Sym STN_UNDEF | // | Elf_Sym oatdata | // | Elf_Sym oatexec | // | Elf_Sym oatlastword | // | Elf_Sym oatbss | (Optional) // | Elf_Sym oatbsslastword | (Optional) // +-------------------------+ // | .dynstr | // | names for .dynsym | // +-------------------------+ // | .hash | // | hashtable for dynsym | // +-------------------------+ // | .rodata | // | oatdata..oatexec-4 | // +-------------------------+ // | .text | // | oatexec..oatlastword | // +-------------------------+ // | .dynamic | // | Elf_Dyn DT_HASH | // | Elf_Dyn DT_STRTAB | // | Elf_Dyn DT_SYMTAB | // | Elf_Dyn DT_SYMENT | // | Elf_Dyn DT_STRSZ | // | Elf_Dyn DT_SONAME | // | Elf_Dyn DT_NULL | // +-------------------------+ (Optional) // | .symtab | (Optional) // | program symbols | (Optional) // +-------------------------+ (Optional) // | .strtab | (Optional) // | names for .symtab | (Optional) // +-------------------------+ (Optional) // | .eh_frame | (Optional) // +-------------------------+ (Optional) // | .eh_frame_hdr | (Optional) // +-------------------------+ (Optional) // | .debug_info | (Optional) // +-------------------------+ (Optional) // | .debug_abbrev | (Optional) // +-------------------------+ (Optional) // | .debug_str | (Optional) // +-------------------------+ (Optional) // | .debug_line | (Optional) // +-------------------------+ // | .shstrtab | // | names of sections | // +-------------------------+ // | Elf_Shdr null | // | Elf_Shdr .dynsym | // | Elf_Shdr .dynstr | // | Elf_Shdr .hash | // | Elf_Shdr .rodata | // | Elf_Shdr .text | // | Elf_Shdr .bss | (Optional) // | Elf_Shdr .dynamic | // | Elf_Shdr .symtab | (Optional) // | Elf_Shdr .strtab | (Optional) // | Elf_Shdr .eh_frame | (Optional) // | Elf_Shdr .eh_frame_hdr | (Optional) // | Elf_Shdr .debug_info | (Optional) // | Elf_Shdr .debug_abbrev | (Optional) // | Elf_Shdr .debug_str | (Optional) // | Elf_Shdr .debug_line | (Optional) // | Elf_Shdr .oat_patches | (Optional) // | Elf_Shdr .shstrtab | // +-------------------------+ constexpr bool debug_logging_ = false; // Create a list of all section which we want to write. // This is the order in which they will be written. std::vector sections; sections.push_back(&dynsym_); sections.push_back(&dynstr_); sections.push_back(&hash_); sections.push_back(&rodata_); sections.push_back(&text_); if (bss_.GetSize() != 0u) { sections.push_back(&bss_); } sections.push_back(&dynamic_); if (!symtab_.IsEmpty()) { sections.push_back(&symtab_); sections.push_back(&strtab_); } for (Section* section : other_sections_) { sections.push_back(section); } sections.push_back(&shstrtab_); for (size_t i = 0; i < sections.size(); i++) { // The first section index is 1. Index 0 is reserved for NULL. // Section index is used for relative symbols and for section links. sections[i]->SetSectionIndex(i + 1); // Add section name to .shstrtab. Elf_Word name_offset = shstrtab_.AddName(sections[i]->GetName()); sections[i]->GetHeader()->sh_name = name_offset; } // The running program does not have access to section headers // and the loader is not supposed to use them either. // The dynamic sections therefore replicates some of the layout // information like the address and size of .rodata and .text. // It also contains other metadata like the SONAME. // The .dynamic section is found using the PT_DYNAMIC program header. BuildDynsymSection(); BuildDynamicSection(elf_file->GetPath()); // We do not know the number of headers until the final stages of write. // It is easiest to just reserve a fixed amount of space for them. constexpr size_t kMaxProgramHeaders = 8; constexpr size_t kProgramHeadersOffset = sizeof(Elf_Ehdr); // Layout of all sections - determine the final file offsets and addresses. // This must be done after we have built all sections and know their size. Elf_Off file_offset = kProgramHeadersOffset + sizeof(Elf_Phdr) * kMaxProgramHeaders; Elf_Addr load_address = file_offset; std::vector section_headers; section_headers.reserve(1u + sections.size()); section_headers.push_back(Elf_Shdr()); // NULL at index 0. for (auto* section : sections) { Elf_Shdr* header = section->GetHeader(); Elf_Off alignment = header->sh_addralign > 0 ? header->sh_addralign : 1; header->sh_size = section->GetSize(); header->sh_link = section->GetLink(); // Allocate memory for the section in the file. if (header->sh_type != SHT_NOBITS) { header->sh_offset = RoundUp(file_offset, alignment); file_offset = header->sh_offset + header->sh_size; } // Allocate memory for the section during program execution. if ((header->sh_flags & SHF_ALLOC) != 0) { header->sh_addr = RoundUp(load_address, alignment); load_address = header->sh_addr + header->sh_size; } if (debug_logging_) { LOG(INFO) << "Section " << section->GetName() << ":" << std::hex << " offset=0x" << header->sh_offset << " addr=0x" << header->sh_addr << " size=0x" << header->sh_size; } // Collect section headers into continuous array for convenience. section_headers.push_back(*header); } Elf_Off section_headers_offset = RoundUp(file_offset, sizeof(Elf_Off)); // Create program headers now that we know the layout of the whole file. // Each segment contains one or more sections which are mapped together. // Not all sections are mapped during the execution of the program. // PT_LOAD does the mapping. Other PT_* types allow the program to locate // interesting parts of memory and their addresses overlap with PT_LOAD. std::vector program_headers; program_headers.push_back(Elf_Phdr()); // Placeholder for PT_PHDR. // Create the main LOAD R segment which spans all sections up to .rodata. const Elf_Shdr* rodata = rodata_.GetHeader(); program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R, 0, rodata->sh_offset + rodata->sh_size, rodata->sh_addralign)); program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_X, text_)); if (bss_.GetHeader()->sh_size != 0u) { program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_W, bss_)); } program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R | PF_W, dynamic_)); program_headers.push_back(MakeProgramHeader(PT_DYNAMIC, PF_R | PF_W, dynamic_)); const Section* eh_frame = FindSection(".eh_frame"); if (eh_frame != nullptr) { program_headers.push_back(MakeProgramHeader(PT_LOAD, PF_R, *eh_frame)); const Section* eh_frame_hdr = FindSection(".eh_frame_hdr"); if (eh_frame_hdr != nullptr) { // Check layout: eh_frame is before eh_frame_hdr and there is no gap. CHECK_LE(eh_frame->GetHeader()->sh_offset, eh_frame_hdr->GetHeader()->sh_offset); CHECK_EQ(eh_frame->GetHeader()->sh_offset + eh_frame->GetHeader()->sh_size, eh_frame_hdr->GetHeader()->sh_offset); // Extend the PT_LOAD of .eh_frame to include the .eh_frame_hdr as well. program_headers.back().p_filesz += eh_frame_hdr->GetHeader()->sh_size; program_headers.back().p_memsz += eh_frame_hdr->GetHeader()->sh_size; program_headers.push_back(MakeProgramHeader(PT_GNU_EH_FRAME, PF_R, *eh_frame_hdr)); } } DCHECK_EQ(program_headers[0].p_type, 0u); // Check placeholder. program_headers[0] = MakeProgramHeader(PT_PHDR, PF_R, kProgramHeadersOffset, program_headers.size() * sizeof(Elf_Phdr), sizeof(Elf_Off)); CHECK_LE(program_headers.size(), kMaxProgramHeaders); // Create the main ELF header. Elf_Ehdr elf_header = MakeElfHeader(isa_); elf_header.e_phoff = kProgramHeadersOffset; elf_header.e_shoff = section_headers_offset; elf_header.e_phnum = program_headers.size(); elf_header.e_shnum = section_headers.size(); elf_header.e_shstrndx = shstrtab_.GetSectionIndex(); // Write all headers and section content to the file. // Depending on the implementations of Section::Write, this // might be just memory copies or some more elaborate operations. if (!WriteArray(elf_file, &elf_header, 1)) { LOG(INFO) << "Failed to write the ELF header"; return false; } if (!WriteArray(elf_file, program_headers.data(), program_headers.size())) { LOG(INFO) << "Failed to write the program headers"; return false; } for (Section* section : sections) { const Elf_Shdr* header = section->GetHeader(); if (header->sh_type != SHT_NOBITS) { if (!SeekTo(elf_file, header->sh_offset) || !section->Write(elf_file)) { LOG(INFO) << "Failed to write section " << section->GetName(); return false; } Elf_Word current_offset = lseek(elf_file->Fd(), 0, SEEK_CUR); CHECK_EQ(current_offset, header->sh_offset + header->sh_size) << "The number of bytes written does not match GetSize()"; } } if (!SeekTo(elf_file, section_headers_offset) || !WriteArray(elf_file, section_headers.data(), section_headers.size())) { LOG(INFO) << "Failed to write the section headers"; return false; } return true; } // Adds the given section to the builder. It does not take ownership. void RegisterSection(Section* section) { other_sections_.push_back(section); } const Section* FindSection(const char* name) { for (const auto* section : other_sections_) { if (section->GetName() == name) { return section; } } return nullptr; } private: static bool SeekTo(File* elf_file, Elf_Word offset) { DCHECK_LE(lseek(elf_file->Fd(), 0, SEEK_CUR), static_cast(offset)) << "Seeking backwards"; if (static_cast(offset) != lseek(elf_file->Fd(), offset, SEEK_SET)) { PLOG(ERROR) << "Failed to seek in file " << elf_file->GetPath(); return false; } return true; } template static bool WriteArray(File* elf_file, const T* data, size_t count) { if (count != 0) { DCHECK(data != nullptr); if (!elf_file->WriteFully(data, count * sizeof(T))) { PLOG(ERROR) << "Failed to write to file " << elf_file->GetPath(); return false; } } return true; } // Helper - create segment header based on memory range. static Elf_Phdr MakeProgramHeader(Elf_Word type, Elf_Word flags, Elf_Off offset, Elf_Word size, Elf_Word align) { Elf_Phdr phdr = Elf_Phdr(); phdr.p_type = type; phdr.p_flags = flags; phdr.p_offset = offset; phdr.p_vaddr = offset; phdr.p_paddr = offset; phdr.p_filesz = size; phdr.p_memsz = size; phdr.p_align = align; return phdr; } // Helper - create segment header based on section header. static Elf_Phdr MakeProgramHeader(Elf_Word type, Elf_Word flags, const Section& section) { const Elf_Shdr* shdr = section.GetHeader(); // Only run-time allocated sections should be in segment headers. CHECK_NE(shdr->sh_flags & SHF_ALLOC, 0u); Elf_Phdr phdr = Elf_Phdr(); phdr.p_type = type; phdr.p_flags = flags; phdr.p_offset = shdr->sh_offset; phdr.p_vaddr = shdr->sh_addr; phdr.p_paddr = shdr->sh_addr; phdr.p_filesz = shdr->sh_type != SHT_NOBITS ? shdr->sh_size : 0u; phdr.p_memsz = shdr->sh_size; phdr.p_align = shdr->sh_addralign; return phdr; } static Elf_Ehdr MakeElfHeader(InstructionSet isa) { Elf_Ehdr elf_header = Elf_Ehdr(); switch (isa) { case kArm: // Fall through. case kThumb2: { elf_header.e_machine = EM_ARM; elf_header.e_flags = EF_ARM_EABI_VER5; break; } case kArm64: { elf_header.e_machine = EM_AARCH64; elf_header.e_flags = 0; break; } case kX86: { elf_header.e_machine = EM_386; elf_header.e_flags = 0; break; } case kX86_64: { elf_header.e_machine = EM_X86_64; elf_header.e_flags = 0; break; } case kMips: { elf_header.e_machine = EM_MIPS; elf_header.e_flags = (EF_MIPS_NOREORDER | EF_MIPS_PIC | EF_MIPS_CPIC | EF_MIPS_ABI_O32 | EF_MIPS_ARCH_32R2); break; } case kMips64: { elf_header.e_machine = EM_MIPS; elf_header.e_flags = (EF_MIPS_NOREORDER | EF_MIPS_PIC | EF_MIPS_CPIC | EF_MIPS_ARCH_64R6); break; } case kNone: { LOG(FATAL) << "No instruction set"; } } elf_header.e_ident[EI_MAG0] = ELFMAG0; elf_header.e_ident[EI_MAG1] = ELFMAG1; elf_header.e_ident[EI_MAG2] = ELFMAG2; elf_header.e_ident[EI_MAG3] = ELFMAG3; elf_header.e_ident[EI_CLASS] = (sizeof(Elf_Addr) == sizeof(Elf32_Addr)) ? ELFCLASS32 : ELFCLASS64;; elf_header.e_ident[EI_DATA] = ELFDATA2LSB; elf_header.e_ident[EI_VERSION] = EV_CURRENT; elf_header.e_ident[EI_OSABI] = ELFOSABI_LINUX; elf_header.e_ident[EI_ABIVERSION] = 0; elf_header.e_type = ET_DYN; elf_header.e_version = 1; elf_header.e_entry = 0; elf_header.e_ehsize = sizeof(Elf_Ehdr); elf_header.e_phentsize = sizeof(Elf_Phdr); elf_header.e_shentsize = sizeof(Elf_Shdr); elf_header.e_phoff = sizeof(Elf_Ehdr); return elf_header; } void BuildDynamicSection(const std::string& elf_file_path) { std::string soname(elf_file_path); size_t directory_separator_pos = soname.rfind('/'); if (directory_separator_pos != std::string::npos) { soname = soname.substr(directory_separator_pos + 1); } // NB: We must add the name before adding DT_STRSZ. Elf_Word soname_offset = dynstr_.AddName(soname); dynamic_.AddDynamicTag(DT_HASH, 0, &hash_); dynamic_.AddDynamicTag(DT_STRTAB, 0, &dynstr_); dynamic_.AddDynamicTag(DT_SYMTAB, 0, &dynsym_); dynamic_.AddDynamicTag(DT_SYMENT, sizeof(Elf_Sym), nullptr); dynamic_.AddDynamicTag(DT_STRSZ, dynstr_.GetSize(), nullptr); dynamic_.AddDynamicTag(DT_SONAME, soname_offset, nullptr); } void BuildDynsymSection() { dynsym_.AddSymbol("oatdata", &rodata_, 0, true, rodata_.GetSize(), STB_GLOBAL, STT_OBJECT); dynsym_.AddSymbol("oatexec", &text_, 0, true, text_.GetSize(), STB_GLOBAL, STT_OBJECT); dynsym_.AddSymbol("oatlastword", &text_, text_.GetSize() - 4, true, 4, STB_GLOBAL, STT_OBJECT); if (bss_.GetSize() != 0u) { dynsym_.AddSymbol("oatbss", &bss_, 0, true, bss_.GetSize(), STB_GLOBAL, STT_OBJECT); dynsym_.AddSymbol("oatbsslastword", &bss_, bss_.GetSize() - 4, true, 4, STB_GLOBAL, STT_OBJECT); } } InstructionSet isa_; StrtabSection dynstr_; SymtabSection dynsym_; HashSection hash_; OatSection rodata_; OatSection text_; NoBitsSection bss_; DynamicSection dynamic_; StrtabSection strtab_; SymtabSection symtab_; std::vector other_sections_; StrtabSection shstrtab_; DISALLOW_COPY_AND_ASSIGN(ElfBuilder); }; } // namespace art #endif // ART_COMPILER_ELF_BUILDER_H_