| /* |
| * Copyright (C) 2012 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_WRITER_QUICK_H_ |
| #define ART_COMPILER_ELF_WRITER_QUICK_H_ |
| |
| #include "elf_utils.h" |
| #include "elf_writer.h" |
| #include "instruction_set.h" |
| |
| namespace art { |
| |
| class ElfWriterQuick FINAL : public ElfWriter { |
| public: |
| // Write an ELF file. Returns true on success, false on failure. |
| static bool Create(File* file, |
| OatWriter* oat_writer, |
| const std::vector<const DexFile*>& dex_files, |
| const std::string& android_root, |
| bool is_host, |
| const CompilerDriver& driver) |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| protected: |
| bool Write(OatWriter* oat_writer, |
| const std::vector<const DexFile*>& dex_files, |
| const std::string& android_root, |
| bool is_host) |
| OVERRIDE |
| SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); |
| |
| private: |
| ElfWriterQuick(const CompilerDriver& driver, File* elf_file) |
| : ElfWriter(driver, elf_file) {} |
| ~ElfWriterQuick() {} |
| |
| class ElfBuilder; |
| void AddDebugSymbols(ElfBuilder& builder, |
| OatWriter* oat_writer, |
| bool debug); |
| |
| class ElfSectionBuilder { |
| public: |
| ElfSectionBuilder(const std::string& sec_name, Elf32_Word type, Elf32_Word flags, |
| const ElfSectionBuilder *link, Elf32_Word info, Elf32_Word align, |
| Elf32_Word entsize) |
| : name_(sec_name), link_(link) { |
| memset(§ion_, 0, sizeof(section_)); |
| section_.sh_type = type; |
| section_.sh_flags = flags; |
| section_.sh_info = info; |
| section_.sh_addralign = align; |
| section_.sh_entsize = entsize; |
| } |
| |
| virtual ~ElfSectionBuilder() {} |
| |
| Elf32_Shdr section_; |
| Elf32_Word section_index_ = 0; |
| |
| protected: |
| const std::string name_; |
| const ElfSectionBuilder* link_; |
| |
| Elf32_Word GetLink() { |
| return (link_) ? link_->section_index_ : 0; |
| } |
| |
| private: |
| friend class ElfBuilder; |
| }; |
| |
| class ElfDynamicBuilder : public ElfSectionBuilder { |
| public: |
| void AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un); |
| void AddDynamicTag(Elf32_Sword tag, Elf32_Word offset, ElfSectionBuilder* section); |
| |
| ElfDynamicBuilder(const std::string& sec_name, ElfSectionBuilder *link) |
| : ElfSectionBuilder(sec_name, SHT_DYNAMIC, SHF_ALLOC | SHF_ALLOC, link, |
| 0, kPageSize, sizeof(Elf32_Dyn)) {} |
| ~ElfDynamicBuilder() {} |
| |
| protected: |
| struct ElfDynamicState { |
| ElfSectionBuilder* section_; |
| Elf32_Sword tag_; |
| Elf32_Word off_; |
| }; |
| std::vector<ElfDynamicState> dynamics_; |
| Elf32_Word GetSize() { |
| // Add 1 for the DT_NULL, 1 for DT_STRSZ, and 1 for DT_SONAME. All of |
| // these must be added when we actually put the file together because |
| // their values are very dependent on state. |
| return dynamics_.size() + 3; |
| } |
| |
| // Create the actual dynamic vector. strsz should be the size of the .dynstr |
| // table and soname_off should be the offset of the soname in .dynstr. |
| // Since niether can be found prior to final layout we will wait until here |
| // to add them. |
| std::vector<Elf32_Dyn> GetDynamics(Elf32_Word strsz, Elf32_Word soname_off); |
| |
| private: |
| friend class ElfBuilder; |
| }; |
| |
| class ElfRawSectionBuilder : public ElfSectionBuilder { |
| public: |
| ElfRawSectionBuilder(const std::string& sec_name, Elf32_Word type, Elf32_Word flags, |
| const ElfSectionBuilder* link, Elf32_Word info, Elf32_Word align, |
| Elf32_Word entsize) |
| : ElfSectionBuilder(sec_name, type, flags, link, info, align, entsize) {} |
| ~ElfRawSectionBuilder() {} |
| std::vector<uint8_t>* GetBuffer() { return &buf_; } |
| void SetBuffer(std::vector<uint8_t> buf) { buf_ = buf; } |
| |
| protected: |
| std::vector<uint8_t> buf_; |
| |
| private: |
| friend class ElfBuilder; |
| }; |
| |
| class ElfOatSectionBuilder : public ElfSectionBuilder { |
| public: |
| ElfOatSectionBuilder(const std::string& sec_name, Elf32_Word size, Elf32_Word offset, |
| Elf32_Word type, Elf32_Word flags) |
| : ElfSectionBuilder(sec_name, type, flags, NULL, 0, kPageSize, 0), |
| offset_(offset), size_(size) {} |
| ~ElfOatSectionBuilder() {} |
| |
| protected: |
| // Offset of the content within the file. |
| Elf32_Word offset_; |
| // Size of the content within the file. |
| Elf32_Word size_; |
| |
| private: |
| friend class ElfBuilder; |
| }; |
| |
| class ElfSymtabBuilder : public ElfSectionBuilder { |
| 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, |
| Elf32_Addr addr, |
| bool is_relative, |
| Elf32_Word size, |
| uint8_t binding, |
| uint8_t type, |
| uint8_t other = 0); |
| |
| ElfSymtabBuilder(const std::string& sec_name, Elf32_Word type, |
| const std::string& str_name, Elf32_Word str_type, bool alloc) |
| : ElfSectionBuilder(sec_name, type, ((alloc)?SHF_ALLOC:0), &strtab_, 0, |
| sizeof(Elf32_Word), sizeof(Elf32_Sym)), |
| str_name_(str_name), str_type_(str_type), |
| strtab_(str_name, str_type, ((alloc) ? SHF_ALLOC : 0), NULL, 0, 1, 1) {} |
| ~ElfSymtabBuilder() {} |
| |
| protected: |
| std::vector<Elf32_Word> GenerateHashContents(); |
| std::string GenerateStrtab(); |
| std::vector<Elf32_Sym> GenerateSymtab(); |
| |
| Elf32_Word GetSize() { |
| // 1 is for the implicit NULL symbol. |
| return symbols_.size() + 1; |
| } |
| |
| struct ElfSymbolState { |
| const std::string name_; |
| const ElfSectionBuilder* section_; |
| Elf32_Addr addr_; |
| Elf32_Word size_; |
| bool is_relative_; |
| uint8_t info_; |
| uint8_t other_; |
| // Used during Write() to temporarially hold name index in the strtab. |
| Elf32_Word name_idx_; |
| }; |
| |
| // Information for the strsym for dynstr sections. |
| const std::string str_name_; |
| Elf32_Word str_type_; |
| // The symbols in the same order they will be in the symbol table. |
| std::vector<ElfSymbolState> symbols_; |
| ElfSectionBuilder strtab_; |
| |
| private: |
| friend class ElfBuilder; |
| }; |
| |
| class ElfBuilder FINAL { |
| public: |
| ElfBuilder(OatWriter* oat_writer, |
| File* elf_file, |
| InstructionSet isa, |
| Elf32_Word rodata_relative_offset, |
| Elf32_Word rodata_size, |
| Elf32_Word text_relative_offset, |
| Elf32_Word text_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), |
| 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(Elf32_Word), sizeof(Elf32_Word)), |
| dynamic_builder_(".dynamic", &dynsym_builder_), |
| shstrtab_builder_(".shstrtab", SHT_STRTAB, 0, NULL, 0, 1, 1) { |
| SetupEhdr(); |
| SetupDynamic(); |
| SetupRequiredSymbols(); |
| SetISA(isa); |
| } |
| ~ElfBuilder() {} |
| |
| bool Write(); |
| |
| // Adds the given raw section to the builder. This will copy it. The caller |
| // is responsible for deallocating their copy. |
| void RegisterRawSection(ElfRawSectionBuilder bld) { |
| other_builders_.push_back(bld); |
| } |
| |
| private: |
| OatWriter* oat_writer_; |
| File* elf_file_; |
| const bool add_symbols_; |
| const bool debug_logging_; |
| |
| bool fatal_error_ = false; |
| |
| Elf32_Ehdr elf_header_; |
| |
| public: |
| ElfOatSectionBuilder text_builder_; |
| ElfOatSectionBuilder rodata_builder_; |
| ElfSymtabBuilder dynsym_builder_; |
| ElfSymtabBuilder symtab_builder_; |
| ElfSectionBuilder hash_builder_; |
| ElfDynamicBuilder dynamic_builder_; |
| ElfSectionBuilder shstrtab_builder_; |
| std::vector<ElfRawSectionBuilder> other_builders_; |
| |
| private: |
| void SetISA(InstructionSet isa); |
| void SetupEhdr(); |
| |
| // 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(); |
| |
| // Sets up the basic dynamic symbols that are needed, namely all those we |
| // can know already. |
| // |
| // Specifically adds: |
| // oatdata |
| // oatexec |
| // oatlastword |
| void SetupRequiredSymbols(); |
| void AssignSectionStr(ElfSectionBuilder *builder, std::string* strtab); |
| struct ElfFilePiece { |
| ElfFilePiece(const std::string& name, Elf32_Word offset, const void* data, Elf32_Word size) |
| : dbg_name_(name), offset_(offset), data_(data), size_(size) {} |
| ~ElfFilePiece() {} |
| |
| const std::string& dbg_name_; |
| Elf32_Word offset_; |
| const void *data_; |
| Elf32_Word size_; |
| static bool Compare(ElfFilePiece a, ElfFilePiece b) { |
| return a.offset_ < b.offset_; |
| } |
| }; |
| |
| // Write each of the pieces out to the file. |
| bool WriteOutFile(const std::vector<ElfFilePiece>& pieces); |
| bool IncludingDebugSymbols() { return add_symbols_ && symtab_builder_.GetSize() > 1; } |
| }; |
| |
| /* |
| * @brief Generate the DWARF debug_info and debug_abbrev sections |
| * @param oat_writer The Oat file Writer. |
| * @param dbg_info Compilation unit information. |
| * @param dbg_abbrev Abbreviations used to generate dbg_info. |
| * @param dbg_str Debug strings. |
| */ |
| void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info, |
| std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str); |
| |
| DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick); |
| }; |
| |
| } // namespace art |
| |
| #endif // ART_COMPILER_ELF_WRITER_QUICK_H_ |