diff options
| -rw-r--r-- | compiler/dex/mir_optimization.cc | 6 | ||||
| -rw-r--r-- | compiler/elf_writer_quick.cc | 1336 | ||||
| -rw-r--r-- | compiler/elf_writer_quick.h | 261 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.cc | 6 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.h | 7 | ||||
| -rw-r--r-- | compiler/utils/x86_64/assembler_x86_64_test.cc | 118 | ||||
| -rw-r--r-- | runtime/elf_utils.h | 2 |
7 files changed, 1061 insertions, 675 deletions
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 1460ce631b..4b2bc4a48e 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -346,7 +346,7 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { if (mir->next != NULL) { MIR* mir_next = mir->next; // Make sure result of cmp is used by next insn and nowhere else - if (IsInstructionIfCcZ(mir->next->dalvikInsn.opcode) && + if (IsInstructionIfCcZ(mir_next->dalvikInsn.opcode) && (mir->ssa_rep->defs[0] == mir_next->ssa_rep->uses[0]) && (GetSSAUseCount(mir->ssa_rep->defs[0]) == 1)) { mir_next->meta.ccode = ConditionCodeForIfCcZ(mir_next->dalvikInsn.opcode); @@ -374,12 +374,16 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { default: LOG(ERROR) << "Unexpected opcode: " << opcode; } mir->dalvikInsn.opcode = static_cast<Instruction::Code>(kMirOpNop); + // Copy the SSA information that is relevant. mir_next->ssa_rep->num_uses = mir->ssa_rep->num_uses; mir_next->ssa_rep->uses = mir->ssa_rep->uses; mir_next->ssa_rep->fp_use = mir->ssa_rep->fp_use; mir_next->ssa_rep->num_defs = 0; mir->ssa_rep->num_uses = 0; mir->ssa_rep->num_defs = 0; + // Copy in the decoded instruction information for potential SSA re-creation. + mir_next->dalvikInsn.vA = mir->dalvikInsn.vB; + mir_next->dalvikInsn.vB = mir->dalvikInsn.vC; } } break; diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 09f2eaea20..cb66e4898a 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -29,21 +29,16 @@ namespace art { -bool ElfWriterQuick::Create(File* elf_file, - OatWriter* oat_writer, - const std::vector<const DexFile*>& dex_files, - const std::string& android_root, - bool is_host, - const CompilerDriver& driver) { - ElfWriterQuick elf_writer(driver, elf_file); - return elf_writer.Write(oat_writer, dex_files, android_root, is_host); +static constexpr Elf32_Word NextOffset(const Elf32_Shdr& cur, const Elf32_Shdr& prev) { + return RoundUp(prev.sh_size + prev.sh_offset, cur.sh_addralign); } -bool ElfWriterQuick::Write(OatWriter* oat_writer, - const std::vector<const DexFile*>& dex_files_unused, - const std::string& android_root_unused, - bool is_host_unused) { - const bool debug = false; +static uint8_t MakeStInfo(uint8_t binding, uint8_t type) { + return ((binding) << 4) + ((type) & 0xf); +} + +bool ElfWriterQuick::ElfBuilder::Write() { + // The basic layout of the elf file. Order may be different in final output. // +-------------------------+ // | Elf32_Ehdr | // +-------------------------+ @@ -67,12 +62,14 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, // | boot.oat\0 | // +-------------------------+ // | .hash | - // | Elf32_Word nbucket = 1 | - // | Elf32_Word nchain = 3 | - // | Elf32_Word bucket[0] = 0| - // | Elf32_Word chain[0] = 1| - // | Elf32_Word chain[1] = 2| - // | Elf32_Word chain[2] = 3| + // | Elf32_Word nbucket = b | + // | Elf32_Word nchain = c | + // | Elf32_Word bucket[0] | + // | ... | + // | Elf32_Word bucket[b - 1]| + // | Elf32_Word chain[0] | + // | ... | + // | Elf32_Word chain[c - 1] | // +-------------------------+ // | .rodata | // | oatdata..oatexec-4 | @@ -88,6 +85,12 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, // | Elf32_Dyn DT_STRTAB | // | Elf32_Dyn DT_STRSZ | // | Elf32_Dyn DT_NULL | + // +-------------------------+ (Optional) + // | .strtab | (Optional) + // | program symbol names | (Optional) + // +-------------------------+ (Optional) + // | .symtab | (Optional) + // | program symbols | (Optional) // +-------------------------+ // | .shstrtab | // | \0 | @@ -98,7 +101,20 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, // | .rodata\0 | // | .text\0 | // | .shstrtab\0 | - // | .debug_frame\0 | + // | .symtab\0 | (Optional) + // | .strtab\0 | (Optional) + // | .debug_str\0 | (Optional) + // | .debug_info\0 | (Optional) + // | .debug_frame\0 | (Optional) + // | .debug_abbrev\0 | (Optional) + // +-------------------------+ (Optional) + // | .debug_str | (Optional) + // +-------------------------+ (Optional) + // | .debug_info | (Optional) + // +-------------------------+ (Optional) + // | .debug_frame | (Optional) + // +-------------------------+ (Optional) + // | .debug_abbrev | (Optional) // +-------------------------+ // | Elf32_Shdr NULL | // | Elf32_Shdr .dynsym | @@ -108,20 +124,20 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, // | Elf32_Shdr .rodata | // | Elf32_Shdr .dynamic | // | Elf32_Shdr .shstrtab | + // | Elf32_Shdr .debug_str | (Optional) // | Elf32_Shdr .debug_info | (Optional) - // | Elf32_Shdr .debug_abbrev| (Optional) // | Elf32_Shdr .debug_frame | (Optional) + // | Elf32_Shdr .debug_abbrev| (Optional) // +-------------------------+ - // phase 1: computing offsets - uint32_t expected_offset = 0; - // Elf32_Ehdr - expected_offset += sizeof(Elf32_Ehdr); + if (fatal_error_) { + return false; + } + // Step 1. Figure out all the offsets. - // PHDR - uint32_t phdr_alignment = sizeof(Elf32_Word); - uint32_t phdr_offset = expected_offset; + // What phdr is. + uint32_t phdr_offset = sizeof(Elf32_Ehdr); const uint8_t PH_PHDR = 0; const uint8_t PH_LOAD_R__ = 1; const uint8_t PH_LOAD_R_X = 2; @@ -129,295 +145,12 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, const uint8_t PH_DYNAMIC = 4; const uint8_t PH_NUM = 5; uint32_t phdr_size = sizeof(Elf32_Phdr) * PH_NUM; - expected_offset += phdr_size; - if (debug) { + if (debug_logging_) { LOG(INFO) << "phdr_offset=" << phdr_offset << std::hex << " " << phdr_offset; LOG(INFO) << "phdr_size=" << phdr_size << std::hex << " " << phdr_size; } - - // .dynsym - uint32_t dynsym_alignment = sizeof(Elf32_Word); - uint32_t dynsym_offset = expected_offset = RoundUp(expected_offset, dynsym_alignment); - const uint8_t SYM_UNDEF = 0; // aka STN_UNDEF - const uint8_t SYM_OATDATA = 1; - const uint8_t SYM_OATEXEC = 2; - const uint8_t SYM_OATLASTWORD = 3; - const uint8_t SYM_NUM = 4; - uint32_t dynsym_size = sizeof(Elf32_Sym) * SYM_NUM; - expected_offset += dynsym_size; - if (debug) { - LOG(INFO) << "dynsym_offset=" << dynsym_offset << std::hex << " " << dynsym_offset; - LOG(INFO) << "dynsym_size=" << dynsym_size << std::hex << " " << dynsym_size; - } - - // .dynstr - uint32_t dynstr_alignment = 1; - uint32_t dynstr_offset = expected_offset = RoundUp(expected_offset, dynstr_alignment); - std::string dynstr; - dynstr += '\0'; - uint32_t dynstr_oatdata_offset = dynstr.size(); - dynstr += "oatdata"; - dynstr += '\0'; - uint32_t dynstr_oatexec_offset = dynstr.size(); - dynstr += "oatexec"; - dynstr += '\0'; - uint32_t dynstr_oatlastword_offset = dynstr.size(); - dynstr += "oatlastword"; - dynstr += '\0'; - uint32_t 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'; - uint32_t dynstr_size = dynstr.size(); - expected_offset += dynstr_size; - if (debug) { - LOG(INFO) << "dynstr_offset=" << dynstr_offset << std::hex << " " << dynstr_offset; - LOG(INFO) << "dynstr_size=" << dynstr_size << std::hex << " " << dynstr_size; - } - - // .hash - uint32_t hash_alignment = sizeof(Elf32_Word); // Even for 64-bit - uint32_t hash_offset = expected_offset = RoundUp(expected_offset, hash_alignment); - const uint8_t HASH_NBUCKET = 0; - const uint8_t HASH_NCHAIN = 1; - const uint8_t HASH_BUCKET0 = 2; - const uint8_t HASH_NUM = HASH_BUCKET0 + 1 + SYM_NUM; - uint32_t hash_size = sizeof(Elf32_Word) * HASH_NUM; - expected_offset += hash_size; - if (debug) { - LOG(INFO) << "hash_offset=" << hash_offset << std::hex << " " << hash_offset; - LOG(INFO) << "hash_size=" << hash_size << std::hex << " " << hash_size; - } - - // .rodata - uint32_t oat_data_alignment = kPageSize; - uint32_t oat_data_offset = expected_offset = RoundUp(expected_offset, oat_data_alignment); - const OatHeader& oat_header = oat_writer->GetOatHeader(); - CHECK(oat_header.IsValid()); - uint32_t oat_data_size = oat_header.GetExecutableOffset(); - expected_offset += oat_data_size; - if (debug) { - LOG(INFO) << "oat_data_offset=" << oat_data_offset << std::hex << " " << oat_data_offset; - LOG(INFO) << "oat_data_size=" << oat_data_size << std::hex << " " << oat_data_size; - } - - // .text - uint32_t oat_exec_alignment = kPageSize; - CHECK_ALIGNED(expected_offset, kPageSize); - uint32_t oat_exec_offset = expected_offset = RoundUp(expected_offset, oat_exec_alignment); - uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size; - expected_offset += oat_exec_size; - CHECK_EQ(oat_data_offset + oat_writer->GetSize(), expected_offset); - if (debug) { - LOG(INFO) << "oat_exec_offset=" << oat_exec_offset << std::hex << " " << oat_exec_offset; - LOG(INFO) << "oat_exec_size=" << oat_exec_size << std::hex << " " << oat_exec_size; - } - - // .dynamic - // alignment would naturally be sizeof(Elf32_Word), but we want this in a new segment - uint32_t dynamic_alignment = kPageSize; - uint32_t dynamic_offset = expected_offset = RoundUp(expected_offset, dynamic_alignment); - const uint8_t DH_SONAME = 0; - const uint8_t DH_HASH = 1; - const uint8_t DH_SYMTAB = 2; - const uint8_t DH_SYMENT = 3; - const uint8_t DH_STRTAB = 4; - const uint8_t DH_STRSZ = 5; - const uint8_t DH_NULL = 6; - const uint8_t DH_NUM = 7; - uint32_t dynamic_size = sizeof(Elf32_Dyn) * DH_NUM; - expected_offset += dynamic_size; - if (debug) { - LOG(INFO) << "dynamic_offset=" << dynamic_offset << std::hex << " " << dynamic_offset; - LOG(INFO) << "dynamic_size=" << dynamic_size << std::hex << " " << dynamic_size; - } - - // .shstrtab - uint32_t shstrtab_alignment = 1; - uint32_t shstrtab_offset = expected_offset = RoundUp(expected_offset, shstrtab_alignment); - std::string shstrtab; - shstrtab += '\0'; - uint32_t shstrtab_dynamic_offset = shstrtab.size(); - CHECK_EQ(1U, shstrtab_dynamic_offset); - shstrtab += ".dynamic"; - shstrtab += '\0'; - uint32_t shstrtab_dynsym_offset = shstrtab.size(); - shstrtab += ".dynsym"; - shstrtab += '\0'; - uint32_t shstrtab_dynstr_offset = shstrtab.size(); - shstrtab += ".dynstr"; - shstrtab += '\0'; - uint32_t shstrtab_hash_offset = shstrtab.size(); - shstrtab += ".hash"; - shstrtab += '\0'; - uint32_t shstrtab_rodata_offset = shstrtab.size(); - shstrtab += ".rodata"; - shstrtab += '\0'; - uint32_t shstrtab_text_offset = shstrtab.size(); - shstrtab += ".text"; - shstrtab += '\0'; - uint32_t shstrtab_shstrtab_offset = shstrtab.size(); - shstrtab += ".shstrtab"; - shstrtab += '\0'; - uint32_t shstrtab_debug_info_offset = shstrtab.size(); - shstrtab += ".debug_info"; - shstrtab += '\0'; - uint32_t shstrtab_debug_abbrev_offset = shstrtab.size(); - shstrtab += ".debug_abbrev"; - shstrtab += '\0'; - uint32_t shstrtab_debug_str_offset = shstrtab.size(); - shstrtab += ".debug_str"; - shstrtab += '\0'; - uint32_t shstrtab_debug_frame_offset = shstrtab.size(); - shstrtab += ".debug_frame"; - shstrtab += '\0'; - uint32_t shstrtab_size = shstrtab.size(); - expected_offset += shstrtab_size; - if (debug) { - LOG(INFO) << "shstrtab_offset=" << shstrtab_offset << std::hex << " " << shstrtab_offset; - LOG(INFO) << "shstrtab_size=" << shstrtab_size << std::hex << " " << shstrtab_size; - } - - // Create debug informatin, if we have it. - bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr; - std::vector<uint8_t> dbg_info; - std::vector<uint8_t> dbg_abbrev; - std::vector<uint8_t> dbg_str; - if (generateDebugInformation) { - FillInCFIInformation(oat_writer, &dbg_info, &dbg_abbrev, &dbg_str); - } - - uint32_t shdbg_info_alignment = 1; - uint32_t shdbg_info_offset = expected_offset; - uint32_t shdbg_info_size = dbg_info.size(); - expected_offset += shdbg_info_size; - if (debug) { - LOG(INFO) << "shdbg_info_offset=" << shdbg_info_offset << std::hex << " " << shdbg_info_offset; - LOG(INFO) << "shdbg_info_size=" << shdbg_info_size << std::hex << " " << shdbg_info_size; - } - - uint32_t shdbg_abbrev_alignment = 1; - uint32_t shdbg_abbrev_offset = expected_offset; - uint32_t shdbg_abbrev_size = dbg_abbrev.size(); - expected_offset += shdbg_abbrev_size; - if (debug) { - LOG(INFO) << "shdbg_abbrev_offset=" << shdbg_abbrev_offset << std::hex << " " << shdbg_abbrev_offset; - LOG(INFO) << "shdbg_abbrev_size=" << shdbg_abbrev_size << std::hex << " " << shdbg_abbrev_size; - } - - uint32_t shdbg_frm_alignment = 4; - uint32_t shdbg_frm_offset = expected_offset = RoundUp(expected_offset, shdbg_frm_alignment); - uint32_t shdbg_frm_size = - generateDebugInformation ? compiler_driver_->GetCallFrameInformation()->size() : 0; - expected_offset += shdbg_frm_size; - if (debug) { - LOG(INFO) << "shdbg_frm_offset=" << shdbg_frm_offset << std::hex << " " << shdbg_frm_offset; - LOG(INFO) << "shdbg_frm_size=" << shdbg_frm_size << std::hex << " " << shdbg_frm_size; - } - - uint32_t shdbg_str_alignment = 1; - uint32_t shdbg_str_offset = expected_offset; - uint32_t shdbg_str_size = dbg_str.size(); - expected_offset += shdbg_str_size; - if (debug) { - LOG(INFO) << "shdbg_str_offset=" << shdbg_str_offset << std::hex << " " << shdbg_str_offset; - LOG(INFO) << "shdbg_str_size=" << shdbg_str_size << std::hex << " " << shdbg_str_size; - } - - // section headers (after all sections) - uint32_t shdr_alignment = sizeof(Elf32_Word); - uint32_t shdr_offset = expected_offset = RoundUp(expected_offset, shdr_alignment); - const uint8_t SH_NULL = 0; - const uint8_t SH_DYNSYM = 1; - const uint8_t SH_DYNSTR = 2; - const uint8_t SH_HASH = 3; - const uint8_t SH_RODATA = 4; - const uint8_t SH_TEXT = 5; - const uint8_t SH_DYNAMIC = 6; - const uint8_t SH_SHSTRTAB = 7; - const uint8_t SH_DBG_INFO = 8; - const uint8_t SH_DBG_ABRV = 9; - const uint8_t SH_DBG_FRM = 10; - const uint8_t SH_DBG_STR = 11; - const uint8_t SH_NUM = generateDebugInformation ? 12 : 8; - uint32_t shdr_size = sizeof(Elf32_Shdr) * SH_NUM; - expected_offset += shdr_size; - if (debug) { - LOG(INFO) << "shdr_offset=" << shdr_offset << std::hex << " " << shdr_offset; - LOG(INFO) << "shdr_size=" << shdr_size << std::hex << " " << shdr_size; - } - - // phase 2: initializing data - - // Elf32_Ehdr - Elf32_Ehdr elf_header; - 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] = ELFCLASS32; - 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; - switch (compiler_driver_->GetInstructionSet()) { - 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; - } - default: { - LOG(FATAL) << "Unknown instruction set: " << compiler_driver_->GetInstructionSet(); - break; - } - } - elf_header.e_version = 1; - elf_header.e_entry = 0; - elf_header.e_phoff = phdr_offset; - elf_header.e_shoff = shdr_offset; - elf_header.e_ehsize = sizeof(Elf32_Ehdr); - elf_header.e_phentsize = sizeof(Elf32_Phdr); - elf_header.e_phnum = PH_NUM; - elf_header.e_shentsize = sizeof(Elf32_Shdr); - elf_header.e_shnum = SH_NUM; - elf_header.e_shstrndx = SH_SHSTRTAB; - - // PHDR Elf32_Phdr program_headers[PH_NUM]; 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; @@ -425,419 +158,680 @@ bool ElfWriterQuick::Write(OatWriter* oat_writer, 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 = phdr_alignment; + program_headers[PH_PHDR].p_align = sizeof(Elf32_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_filesz = oat_data_offset + oat_data_size; - program_headers[PH_LOAD_R__].p_memsz = oat_data_offset + oat_data_size; program_headers[PH_LOAD_R__].p_flags = PF_R; - program_headers[PH_LOAD_R__].p_align = oat_data_alignment; program_headers[PH_LOAD_R_X].p_type = PT_LOAD; - program_headers[PH_LOAD_R_X].p_offset = oat_exec_offset; - program_headers[PH_LOAD_R_X].p_vaddr = oat_exec_offset; - program_headers[PH_LOAD_R_X].p_paddr = oat_exec_offset; - program_headers[PH_LOAD_R_X].p_filesz = oat_exec_size; - program_headers[PH_LOAD_R_X].p_memsz = oat_exec_size; program_headers[PH_LOAD_R_X].p_flags = PF_R | PF_X; - program_headers[PH_LOAD_R_X].p_align = oat_exec_alignment; - // TODO: PF_W for DYNAMIC is considered processor specific, do we need it? program_headers[PH_LOAD_RW_].p_type = PT_LOAD; - program_headers[PH_LOAD_RW_].p_offset = dynamic_offset; - program_headers[PH_LOAD_RW_].p_vaddr = dynamic_offset; - program_headers[PH_LOAD_RW_].p_paddr = dynamic_offset; - program_headers[PH_LOAD_RW_].p_filesz = dynamic_size; - program_headers[PH_LOAD_RW_].p_memsz = dynamic_size; program_headers[PH_LOAD_RW_].p_flags = PF_R | PF_W; - program_headers[PH_LOAD_RW_].p_align = dynamic_alignment; - // TODO: PF_W for DYNAMIC is considered processor specific, do we need it? program_headers[PH_DYNAMIC].p_type = PT_DYNAMIC; - program_headers[PH_DYNAMIC].p_offset = dynamic_offset; - program_headers[PH_DYNAMIC].p_vaddr = dynamic_offset; - program_headers[PH_DYNAMIC].p_paddr = dynamic_offset; - program_headers[PH_DYNAMIC].p_filesz = dynamic_size; - program_headers[PH_DYNAMIC].p_memsz = dynamic_size; program_headers[PH_DYNAMIC].p_flags = PF_R | PF_W; - program_headers[PH_DYNAMIC].p_align = dynamic_alignment; - - // .dynsym - Elf32_Sym dynsym[SYM_NUM]; - memset(&dynsym, 0, sizeof(dynsym)); - - dynsym[SYM_UNDEF].st_name = 0; - dynsym[SYM_UNDEF].st_value = 0; - dynsym[SYM_UNDEF].st_size = 0; - dynsym[SYM_UNDEF].st_info = 0; - dynsym[SYM_UNDEF].st_other = 0; - dynsym[SYM_UNDEF].st_shndx = 0; - - dynsym[SYM_OATDATA].st_name = dynstr_oatdata_offset; - dynsym[SYM_OATDATA].st_value = oat_data_offset; - dynsym[SYM_OATDATA].st_size = oat_data_size; - SetBindingAndType(&dynsym[SYM_OATDATA], STB_GLOBAL, STT_OBJECT); - dynsym[SYM_OATDATA].st_other = STV_DEFAULT; - dynsym[SYM_OATDATA].st_shndx = SH_RODATA; - - dynsym[SYM_OATEXEC].st_name = dynstr_oatexec_offset; - dynsym[SYM_OATEXEC].st_value = oat_exec_offset; - dynsym[SYM_OATEXEC].st_size = oat_exec_size; - SetBindingAndType(&dynsym[SYM_OATEXEC], STB_GLOBAL, STT_OBJECT); - dynsym[SYM_OATEXEC].st_other = STV_DEFAULT; - dynsym[SYM_OATEXEC].st_shndx = SH_TEXT; - - dynsym[SYM_OATLASTWORD].st_name = dynstr_oatlastword_offset; - dynsym[SYM_OATLASTWORD].st_value = oat_exec_offset + oat_exec_size - 4; - dynsym[SYM_OATLASTWORD].st_size = 4; - SetBindingAndType(&dynsym[SYM_OATLASTWORD], STB_GLOBAL, STT_OBJECT); - dynsym[SYM_OATLASTWORD].st_other = STV_DEFAULT; - dynsym[SYM_OATLASTWORD].st_shndx = SH_TEXT; - - // .dynstr initialized above as dynstr - - // .hash - Elf32_Word hash[HASH_NUM]; // Note this is Elf32_Word even on 64-bit - hash[HASH_NBUCKET] = 1; - hash[HASH_NCHAIN] = SYM_NUM; - hash[HASH_BUCKET0] = SYM_OATDATA; - hash[HASH_BUCKET0 + 1 + SYM_UNDEF] = SYM_UNDEF; - hash[HASH_BUCKET0 + 1 + SYM_OATDATA] = SYM_OATEXEC; - hash[HASH_BUCKET0 + 1 + SYM_OATEXEC] = SYM_OATLASTWORD; - hash[HASH_BUCKET0 + 1 + SYM_OATLASTWORD] = SYM_UNDEF; - - // .rodata and .text content come from oat_contents - - // .dynamic - Elf32_Dyn dynamic_headers[DH_NUM]; - memset(&dynamic_headers, 0, sizeof(dynamic_headers)); - - dynamic_headers[DH_SONAME].d_tag = DT_SONAME; - dynamic_headers[DH_SONAME].d_un.d_val = dynstr_soname_offset; - - dynamic_headers[DH_HASH].d_tag = DT_HASH; - dynamic_headers[DH_HASH].d_un.d_ptr = hash_offset; - - dynamic_headers[DH_SYMTAB].d_tag = DT_SYMTAB; - dynamic_headers[DH_SYMTAB].d_un.d_ptr = dynsym_offset; - - dynamic_headers[DH_SYMENT].d_tag = DT_SYMENT; - dynamic_headers[DH_SYMENT].d_un.d_val = sizeof(Elf32_Sym); - - dynamic_headers[DH_STRTAB].d_tag = DT_STRTAB; - dynamic_headers[DH_STRTAB].d_un.d_ptr = dynstr_offset; - - dynamic_headers[DH_STRSZ].d_tag = DT_STRSZ; - dynamic_headers[DH_STRSZ].d_un.d_val = dynstr_size; - - dynamic_headers[DH_NULL].d_tag = DT_NULL; - dynamic_headers[DH_NULL].d_un.d_val = 0; - - // .shstrtab initialized above as shstrtab - - // section headers (after all sections) - Elf32_Shdr section_headers[SH_NUM]; - memset(§ion_headers, 0, sizeof(section_headers)); - - section_headers[SH_NULL].sh_name = 0; - section_headers[SH_NULL].sh_type = SHT_NULL; - section_headers[SH_NULL].sh_flags = 0; - section_headers[SH_NULL].sh_addr = 0; - section_headers[SH_NULL].sh_offset = 0; - section_headers[SH_NULL].sh_size = 0; - section_headers[SH_NULL].sh_link = 0; - section_headers[SH_NULL].sh_info = 0; - section_headers[SH_NULL].sh_addralign = 0; - section_headers[SH_NULL].sh_entsize = 0; - - section_headers[SH_DYNSYM].sh_name = shstrtab_dynsym_offset; - section_headers[SH_DYNSYM].sh_type = SHT_DYNSYM; - section_headers[SH_DYNSYM].sh_flags = SHF_ALLOC; - section_headers[SH_DYNSYM].sh_addr = dynsym_offset; - section_headers[SH_DYNSYM].sh_offset = dynsym_offset; - section_headers[SH_DYNSYM].sh_size = dynsym_size; - section_headers[SH_DYNSYM].sh_link = SH_DYNSTR; - section_headers[SH_DYNSYM].sh_info = 1; // 1 because we have not STB_LOCAL symbols - section_headers[SH_DYNSYM].sh_addralign = dynsym_alignment; - section_headers[SH_DYNSYM].sh_entsize = sizeof(Elf32_Sym); - - section_headers[SH_DYNSTR].sh_name = shstrtab_dynstr_offset; - section_headers[SH_DYNSTR].sh_type = SHT_STRTAB; - section_headers[SH_DYNSTR].sh_flags = SHF_ALLOC; - section_headers[SH_DYNSTR].sh_addr = dynstr_offset; - section_headers[SH_DYNSTR].sh_offset = dynstr_offset; - section_headers[SH_DYNSTR].sh_size = dynstr_size; - section_headers[SH_DYNSTR].sh_link = 0; - section_headers[SH_DYNSTR].sh_info = 0; - section_headers[SH_DYNSTR].sh_addralign = dynstr_alignment; - section_headers[SH_DYNSTR].sh_entsize = 0; - - section_headers[SH_HASH].sh_name = shstrtab_hash_offset; - section_headers[SH_HASH].sh_type = SHT_HASH; - section_headers[SH_HASH].sh_flags = SHF_ALLOC; - section_headers[SH_HASH].sh_addr = hash_offset; - section_headers[SH_HASH].sh_offset = hash_offset; - section_headers[SH_HASH].sh_size = hash_size; - section_headers[SH_HASH].sh_link = SH_DYNSYM; - section_headers[SH_HASH].sh_info = 0; - section_headers[SH_HASH].sh_addralign = hash_alignment; - section_headers[SH_HASH].sh_entsize = sizeof(Elf32_Word); // This is Elf32_Word even on 64-bit - - section_headers[SH_RODATA].sh_name = shstrtab_rodata_offset; - section_headers[SH_RODATA].sh_type = SHT_PROGBITS; - section_headers[SH_RODATA].sh_flags = SHF_ALLOC; - section_headers[SH_RODATA].sh_addr = oat_data_offset; - section_headers[SH_RODATA].sh_offset = oat_data_offset; - section_headers[SH_RODATA].sh_size = oat_data_size; - section_headers[SH_RODATA].sh_link = 0; - section_headers[SH_RODATA].sh_info = 0; - section_headers[SH_RODATA].sh_addralign = oat_data_alignment; - section_headers[SH_RODATA].sh_entsize = 0; - - section_headers[SH_TEXT].sh_name = shstrtab_text_offset; - section_headers[SH_TEXT].sh_type = SHT_PROGBITS; - section_headers[SH_TEXT].sh_flags = SHF_ALLOC | SHF_EXECINSTR; - section_headers[SH_TEXT].sh_addr = oat_exec_offset; - section_headers[SH_TEXT].sh_offset = oat_exec_offset; - section_headers[SH_TEXT].sh_size = oat_exec_size; - section_headers[SH_TEXT].sh_link = 0; - section_headers[SH_TEXT].sh_info = 0; - section_headers[SH_TEXT].sh_addralign = oat_exec_alignment; - section_headers[SH_TEXT].sh_entsize = 0; - - // TODO: SHF_WRITE for .dynamic is considered processor specific, do we need it? - section_headers[SH_DYNAMIC].sh_name = shstrtab_dynamic_offset; - section_headers[SH_DYNAMIC].sh_type = SHT_DYNAMIC; - section_headers[SH_DYNAMIC].sh_flags = SHF_WRITE | SHF_ALLOC; - section_headers[SH_DYNAMIC].sh_addr = dynamic_offset; - section_headers[SH_DYNAMIC].sh_offset = dynamic_offset; - section_headers[SH_DYNAMIC].sh_size = dynamic_size; - section_headers[SH_DYNAMIC].sh_link = SH_DYNSTR; - section_headers[SH_DYNAMIC].sh_info = 0; - section_headers[SH_DYNAMIC].sh_addralign = dynamic_alignment; - section_headers[SH_DYNAMIC].sh_entsize = sizeof(Elf32_Dyn); - - section_headers[SH_SHSTRTAB].sh_name = shstrtab_shstrtab_offset; - section_headers[SH_SHSTRTAB].sh_type = SHT_STRTAB; - section_headers[SH_SHSTRTAB].sh_flags = 0; - section_headers[SH_SHSTRTAB].sh_addr = shstrtab_offset; - section_headers[SH_SHSTRTAB].sh_offset = shstrtab_offset; - section_headers[SH_SHSTRTAB].sh_size = shstrtab_size; - section_headers[SH_SHSTRTAB].sh_link = 0; - section_headers[SH_SHSTRTAB].sh_info = 0; - section_headers[SH_SHSTRTAB].sh_addralign = shstrtab_alignment; - section_headers[SH_SHSTRTAB].sh_entsize = 0; - if (generateDebugInformation) { - section_headers[SH_DBG_INFO].sh_name = shstrtab_debug_info_offset; - section_headers[SH_DBG_INFO].sh_type = SHT_PROGBITS; - section_headers[SH_DBG_INFO].sh_flags = 0; - section_headers[SH_DBG_INFO].sh_addr = 0; - section_headers[SH_DBG_INFO].sh_offset = shdbg_info_offset; - section_headers[SH_DBG_INFO].sh_size = shdbg_info_size; - section_headers[SH_DBG_INFO].sh_link = 0; - section_headers[SH_DBG_INFO].sh_info = 0; - section_headers[SH_DBG_INFO].sh_addralign = shdbg_info_alignment; - section_headers[SH_DBG_INFO].sh_entsize = 0; - - section_headers[SH_DBG_ABRV].sh_name = shstrtab_debug_abbrev_offset; - section_headers[SH_DBG_ABRV].sh_type = SHT_PROGBITS; - section_headers[SH_DBG_ABRV].sh_flags = 0; - section_headers[SH_DBG_ABRV].sh_addr = 0; - section_headers[SH_DBG_ABRV].sh_offset = shdbg_abbrev_offset; - section_headers[SH_DBG_ABRV].sh_size = shdbg_abbrev_size; - section_headers[SH_DBG_ABRV].sh_link = 0; - section_headers[SH_DBG_ABRV].sh_info = 0; - section_headers[SH_DBG_ABRV].sh_addralign = shdbg_abbrev_alignment; - section_headers[SH_DBG_ABRV].sh_entsize = 0; - - section_headers[SH_DBG_FRM].sh_name = shstrtab_debug_frame_offset; - section_headers[SH_DBG_FRM].sh_type = SHT_PROGBITS; - section_headers[SH_DBG_FRM].sh_flags = 0; - section_headers[SH_DBG_FRM].sh_addr = 0; - section_headers[SH_DBG_FRM].sh_offset = shdbg_frm_offset; - section_headers[SH_DBG_FRM].sh_size = shdbg_frm_size; - section_headers[SH_DBG_FRM].sh_link = 0; - section_headers[SH_DBG_FRM].sh_info = 0; - section_headers[SH_DBG_FRM].sh_addralign = shdbg_frm_alignment; - section_headers[SH_DBG_FRM].sh_entsize = 0; - - section_headers[SH_DBG_STR].sh_name = shstrtab_debug_str_offset; - section_headers[SH_DBG_STR].sh_type = SHT_PROGBITS; - section_headers[SH_DBG_STR].sh_flags = 0; - section_headers[SH_DBG_STR].sh_addr = 0; - section_headers[SH_DBG_STR].sh_offset = shdbg_str_offset; - section_headers[SH_DBG_STR].sh_size = shdbg_str_size; - section_headers[SH_DBG_STR].sh_link = 0; - section_headers[SH_DBG_STR].sh_info = 0; - section_headers[SH_DBG_STR].sh_addralign = shdbg_str_alignment; - section_headers[SH_DBG_STR].sh_entsize = 0; - } - - // phase 3: writing file - - // Elf32_Ehdr - if (!elf_file_->WriteFully(&elf_header, sizeof(elf_header))) { - PLOG(ERROR) << "Failed to write ELF header for " << elf_file_->GetPath(); - return false; - } + // Get the dynstr string. + std::string dynstr(dynsym_builder_.GenerateStrtab()); - // PHDR - if (static_cast<off_t>(phdr_offset) != lseek(elf_file_->Fd(), 0, SEEK_CUR)) { - PLOG(ERROR) << "Failed to be at expected ELF program header offset phdr_offset " - << " for " << elf_file_->GetPath(); - return false; + // Add the SONAME to the dynstr. + uint32_t 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); } - if (!elf_file_->WriteFully(program_headers, sizeof(program_headers))) { - PLOG(ERROR) << "Failed to write ELF program headers for " << elf_file_->GetPath(); - return false; + 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 strtab + std::string strtab; + if (IncludingDebugSymbols()) { + 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(); + } } - // .dynsym - DCHECK_LE(phdr_offset + phdr_size, dynsym_offset); - if (static_cast<off_t>(dynsym_offset) != lseek(elf_file_->Fd(), dynsym_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .dynsym offset location " << dynsym_offset - << " for " << elf_file_->GetPath(); - return false; - } - if (!elf_file_->WriteFully(dynsym, sizeof(dynsym))) { - PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath(); - return false; - } + // Get the section header string table. + std::vector<Elf32_Shdr*> section_ptrs; + std::string shstrtab; + shstrtab += '\0'; - // .dynstr - DCHECK_LE(dynsym_offset + dynsym_size, dynstr_offset); - if (static_cast<off_t>(dynstr_offset) != lseek(elf_file_->Fd(), dynstr_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .dynstr offset " << dynstr_offset - << " for " << elf_file_->GetPath(); - return false; - } - if (!elf_file_->WriteFully(&dynstr[0], dynstr_size)) { - PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath(); - return false; + // Setup sym_undef + Elf32_Shdr null_hdr; + 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); + + uint32_t section_index = 1; + + // setup .dynsym + section_ptrs.push_back(&dynsym_builder_.section_); + AssignSectionStr(&dynsym_builder_, &shstrtab); + dynsym_builder_.section_index_ = section_index++; + + // Setup .dynstr + section_ptrs.push_back(&dynsym_builder_.strtab_.section_); + AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab); + dynsym_builder_.strtab_.section_index_ = section_index++; + + // Setup .hash + section_ptrs.push_back(&hash_builder_.section_); + AssignSectionStr(&hash_builder_, &shstrtab); + hash_builder_.section_index_ = section_index++; + + // Setup .rodata + section_ptrs.push_back(&rodata_builder_.section_); + AssignSectionStr(&rodata_builder_, &shstrtab); + rodata_builder_.section_index_ = section_index++; + + // Setup .text + section_ptrs.push_back(&text_builder_.section_); + AssignSectionStr(&text_builder_, &shstrtab); + text_builder_.section_index_ = section_index++; + + // Setup .dynamic + section_ptrs.push_back(&dynamic_builder_.section_); + AssignSectionStr(&dynamic_builder_, &shstrtab); + dynamic_builder_.section_index_ = section_index++; + + if (IncludingDebugSymbols()) { + // Setup .symtab + section_ptrs.push_back(&symtab_builder_.section_); + AssignSectionStr(&symtab_builder_, &shstrtab); + symtab_builder_.section_index_ = section_index++; + + // Setup .strtab + section_ptrs.push_back(&symtab_builder_.strtab_.section_); + AssignSectionStr(&symtab_builder_.strtab_, &shstrtab); + symtab_builder_.strtab_.section_index_ = section_index++; + } + ElfRawSectionBuilder* it = other_builders_.data(); + for (uint32_t cnt = 0; cnt < other_builders_.size(); ++it, ++cnt) { + // Setup all the other sections. + section_ptrs.push_back(&it->section_); + AssignSectionStr(it, &shstrtab); + it->section_index_ = section_index++; + } + + // Setup shstrtab + section_ptrs.push_back(&shstrtab_builder_.section_); + AssignSectionStr(&shstrtab_builder_, &shstrtab); + shstrtab_builder_.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(); + } + + // Fill in the hash section. + std::vector<Elf32_Word> hash = dynsym_builder_.GenerateHashContents(); + + if (debug_logging_) { + LOG(INFO) << ".hash size (bytes)=" << hash.size() * sizeof(Elf32_Word) + << std::hex << " " << hash.size() * sizeof(Elf32_Word); + } + + Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers); + std::vector<ElfFilePiece> pieces; + + // Get the layout in the sections. + // + // Get the layout of the dynsym section. + dynsym_builder_.section_.sh_offset = RoundUp(base_offset, dynsym_builder_.section_.sh_addralign); + dynsym_builder_.section_.sh_addr = dynsym_builder_.section_.sh_offset; + dynsym_builder_.section_.sh_size = dynsym_builder_.GetSize() * sizeof(Elf32_Sym); + dynsym_builder_.section_.sh_link = dynsym_builder_.GetLink(); + + // Get the layout of the dynstr section. + dynsym_builder_.strtab_.section_.sh_offset = NextOffset(dynsym_builder_.strtab_.section_, + dynsym_builder_.section_); + dynsym_builder_.strtab_.section_.sh_addr = dynsym_builder_.strtab_.section_.sh_offset; + dynsym_builder_.strtab_.section_.sh_size = dynstr.size(); + dynsym_builder_.strtab_.section_.sh_link = dynsym_builder_.strtab_.GetLink(); + + // Get the layout of the hash section + hash_builder_.section_.sh_offset = NextOffset(hash_builder_.section_, + dynsym_builder_.strtab_.section_); + hash_builder_.section_.sh_addr = hash_builder_.section_.sh_offset; + hash_builder_.section_.sh_size = hash.size() * sizeof(Elf32_Word); + hash_builder_.section_.sh_link = hash_builder_.GetLink(); + + // Get the layout of the rodata section. + rodata_builder_.section_.sh_offset = NextOffset(rodata_builder_.section_, + hash_builder_.section_); + rodata_builder_.section_.sh_addr = rodata_builder_.section_.sh_offset; + rodata_builder_.section_.sh_size = rodata_builder_.size_; + rodata_builder_.section_.sh_link = rodata_builder_.GetLink(); + + // Get the layout of the text section. + text_builder_.section_.sh_offset = NextOffset(text_builder_.section_, rodata_builder_.section_); + text_builder_.section_.sh_addr = text_builder_.section_.sh_offset; + text_builder_.section_.sh_size = text_builder_.size_; + text_builder_.section_.sh_link = text_builder_.GetLink(); + CHECK_ALIGNED(rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size, kPageSize); + + // Get the layout of the dynamic section. + dynamic_builder_.section_.sh_offset = NextOffset(dynamic_builder_.section_, + text_builder_.section_); + dynamic_builder_.section_.sh_addr = dynamic_builder_.section_.sh_offset; + dynamic_builder_.section_.sh_size = dynamic_builder_.GetSize() * sizeof(Elf32_Dyn); + dynamic_builder_.section_.sh_link = dynamic_builder_.GetLink(); + + Elf32_Shdr prev = dynamic_builder_.section_; + if (IncludingDebugSymbols()) { + // Get the layout of the symtab section. + symtab_builder_.section_.sh_offset = NextOffset(symtab_builder_.section_, + dynamic_builder_.section_); + symtab_builder_.section_.sh_addr = 0; + // Add to leave space for the null symbol. + symtab_builder_.section_.sh_size = symtab_builder_.GetSize() * sizeof(Elf32_Sym); + symtab_builder_.section_.sh_link = symtab_builder_.GetLink(); + + // Get the layout of the dynstr section. + symtab_builder_.strtab_.section_.sh_offset = NextOffset(symtab_builder_.strtab_.section_, + symtab_builder_.section_); + symtab_builder_.strtab_.section_.sh_addr = 0; + symtab_builder_.strtab_.section_.sh_size = strtab.size(); + symtab_builder_.strtab_.section_.sh_link = symtab_builder_.strtab_.GetLink(); + + prev = symtab_builder_.strtab_.section_; + } + if (debug_logging_) { + LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset + << " dynsym size=" << dynsym_builder_.section_.sh_size; + LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset + << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size; + LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset + << " hash size=" << hash_builder_.section_.sh_size; + LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset + << " rodata size=" << rodata_builder_.section_.sh_size; + LOG(INFO) << "text off=" << text_builder_.section_.sh_offset + << " text size=" << text_builder_.section_.sh_size; + LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset + << " dynamic size=" << dynamic_builder_.section_.sh_size; + if (IncludingDebugSymbols()) { + LOG(INFO) << "symtab off=" << symtab_builder_.section_.sh_offset + << " symtab size=" << symtab_builder_.section_.sh_size; + LOG(INFO) << "strtab off=" << symtab_builder_.strtab_.section_.sh_offset + << " strtab size=" << symtab_builder_.strtab_.section_.sh_size; + } } - - // .hash - DCHECK_LE(dynstr_offset + dynstr_size, hash_offset); - if (static_cast<off_t>(hash_offset) != lseek(elf_file_->Fd(), hash_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .hash offset " << hash_offset - << " for " << elf_file_->GetPath(); - return false; + // Get the layout of the extra sections. (This will deal with the debug + // sections if they are there) + for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) { + it->section_.sh_offset = NextOffset(it->section_, prev); + it->section_.sh_addr = 0; + it->section_.sh_size = it->GetBuffer()->size(); + it->section_.sh_link = it->GetLink(); + pieces.push_back(ElfFilePiece(it->name_, it->section_.sh_offset, + it->GetBuffer()->data(), it->GetBuffer()->size())); + prev = it->section_; + if (debug_logging_) { + LOG(INFO) << it->name_ << " off=" << it->section_.sh_offset + << " " << it->name_ << " size=" << it->section_.sh_size; + } } - if (!elf_file_->WriteFully(hash, sizeof(hash))) { - PLOG(ERROR) << "Failed to write .dynsym for " << elf_file_->GetPath(); + // Get the layout of the shstrtab section + shstrtab_builder_.section_.sh_offset = NextOffset(shstrtab_builder_.section_, prev); + shstrtab_builder_.section_.sh_addr = 0; + shstrtab_builder_.section_.sh_size = shstrtab.size(); + shstrtab_builder_.section_.sh_link = shstrtab_builder_.GetLink(); + if (debug_logging_) { + LOG(INFO) << "shstrtab off=" << shstrtab_builder_.section_.sh_offset + << " shstrtab size=" << shstrtab_builder_.section_.sh_size; + } + + // The section list comes after come after. + Elf32_Word sections_offset = RoundUp( + shstrtab_builder_.section_.sh_offset + shstrtab_builder_.section_.sh_size, + sizeof(Elf32_Word)); + + // Setup the actual symbol arrays. + std::vector<Elf32_Sym> dynsym = dynsym_builder_.GenerateSymtab(); + CHECK_EQ(dynsym.size() * sizeof(Elf32_Sym), dynsym_builder_.section_.sh_size); + std::vector<Elf32_Sym> symtab; + if (IncludingDebugSymbols()) { + symtab = symtab_builder_.GenerateSymtab(); + CHECK_EQ(symtab.size() * sizeof(Elf32_Sym), symtab_builder_.section_.sh_size); + } + + // Setup the dynamic section. + // This will add the 2 values we cannot know until now time, namely the size + // and the soname_offset. + std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr.size(), + dynstr_soname_offset); + CHECK_EQ(dynamic.size() * sizeof(Elf32_Dyn), dynamic_builder_.section_.sh_size); + + // Finish setup of the program headers now that we know the layout of the + // whole file. + Elf32_Word load_r_size = rodata_builder_.section_.sh_offset + rodata_builder_.section_.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_.section_.sh_addralign; + + Elf32_Word load_rx_size = text_builder_.section_.sh_size; + program_headers[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset; + program_headers[PH_LOAD_R_X].p_vaddr = text_builder_.section_.sh_offset; + program_headers[PH_LOAD_R_X].p_paddr = text_builder_.section_.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_.section_.sh_addralign; + + program_headers[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset; + program_headers[PH_LOAD_RW_].p_vaddr = dynamic_builder_.section_.sh_offset; + program_headers[PH_LOAD_RW_].p_paddr = dynamic_builder_.section_.sh_offset; + program_headers[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size; + program_headers[PH_LOAD_RW_].p_memsz = dynamic_builder_.section_.sh_size; + program_headers[PH_LOAD_RW_].p_align = dynamic_builder_.section_.sh_addralign; + + program_headers[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset; + program_headers[PH_DYNAMIC].p_vaddr = dynamic_builder_.section_.sh_offset; + program_headers[PH_DYNAMIC].p_paddr = dynamic_builder_.section_.sh_offset; + program_headers[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size; + program_headers[PH_DYNAMIC].p_memsz = dynamic_builder_.section_.sh_size; + program_headers[PH_DYNAMIC].p_align = dynamic_builder_.section_.sh_addralign; + + // Finish setup of the Ehdr values. + elf_header_.e_phoff = phdr_offset; + elf_header_.e_shoff = sections_offset; + elf_header_.e_phnum = PH_NUM; + elf_header_.e_shnum = section_ptrs.size(); + elf_header_.e_shstrndx = shstrtab_builder_.section_index_; + + // Add the rest of the pieces to the list. + pieces.push_back(ElfFilePiece("Elf Header", 0, &elf_header_, sizeof(elf_header_))); + pieces.push_back(ElfFilePiece("Program headers", phdr_offset, + &program_headers, sizeof(program_headers))); + pieces.push_back(ElfFilePiece(".dynamic", dynamic_builder_.section_.sh_offset, + dynamic.data(), dynamic_builder_.section_.sh_size)); + pieces.push_back(ElfFilePiece(".dynsym", dynsym_builder_.section_.sh_offset, + dynsym.data(), dynsym.size() * sizeof(Elf32_Sym))); + pieces.push_back(ElfFilePiece(".dynstr", dynsym_builder_.strtab_.section_.sh_offset, + dynstr.c_str(), dynstr.size())); + pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset, + hash.data(), hash.size() * sizeof(Elf32_Word))); + pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset, + NULL, rodata_builder_.section_.sh_size)); + pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset, + NULL, text_builder_.section_.sh_size)); + if (IncludingDebugSymbols()) { + pieces.push_back(ElfFilePiece(".symtab", symtab_builder_.section_.sh_offset, + symtab.data(), symtab.size() * sizeof(Elf32_Sym))); + pieces.push_back(ElfFilePiece(".strtab", symtab_builder_.strtab_.section_.sh_offset, + strtab.c_str(), strtab.size())); + } + pieces.push_back(ElfFilePiece(".shstrtab", shstrtab_builder_.section_.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. + Elf32_Word cur_off = sections_offset + i * sizeof(Elf32_Shdr); + pieces.push_back(ElfFilePiece("section table piece", cur_off, + section_ptrs[i], sizeof(Elf32_Shdr))); + } + + if (!WriteOutFile(pieces)) { + LOG(ERROR) << "Unable to write to file " << elf_file_->GetPath(); return false; } - - // .rodata .text - DCHECK_LE(hash_offset + hash_size, oat_data_offset); + // write out the actual oat file data. + Elf32_Word oat_data_offset = rodata_builder_.section_.sh_offset; if (static_cast<off_t>(oat_data_offset) != lseek(elf_file_->Fd(), oat_data_offset, SEEK_SET)) { PLOG(ERROR) << "Failed to seek to .rodata offset " << oat_data_offset << " for " << elf_file_->GetPath(); return false; } - std::unique_ptr<BufferedOutputStream> output_stream(new BufferedOutputStream(new FileOutputStream(elf_file_))); - if (!oat_writer->Write(output_stream.get())) { + std::unique_ptr<BufferedOutputStream> output_stream( + new BufferedOutputStream(new FileOutputStream(elf_file_))); + if (!oat_writer_->Write(output_stream.get())) { PLOG(ERROR) << "Failed to write .rodata and .text for " << elf_file_->GetPath(); return false; } - // .dynamic - DCHECK_LE(oat_data_offset + oat_writer->GetSize(), dynamic_offset); - if (static_cast<off_t>(dynamic_offset) != lseek(elf_file_->Fd(), dynamic_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .dynamic offset " << dynamic_offset - << " for " << elf_file_->GetPath(); - return false; + return true; +} + +bool ElfWriterQuick::ElfBuilder::WriteOutFile(const std::vector<ElfFilePiece>& pieces) { + // TODO It would be nice if this checked for overlap. + for (auto it = pieces.begin(); it != pieces.end(); ++it) { + if (it->data_) { + if (static_cast<off_t>(it->offset_) != lseek(elf_file_->Fd(), it->offset_, SEEK_SET)) { + PLOG(ERROR) << "Failed to seek to " << it->dbg_name_ << " offset location " + << it->offset_ << " for " << elf_file_->GetPath(); + return false; + } + if (!elf_file_->WriteFully(it->data_, it->size_)) { + PLOG(ERROR) << "Failed to write " << it->dbg_name_ << " for " << elf_file_->GetPath(); + return false; + } + } } - if (!elf_file_->WriteFully(&dynamic_headers[0], dynamic_size)) { - PLOG(ERROR) << "Failed to write .dynamic for " << elf_file_->GetPath(); - return false; + return true; +} + +void ElfWriterQuick::ElfBuilder::SetupDynamic() { + dynamic_builder_.AddDynamicTag(DT_HASH, 0, &hash_builder_); + dynamic_builder_.AddDynamicTag(DT_STRTAB, 0, &dynsym_builder_.strtab_); + dynamic_builder_.AddDynamicTag(DT_SYMTAB, 0, &dynsym_builder_); + dynamic_builder_.AddDynamicTag(DT_SYMENT, sizeof(Elf32_Sym)); +} + +void ElfWriterQuick::ElfBuilder::SetupRequiredSymbols() { + dynsym_builder_.AddSymbol("oatdata", &rodata_builder_, 0, true, + rodata_builder_.size_, STB_GLOBAL, STT_OBJECT); + dynsym_builder_.AddSymbol("oatexec", &text_builder_, 0, true, + text_builder_.size_, STB_GLOBAL, STT_OBJECT); + dynsym_builder_.AddSymbol("oatlastword", &text_builder_, text_builder_.size_ - 4, + true, 4, STB_GLOBAL, STT_OBJECT); +} + +void ElfWriterQuick::ElfDynamicBuilder::AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un) { + if (tag == DT_NULL) { + return; } + dynamics_.push_back({NULL, tag, d_un}); +} - // .shstrtab - DCHECK_LE(dynamic_offset + dynamic_size, shstrtab_offset); - if (static_cast<off_t>(shstrtab_offset) != lseek(elf_file_->Fd(), shstrtab_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .shstrtab offset " << shstrtab_offset - << " for " << elf_file_->GetPath(); - return false; +void ElfWriterQuick::ElfDynamicBuilder::AddDynamicTag(Elf32_Sword tag, Elf32_Word d_un, + ElfSectionBuilder* section) { + if (tag == DT_NULL) { + return; } - if (!elf_file_->WriteFully(&shstrtab[0], shstrtab_size)) { - PLOG(ERROR) << "Failed to write .shstrtab for " << elf_file_->GetPath(); - return false; + dynamics_.push_back({section, tag, d_un}); +} + +std::vector<Elf32_Dyn> ElfWriterQuick::ElfDynamicBuilder::GetDynamics(Elf32_Word strsz, + Elf32_Word soname) { + std::vector<Elf32_Dyn> ret; + for (auto it = dynamics_.cbegin(); it != dynamics_.cend(); ++it) { + if (it->section_) { + // We are adding an address relative to a section. + ret.push_back( + {it->tag_, {it->off_ + it->section_->section_.sh_addr}}); + } else { + ret.push_back({it->tag_, {it->off_}}); + } } + ret.push_back({DT_STRSZ, {strsz}}); + ret.push_back({DT_SONAME, {soname}}); + ret.push_back({DT_NULL, {0}}); + return ret; +} - if (generateDebugInformation) { - // .debug_info - DCHECK_LE(shstrtab_offset + shstrtab_size, shdbg_info_offset); - if (static_cast<off_t>(shdbg_info_offset) != lseek(elf_file_->Fd(), shdbg_info_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .shdbg_info offset " << shdbg_info_offset - << " for " << elf_file_->GetPath(); - return false; +std::vector<Elf32_Sym> ElfWriterQuick::ElfSymtabBuilder::GenerateSymtab() { + std::vector<Elf32_Sym> ret; + Elf32_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) { + Elf32_Sym sym; + memset(&sym, 0, sizeof(sym)); + sym.st_name = it->name_idx_; + if (it->is_relative_) { + sym.st_value = it->addr_ + it->section_->section_.sh_offset; + } else { + sym.st_value = it->addr_; } - if (!elf_file_->WriteFully(&dbg_info[0], shdbg_info_size)) { - PLOG(ERROR) << "Failed to write .debug_info for " << elf_file_->GetPath(); - return false; + sym.st_size = it->size_; + sym.st_other = it->other_; + sym.st_shndx = it->section_->section_index_; + sym.st_info = it->info_; + + ret.push_back(sym); + } + return ret; +} + +std::string ElfWriterQuick::ElfSymtabBuilder::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_.section_.sh_size = tab.size(); + return tab; +} + +void ElfWriterQuick::ElfBuilder::AssignSectionStr( + ElfSectionBuilder* builder, std::string* strtab) { + builder->section_.sh_name = strtab->size(); + *strtab += builder->name_; + *strtab += '\0'; + if (debug_logging_) { + LOG(INFO) << "adding section name \"" << builder->name_ << "\" " + << "to shstrtab at offset " << builder->section_.sh_name; + } +} + +// from bionic +static 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; +} + + +std::vector<Elf32_Word> ElfWriterQuick::ElfSymtabBuilder::GenerateHashContents() { + // 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 | + // | <sym1> | | 4 | | 2 | + // | <sym2> | | | | 5 | + // | <sym3> | | | | STN_UNDEF | + // | <sym4> | | | | 3 | + // | <sym5> | | | | 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). + + // Select number of buckets. + // This is essentially arbitrary. + Elf32_Word nbuckets; + Elf32_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); + } + std::vector<Elf32_Word> 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); + + Elf32_Word* buckets = hash.data() + bucket_offset; + Elf32_Word* chain = hash.data() + chain_offset; + + // Set up the actual hash table. + for (Elf32_Word i = 0; i < symbols_.size(); i++) { + // Add 1 since we need to have the null symbol that is not in the symbols + // list. + Elf32_Word index = i + 1; + Elf32_Word hash_val = static_cast<Elf32_Word>(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<Elf32_Word>(0)); } + } + + return hash; +} + +void ElfWriterQuick::ElfBuilder::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] = ELFCLASS32; + 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(Elf32_Ehdr); + elf_header_.e_phentsize = sizeof(Elf32_Phdr); + elf_header_.e_shentsize = sizeof(Elf32_Shdr); + elf_header_.e_phoff = sizeof(Elf32_Ehdr); +} - // .debug_abbrev - DCHECK_LE(shdbg_info_offset + shdbg_info_size, shdbg_abbrev_offset); - if (static_cast<off_t>(shdbg_abbrev_offset) != lseek(elf_file_->Fd(), shdbg_abbrev_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .shdbg_abbrev offset " << shdbg_abbrev_offset - << " for " << elf_file_->GetPath(); - return false; +void ElfWriterQuick::ElfBuilder::SetISA(InstructionSet isa) { + switch (isa) { + case kArm: + // Fall through. + case kThumb2: { + elf_header_.e_machine = EM_ARM; + elf_header_.e_flags = EF_ARM_EABI_VER5; + break; } - if (!elf_file_->WriteFully(&dbg_abbrev[0], shdbg_abbrev_size)) { - PLOG(ERROR) << "Failed to write .debug_abbrev for " << elf_file_->GetPath(); - return false; + case kArm64: { + elf_header_.e_machine = EM_AARCH64; + elf_header_.e_flags = 0; + break; } - - // .debug_frame - DCHECK_LE(shdbg_abbrev_offset + shdbg_abbrev_size, shdbg_frm_offset); - if (static_cast<off_t>(shdbg_frm_offset) != lseek(elf_file_->Fd(), shdbg_frm_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .shdbg_frm offset " << shdbg_frm_offset - << " for " << elf_file_->GetPath(); - return false; + case kX86: { + elf_header_.e_machine = EM_386; + elf_header_.e_flags = 0; + break; } - if (!elf_file_->WriteFully(&((*compiler_driver_->GetCallFrameInformation())[0]), shdbg_frm_size)) { - PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath(); - return false; + case kX86_64: { + elf_header_.e_machine = EM_X86_64; + elf_header_.e_flags = 0; + break; } - - // .debug_str - DCHECK_LE(shdbg_frm_offset + shdbg_frm_size, shdbg_str_offset); - if (static_cast<off_t>(shdbg_str_offset) != lseek(elf_file_->Fd(), shdbg_str_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to .shdbg_str offset " << shdbg_str_offset - << " for " << elf_file_->GetPath(); - return false; + 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; } - if (!elf_file_->WriteFully(&dbg_str[0], shdbg_str_size)) { - PLOG(ERROR) << "Failed to write .debug_frame for " << elf_file_->GetPath(); - return false; + default: { + fatal_error_ = true; + LOG(FATAL) << "Unknown instruction set: " << isa; + break; } } +} + +void ElfWriterQuick::ElfSymtabBuilder::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) { + CHECK(section); + ElfSymtabBuilder::ElfSymbolState state {name, section, addr, size, is_relative, + MakeStInfo(binding, type), other, 0}; + symbols_.push_back(state); +} - // section headers (after all sections) +bool ElfWriterQuick::Create(File* elf_file, + OatWriter* oat_writer, + const std::vector<const DexFile*>& dex_files, + const std::string& android_root, + bool is_host, + const CompilerDriver& driver) { + ElfWriterQuick elf_writer(driver, elf_file); + return elf_writer.Write(oat_writer, dex_files, android_root, is_host); +} + +bool ElfWriterQuick::Write(OatWriter* oat_writer, + const std::vector<const DexFile*>& dex_files_unused, + const std::string& android_root_unused, + bool is_host_unused) { + const bool debug = false; + const OatHeader& oat_header = oat_writer->GetOatHeader(); + Elf32_Word oat_data_size = oat_header.GetExecutableOffset(); + uint32_t oat_exec_size = oat_writer->GetSize() - oat_data_size; + + ElfBuilder builder(oat_writer, elf_file_, compiler_driver_->GetInstructionSet(), 0, + oat_data_size, oat_data_size, oat_exec_size, false, debug); + + bool generateDebugInformation = compiler_driver_->GetCallFrameInformation() != nullptr; if (generateDebugInformation) { - DCHECK_LE(shdbg_str_offset + shdbg_str_size, shdr_offset); - } else { - DCHECK_LE(shstrtab_offset + shstrtab_size, shdr_offset); - } - if (static_cast<off_t>(shdr_offset) != lseek(elf_file_->Fd(), shdr_offset, SEEK_SET)) { - PLOG(ERROR) << "Failed to seek to ELF section headers offset " << shdr_offset - << " for " << elf_file_->GetPath(); - return false; - } - if (!elf_file_->WriteFully(section_headers, sizeof(section_headers))) { - PLOG(ERROR) << "Failed to write ELF section headers for " << elf_file_->GetPath(); - return false; + ElfRawSectionBuilder debug_info(".debug_info", SHT_PROGBITS, 0, NULL, 0, 1, 0); + ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, NULL, 0, 1, 0); + ElfRawSectionBuilder debug_str(".debug_str", SHT_PROGBITS, 0, NULL, 0, 1, 0); + ElfRawSectionBuilder debug_frame(".debug_frame", SHT_PROGBITS, 0, NULL, 0, 4, 0); + debug_frame.SetBuffer(*compiler_driver_->GetCallFrameInformation()); + + FillInCFIInformation(oat_writer, debug_info.GetBuffer(), + debug_abbrev.GetBuffer(), debug_str.GetBuffer()); + builder.RegisterRawSection(debug_info); + builder.RegisterRawSection(debug_abbrev); + builder.RegisterRawSection(debug_frame); + builder.RegisterRawSection(debug_str); } - VLOG(compiler) << "ELF file written successfully: " << elf_file_->GetPath(); - return true; -} // NOLINT(readability/fn_size) + return builder.Write(); +} static void UpdateWord(std::vector<uint8_t>*buf, int offset, int data) { (*buf)[offset+0] = data; diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h index dec75dc83f..f687d2e80b 100644 --- a/compiler/elf_writer_quick.h +++ b/compiler/elf_writer_quick.h @@ -17,7 +17,9 @@ #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 { @@ -45,6 +47,265 @@ class ElfWriterQuick FINAL : public ElfWriter { : ElfWriter(driver, elf_file) {} ~ElfWriterQuick() {} + class ElfBuilder; + 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(); + ElfSymtabBuilder* GetDefaultDynsymBuilder() { return &dynsym_builder_; } + + // 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. diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index a14551c3b7..b07eed390f 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -1650,7 +1650,7 @@ void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, pushq(spill_regs.at(i).AsX86_64().AsCpuRegister()); } // return address then method on stack - addq(CpuRegister(RSP), Immediate(-frame_size + (spill_regs.size() * kFramePointerSize) + + addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(frame_size) + (spill_regs.size() * kFramePointerSize) + sizeof(StackReference<mirror::ArtMethod>) /*method*/ + kFramePointerSize /*return address*/)); @@ -1682,7 +1682,7 @@ void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void X86_64Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& spill_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); - addq(CpuRegister(RSP), Immediate(frame_size - (spill_regs.size() * kFramePointerSize) - kFramePointerSize)); + addq(CpuRegister(RSP), Immediate(static_cast<int64_t>(frame_size) - (spill_regs.size() * kFramePointerSize) - kFramePointerSize)); for (size_t i = 0; i < spill_regs.size(); ++i) { popq(spill_regs.at(i).AsX86_64().AsCpuRegister()); } @@ -1691,7 +1691,7 @@ void X86_64Assembler::RemoveFrame(size_t frame_size, void X86_64Assembler::IncreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); - addq(CpuRegister(RSP), Immediate(-adjust)); + addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust))); } void X86_64Assembler::DecreaseFrameSize(size_t adjust) { diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 548d379346..6276603757 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -29,6 +29,13 @@ namespace art { namespace x86_64 { +// Encodes an immediate value for operands. +// +// Note: Immediates can be 64b on x86-64 for certain instructions, but are often restricted +// to 32b. +// +// Note: As we support cross-compilation, the value type must be int64_t. Please be aware of +// conversion rules in expressions regarding negation, especially size_t on 32b. class Immediate { public: explicit Immediate(int64_t value) : value_(value) {} diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index 7201d04292..799db9f5bd 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -200,4 +200,122 @@ TEST_F(AssemblerX86_64Test, SetCC) { DriverFn(&setcc_test_fn, "setcc"); } +static x86_64::X86_64ManagedRegister ManagedFromCpu(x86_64::Register r) { + return x86_64::X86_64ManagedRegister::FromCpuRegister(r); +} + +static x86_64::X86_64ManagedRegister ManagedFromFpu(x86_64::FloatRegister r) { + return x86_64::X86_64ManagedRegister::FromXmmRegister(r); +} + +std::string buildframe_test_fn(x86_64::X86_64Assembler* assembler) { + // TODO: more interesting spill registers / entry spills. + + // Two random spill regs. + std::vector<ManagedRegister> spill_regs; + spill_regs.push_back(ManagedFromCpu(x86_64::R10)); + spill_regs.push_back(ManagedFromCpu(x86_64::RSI)); + + // Three random entry spills. + ManagedRegisterEntrySpills entry_spills; + ManagedRegisterSpill spill(ManagedFromCpu(x86_64::RAX), 8, 0); + entry_spills.push_back(spill); + ManagedRegisterSpill spill2(ManagedFromCpu(x86_64::RBX), 8, 8); + entry_spills.push_back(spill2); + ManagedRegisterSpill spill3(ManagedFromFpu(x86_64::XMM1), 8, 16); + entry_spills.push_back(spill3); + + x86_64::X86_64ManagedRegister method_reg = ManagedFromCpu(x86_64::RDI); + + size_t frame_size = 10 * kStackAlignment; + assembler->BuildFrame(10 * kStackAlignment, method_reg, spill_regs, entry_spills); + + // Construct assembly text counterpart. + std::ostringstream str; + // 1) Push the spill_regs. + str << "pushq %rsi\n"; + str << "pushq %r10\n"; + // 2) Move down the stack pointer. + ssize_t displacement = -static_cast<ssize_t>(frame_size) + spill_regs.size() * 8 + + sizeof(StackReference<mirror::ArtMethod>) + 8; + str << "addq $" << displacement << ", %rsp\n"; + // 3) Make space for method reference, and store it. + str << "subq $4, %rsp\n"; + str << "movl %edi, (%rsp)\n"; + // 4) Entry spills. + str << "movq %rax, " << frame_size + 0 << "(%rsp)\n"; + str << "movq %rbx, " << frame_size + 8 << "(%rsp)\n"; + str << "movsd %xmm1, " << frame_size + 16 << "(%rsp)\n"; + + return str.str(); +} + +TEST_F(AssemblerX86_64Test, BuildFrame) { + DriverFn(&buildframe_test_fn, "BuildFrame"); +} + +std::string removeframe_test_fn(x86_64::X86_64Assembler* assembler) { + // TODO: more interesting spill registers / entry spills. + + // Two random spill regs. + std::vector<ManagedRegister> spill_regs; + spill_regs.push_back(ManagedFromCpu(x86_64::R10)); + spill_regs.push_back(ManagedFromCpu(x86_64::RSI)); + + size_t frame_size = 10 * kStackAlignment; + assembler->RemoveFrame(10 * kStackAlignment, spill_regs); + + // Construct assembly text counterpart. + std::ostringstream str; + // 1) Move up the stack pointer. + ssize_t displacement = static_cast<ssize_t>(frame_size) - spill_regs.size() * 8 - 8; + str << "addq $" << displacement << ", %rsp\n"; + // 2) Pop spill regs. + str << "popq %r10\n"; + str << "popq %rsi\n"; + str << "ret\n"; + + return str.str(); +} + +TEST_F(AssemblerX86_64Test, RemoveFrame) { + DriverFn(&removeframe_test_fn, "RemoveFrame"); +} + +std::string increaseframe_test_fn(x86_64::X86_64Assembler* assembler) { + assembler->IncreaseFrameSize(0U); + assembler->IncreaseFrameSize(kStackAlignment); + assembler->IncreaseFrameSize(10 * kStackAlignment); + + // Construct assembly text counterpart. + std::ostringstream str; + str << "addq $0, %rsp\n"; + str << "addq $-" << kStackAlignment << ", %rsp\n"; + str << "addq $-" << 10 * kStackAlignment << ", %rsp\n"; + + return str.str(); +} + +TEST_F(AssemblerX86_64Test, IncreaseFrame) { + DriverFn(&increaseframe_test_fn, "IncreaseFrame"); +} + +std::string decreaseframe_test_fn(x86_64::X86_64Assembler* assembler) { + assembler->DecreaseFrameSize(0U); + assembler->DecreaseFrameSize(kStackAlignment); + assembler->DecreaseFrameSize(10 * kStackAlignment); + + // Construct assembly text counterpart. + std::ostringstream str; + str << "addq $0, %rsp\n"; + str << "addq $" << kStackAlignment << ", %rsp\n"; + str << "addq $" << 10 * kStackAlignment << ", %rsp\n"; + + return str.str(); +} + +TEST_F(AssemblerX86_64Test, DecreaseFrame) { + DriverFn(&decreaseframe_test_fn, "DecreaseFrame"); +} + } // namespace art diff --git a/runtime/elf_utils.h b/runtime/elf_utils.h index f160dc4b2c..ce8587b889 100644 --- a/runtime/elf_utils.h +++ b/runtime/elf_utils.h @@ -17,6 +17,8 @@ #ifndef ART_RUNTIME_ELF_UTILS_H_ #define ART_RUNTIME_ELF_UTILS_H_ +#include <sys/cdefs.h> + // Explicitly include elf.h from elfutils to avoid Linux and other dependencies. #include "../../external/elfutils/0.153/libelf/elf.h" |