diff options
-rw-r--r-- | compiler/Android.mk | 2 | ||||
-rw-r--r-- | compiler/elf_builder.h | 3 | ||||
-rw-r--r-- | compiler/elf_fixup.cc | 182 | ||||
-rw-r--r-- | compiler/elf_fixup.h | 56 | ||||
-rw-r--r-- | compiler/elf_stripper.cc | 138 | ||||
-rw-r--r-- | compiler/elf_stripper.h | 39 | ||||
-rw-r--r-- | compiler/elf_writer.cc | 16 | ||||
-rw-r--r-- | compiler/elf_writer.h | 4 | ||||
-rw-r--r-- | compiler/image_test.cc | 4 | ||||
-rw-r--r-- | compiler/image_writer.cc | 7 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 5 | ||||
-rw-r--r-- | patchoat/patchoat.cc | 124 | ||||
-rw-r--r-- | patchoat/patchoat.h | 13 | ||||
-rw-r--r-- | runtime/elf.h | 1 | ||||
-rw-r--r-- | runtime/elf_file.cc | 1051 | ||||
-rw-r--r-- | runtime/elf_file.h | 185 | ||||
-rw-r--r-- | runtime/elf_file_impl.h | 220 | ||||
-rw-r--r-- | runtime/oat_file.cc | 8 |
18 files changed, 1251 insertions, 807 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 8b5e6d5..133044a 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -125,8 +125,6 @@ LIBART_COMPILER_SRC_FILES := \ utils/scoped_arena_allocator.cc \ buffered_output_stream.cc \ compiler.cc \ - elf_fixup.cc \ - elf_stripper.cc \ elf_writer.cc \ elf_writer_quick.cc \ file_output_stream.cc \ diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 3be2478..74ee038 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -1094,7 +1094,8 @@ class ElfBuilder FINAL { 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_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; diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc deleted file mode 100644 index 0d34879..0000000 --- a/compiler/elf_fixup.cc +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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. - */ - -#include "elf_fixup.h" - -#include <inttypes.h> -#include <memory> - -#include "base/logging.h" -#include "base/stringprintf.h" -#include "elf_file.h" -#include "elf_writer.h" - -namespace art { - -static const bool DEBUG_FIXUP = false; - -bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) { - std::string error_msg; - std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg)); - CHECK(elf_file.get() != nullptr) << error_msg; - - // Lookup "oatdata" symbol address. - Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get()); - Elf32_Off base_address = oat_data_begin - oatdata_address; - - if (!FixupDynamic(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed to fixup .dynamic in " << file->GetPath(); - return false; - } - if (!FixupSectionHeaders(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed to fixup section headers in " << file->GetPath(); - return false; - } - if (!FixupProgramHeaders(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed to fixup program headers in " << file->GetPath(); - return false; - } - if (!FixupSymbols(*elf_file.get(), base_address, true)) { - LOG(WARNING) << "Failed to fixup .dynsym in " << file->GetPath(); - return false; - } - if (!FixupSymbols(*elf_file.get(), base_address, false)) { - LOG(WARNING) << "Failed to fixup .symtab in " << file->GetPath(); - return false; - } - if (!FixupRelocations(*elf_file.get(), base_address)) { - LOG(WARNING) << "Failed to fixup .rel.dyn in " << file->GetPath(); - return false; - } - if (!elf_file->FixupDebugSections(base_address)) { - LOG(WARNING) << "Failed to fixup debug sections in " << file->GetPath(); - return false; - } - return true; -} - - -bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) { - for (Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) { - Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i); - Elf32_Word d_tag = elf_dyn.d_tag; - if (IsDynamicSectionPointer(d_tag, elf_file.GetHeader().e_machine)) { - uint32_t d_ptr = elf_dyn.d_un.d_ptr; - if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR, - elf_file.GetFile().GetPath().c_str(), i, - d_ptr, d_ptr + base_address); - } - d_ptr += base_address; - elf_dyn.d_un.d_ptr = d_ptr; - } - } - return true; -} - -bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) { - for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) { - Elf32_Shdr* sh = elf_file.GetSectionHeader(i); - CHECK(sh != nullptr); - // 0 implies that the section will not exist in the memory of the process - if (sh->sh_addr == 0) { - continue; - } - if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR, - elf_file.GetFile().GetPath().c_str(), i, - sh->sh_addr, sh->sh_addr + base_address); - } - sh->sh_addr += base_address; - } - return true; -} - -bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) { - // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now. - for (Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) { - Elf32_Phdr* ph = elf_file.GetProgramHeader(i); - CHECK(ph != nullptr); - CHECK_EQ(ph->p_vaddr, ph->p_paddr) << elf_file.GetFile().GetPath() << " i=" << i; - CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)))) - << elf_file.GetFile().GetPath() << " i=" << i; - if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR, - elf_file.GetFile().GetPath().c_str(), i, - ph->p_vaddr, ph->p_vaddr + base_address); - } - ph->p_vaddr += base_address; - ph->p_paddr += base_address; - CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)))) - << elf_file.GetFile().GetPath() << " i=" << i; - } - return true; -} - -bool ElfFixup::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic) { - Elf32_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB; - // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile - Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type); - if (symbol_section == nullptr) { - // file is missing optional .symtab - CHECK(!dynamic) << elf_file.GetFile().GetPath(); - return true; - } - for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) { - Elf32_Sym* symbol = elf_file.GetSymbol(section_type, i); - CHECK(symbol != nullptr); - if (symbol->st_value != 0) { - if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR, - elf_file.GetFile().GetPath().c_str(), i, - symbol->st_value, symbol->st_value + base_address); - } - symbol->st_value += base_address; - } - } - return true; -} - -bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) { - for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) { - Elf32_Shdr* sh = elf_file.GetSectionHeader(i); - CHECK(sh != nullptr); - if (sh->sh_type == SHT_REL) { - for (uint32_t i = 0; i < elf_file.GetRelNum(*sh); i++) { - Elf32_Rel& rel = elf_file.GetRel(*sh, i); - if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR, - elf_file.GetFile().GetPath().c_str(), i, - rel.r_offset, rel.r_offset + base_address); - } - rel.r_offset += base_address; - } - } else if (sh->sh_type == SHT_RELA) { - for (uint32_t i = 0; i < elf_file.GetRelaNum(*sh); i++) { - Elf32_Rela& rela = elf_file.GetRela(*sh, i); - if (DEBUG_FIXUP) { - LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR, - elf_file.GetFile().GetPath().c_str(), i, - rela.r_offset, rela.r_offset + base_address); - } - rela.r_offset += base_address; - } - } - } - return true; -} - -} // namespace art diff --git a/compiler/elf_fixup.h b/compiler/elf_fixup.h deleted file mode 100644 index 1abf06b..0000000 --- a/compiler/elf_fixup.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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_FIXUP_H_ -#define ART_COMPILER_ELF_FIXUP_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "os.h" - -namespace art { - -class ElfFile; - -class ElfFixup { - public: - // Fixup an ELF file so that that oat header will be loaded at oat_begin. - // Returns true on success, false on failure. - static bool Fixup(File* file, uintptr_t oat_data_begin); - - private: - // Fixup .dynamic d_ptr values for the expected base_address. - static bool FixupDynamic(ElfFile& elf_file, uintptr_t base_address); - - // Fixup Elf32_Shdr p_vaddr to load at the desired address. - static bool FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address); - - // Fixup Elf32_Phdr p_vaddr to load at the desired address. - static bool FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address); - - // Fixup symbol table - static bool FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic); - - // Fixup dynamic relocations - static bool FixupRelocations(ElfFile& elf_file, uintptr_t base_address); - - DISALLOW_IMPLICIT_CONSTRUCTORS(ElfFixup); -}; - -} // namespace art - -#endif // ART_COMPILER_ELF_FIXUP_H_ diff --git a/compiler/elf_stripper.cc b/compiler/elf_stripper.cc deleted file mode 100644 index 457d8a0..0000000 --- a/compiler/elf_stripper.cc +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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. - */ - -#include "elf_stripper.h" - -#include <unistd.h> -#include <sys/types.h> -#include <memory> -#include <vector> - -#include "base/logging.h" -#include "base/stringprintf.h" -#include "elf_file.h" -#include "elf_utils.h" -#include "utils.h" - -namespace art { - -bool ElfStripper::Strip(File* file, std::string* error_msg) { - std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg)); - if (elf_file.get() == nullptr) { - return false; - } - - // ELF files produced by MCLinker look roughly like this - // - // +------------+ - // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first - // +------------+ - // | Elf32_Phdr | program headers - // | Elf32_Phdr | - // | ... | - // | Elf32_Phdr | - // +------------+ - // | section | mixture of needed and unneeded sections - // +------------+ - // | section | - // +------------+ - // | ... | - // +------------+ - // | section | - // +------------+ - // | Elf32_Shdr | section headers - // | Elf32_Shdr | - // | ... | contains offset to section start - // | Elf32_Shdr | - // +------------+ - // - // To strip: - // - leave the Elf32_Ehdr and Elf32_Phdr values in place. - // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep - // - move the sections are keeping up to fill in gaps of sections we want to strip - // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr - // - truncate rest of file - // - - std::vector<Elf32_Shdr> section_headers; - std::vector<Elf32_Word> section_headers_original_indexes; - section_headers.reserve(elf_file->GetSectionHeaderNum()); - - - Elf32_Shdr* string_section = elf_file->GetSectionNameStringSection(); - CHECK(string_section != nullptr); - for (Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) { - Elf32_Shdr* sh = elf_file->GetSectionHeader(i); - CHECK(sh != nullptr); - const char* name = elf_file->GetString(*string_section, sh->sh_name); - if (name == nullptr) { - CHECK_EQ(0U, i); - section_headers.push_back(*sh); - section_headers_original_indexes.push_back(0); - continue; - } - if (StartsWith(name, ".debug") - || (strcmp(name, ".strtab") == 0) - || (strcmp(name, ".symtab") == 0)) { - continue; - } - section_headers.push_back(*sh); - section_headers_original_indexes.push_back(i); - } - CHECK_NE(0U, section_headers.size()); - CHECK_EQ(section_headers.size(), section_headers_original_indexes.size()); - - // section 0 is the NULL section, sections start at offset of first section - CHECK(elf_file->GetSectionHeader(1) != nullptr); - Elf32_Off offset = elf_file->GetSectionHeader(1)->sh_offset; - for (size_t i = 1; i < section_headers.size(); i++) { - Elf32_Shdr& new_sh = section_headers[i]; - Elf32_Shdr* old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]); - CHECK(old_sh != nullptr); - CHECK_EQ(new_sh.sh_name, old_sh->sh_name); - if (old_sh->sh_addralign > 1) { - offset = RoundUp(offset, old_sh->sh_addralign); - } - if (old_sh->sh_offset == offset) { - // already in place - offset += old_sh->sh_size; - continue; - } - // shift section earlier - memmove(elf_file->Begin() + offset, - elf_file->Begin() + old_sh->sh_offset, - old_sh->sh_size); - new_sh.sh_offset = offset; - offset += old_sh->sh_size; - } - - Elf32_Off shoff = offset; - size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf32_Shdr); - memcpy(elf_file->Begin() + offset, §ion_headers[0], section_headers_size_in_bytes); - offset += section_headers_size_in_bytes; - - elf_file->GetHeader().e_shnum = section_headers.size(); - elf_file->GetHeader().e_shoff = shoff; - int result = ftruncate(file->Fd(), offset); - if (result != 0) { - *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s", - file->GetPath().c_str(), strerror(errno)); - return false; - } - return true; -} - -} // namespace art diff --git a/compiler/elf_stripper.h b/compiler/elf_stripper.h deleted file mode 100644 index f1a1d46..0000000 --- a/compiler/elf_stripper.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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_STRIPPER_H_ -#define ART_COMPILER_ELF_STRIPPER_H_ - -#include <string> - -#include "base/macros.h" -#include "os.h" - -namespace art { - -class ElfStripper { - public: - // Strip an ELF file of unneeded debugging information. - // Returns true on success, false on failure. - static bool Strip(File* file, std::string* error_msg); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(ElfStripper); -}; - -} // namespace art - -#endif // ART_COMPILER_ELF_STRIPPER_H_ diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc index 55ee18e..47402f3 100644 --- a/compiler/elf_writer.cc +++ b/compiler/elf_writer.cc @@ -30,8 +30,8 @@ namespace art { -uint32_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) { - Elf32_Addr oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM, +uintptr_t ElfWriter::GetOatDataAddress(ElfFile* elf_file) { + uintptr_t oatdata_address = elf_file->FindSymbolAddress(SHT_DYNSYM, "oatdata", false); CHECK_NE(0U, oatdata_address); @@ -51,4 +51,16 @@ void ElfWriter::GetOatElfInformation(File* file, CHECK_NE(0U, oat_data_offset); } +bool ElfWriter::Fixup(File* file, uintptr_t oat_data_begin) { + std::string error_msg; + std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg)); + CHECK(elf_file.get() != nullptr) << error_msg; + + // Lookup "oatdata" symbol address. + uintptr_t oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get()); + uintptr_t base_address = oat_data_begin - oatdata_address; + + return elf_file->Fixup(base_address); +} + } // namespace art diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h index 03b965a..033c1f8 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -42,7 +42,9 @@ class ElfWriter { size_t& oat_data_offset); // Returns runtime oat_data runtime address for an opened ElfFile. - static uint32_t GetOatDataAddress(ElfFile* elf_file); + static uintptr_t GetOatDataAddress(ElfFile* elf_file); + + static bool Fixup(File* file, uintptr_t oat_data_begin); protected: ElfWriter(const CompilerDriver& driver, File* elf_file) diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 2a37049..5834e8e 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -23,7 +23,7 @@ #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "common_compiler_test.h" -#include "elf_fixup.h" +#include "elf_writer.h" #include "gc/space/image_space.h" #include "image_writer.h" #include "lock_word.h" @@ -101,7 +101,7 @@ TEST_F(ImageTest, WriteRead) { bool success_image = writer.Write(image_file.GetFilename(), dup_oat->GetPath(), dup_oat->GetPath()); ASSERT_TRUE(success_image); - bool success_fixup = ElfFixup::Fixup(dup_oat.get(), writer.GetOatDataBegin()); + bool success_fixup = ElfWriter::Fixup(dup_oat.get(), writer.GetOatDataBegin()); ASSERT_TRUE(success_fixup); } diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 1c8b8d5..6fff5f4 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -811,11 +811,12 @@ void ImageWriter::FixupMethod(ArtMethod* orig, ArtMethod* copy) { } static OatHeader* GetOatHeaderFromElf(ElfFile* elf) { - Elf32_Shdr* data_sec = elf->FindSectionByName(".rodata"); - if (data_sec == nullptr) { + uint64_t data_sec_offset; + bool has_data_sec = elf->GetSectionOffsetAndSize(".rodata", &data_sec_offset, nullptr); + if (!has_data_sec) { return nullptr; } - return reinterpret_cast<OatHeader*>(elf->Begin() + data_sec->sh_offset); + return reinterpret_cast<OatHeader*>(elf->Begin() + data_sec_offset); } void ImageWriter::SetOatChecksumFromElfFile(File* elf_file) { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 09825e2..e1f513d 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -44,8 +44,7 @@ #include "dex/quick/dex_file_to_method_inliner_map.h" #include "driver/compiler_driver.h" #include "driver/compiler_options.h" -#include "elf_fixup.h" -#include "elf_stripper.h" +#include "elf_writer.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" #include "image_writer.h" @@ -472,7 +471,7 @@ class Dex2Oat { PLOG(ERROR) << "Failed to open ELF file: " << oat_filename; return false; } - if (!ElfFixup::Fixup(oat_file.get(), oat_data_begin)) { + if (!ElfWriter::Fixup(oat_file.get(), oat_data_begin)) { LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath(); return false; } diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 50b4ece..c457ecd 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -29,6 +29,7 @@ #include "base/stringprintf.h" #include "elf_utils.h" #include "elf_file.h" +#include "elf_file_impl.h" #include "gc/space/image_space.h" #include "image.h" #include "instruction_set.h" @@ -467,15 +468,16 @@ bool PatchOat::Patch(File* input_oat, off_t delta, File* output_oat, TimingLogge return true; } -template <typename ptr_t> -bool PatchOat::CheckOatFile(const Elf32_Shdr& patches_sec) { - if (patches_sec.sh_type != SHT_OAT_PATCH) { +template <typename ElfFileImpl, typename ptr_t> +bool PatchOat::CheckOatFile(ElfFileImpl* oat_file) { + auto patches_sec = oat_file->FindSectionByName(".oat_patches"); + if (patches_sec->sh_type != SHT_OAT_PATCH) { return false; } - ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset); - ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t)); - Elf32_Shdr* oat_data_sec = oat_file_->FindSectionByName(".rodata"); - Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text"); + ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file->Begin() + patches_sec->sh_offset); + ptr_t* patches_end = patches + (patches_sec->sh_size / sizeof(ptr_t)); + auto oat_data_sec = oat_file->FindSectionByName(".rodata"); + auto oat_text_sec = oat_file->FindSectionByName(".text"); if (oat_data_sec == nullptr) { return false; } @@ -495,14 +497,15 @@ bool PatchOat::CheckOatFile(const Elf32_Shdr& patches_sec) { return true; } -bool PatchOat::PatchOatHeader() { - Elf32_Shdr *rodata_sec = oat_file_->FindSectionByName(".rodata"); +template <typename ElfFileImpl> +bool PatchOat::PatchOatHeader(ElfFileImpl* oat_file) { + auto rodata_sec = oat_file->FindSectionByName(".rodata"); if (rodata_sec == nullptr) { return false; } - OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file_->Begin() + rodata_sec->sh_offset); + OatHeader* oat_header = reinterpret_cast<OatHeader*>(oat_file->Begin() + rodata_sec->sh_offset); if (!oat_header->IsValid()) { - LOG(ERROR) << "Elf file " << oat_file_->GetFile().GetPath() << " has an invalid oat header"; + LOG(ERROR) << "Elf file " << oat_file->GetFile().GetPath() << " has an invalid oat header"; return false; } oat_header->RelocateOat(delta_); @@ -510,28 +513,31 @@ bool PatchOat::PatchOatHeader() { } bool PatchOat::PatchElf() { + if (oat_file_->is_elf64_) + return PatchElf<ElfFileImpl64>(oat_file_->GetImpl64()); + else + return PatchElf<ElfFileImpl32>(oat_file_->GetImpl32()); +} + +template <typename ElfFileImpl> +bool PatchOat::PatchElf(ElfFileImpl* oat_file) { TimingLogger::ScopedTiming t("Fixup Elf Text Section", timings_); - if (!PatchTextSection()) { + if (!PatchTextSection<ElfFileImpl>(oat_file)) { return false; } - if (!PatchOatHeader()) { + if (!PatchOatHeader<ElfFileImpl>(oat_file)) { return false; } bool need_fixup = false; - t.NewTiming("Fixup Elf Headers"); - // Fixup Phdr's - for (unsigned int i = 0; i < oat_file_->GetProgramHeaderNum(); i++) { - Elf32_Phdr* hdr = oat_file_->GetProgramHeader(i); - CHECK(hdr != nullptr); + for (unsigned int i = 0; i < oat_file->GetProgramHeaderNum(); i++) { + auto hdr = oat_file->GetProgramHeader(i); if (hdr->p_vaddr != 0 && hdr->p_vaddr != hdr->p_offset) { need_fixup = true; - hdr->p_vaddr += delta_; } if (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset) { need_fixup = true; - hdr->p_paddr += delta_; } } if (!need_fixup) { @@ -539,67 +545,39 @@ bool PatchOat::PatchElf() { // their addr. Therefore we do not need to update these parts. return true; } + + t.NewTiming("Fixup Elf Headers"); + // Fixup Phdr's + oat_file->FixupProgramHeaders(delta_); + t.NewTiming("Fixup Section Headers"); - for (unsigned int i = 0; i < oat_file_->GetSectionHeaderNum(); i++) { - Elf32_Shdr* hdr = oat_file_->GetSectionHeader(i); - CHECK(hdr != nullptr); - if (hdr->sh_addr != 0) { - hdr->sh_addr += delta_; - } - } + // Fixup Shdr's + oat_file->FixupSectionHeaders(delta_); t.NewTiming("Fixup Dynamics"); - for (Elf32_Word i = 0; i < oat_file_->GetDynamicNum(); i++) { - Elf32_Dyn& dyn = oat_file_->GetDynamic(i); - if (IsDynamicSectionPointer(dyn.d_tag, oat_file_->GetHeader().e_machine)) { - dyn.d_un.d_ptr += delta_; - } - } + oat_file->FixupDynamic(delta_); t.NewTiming("Fixup Elf Symbols"); // Fixup dynsym - Elf32_Shdr* dynsym_sec = oat_file_->FindSectionByName(".dynsym"); - CHECK(dynsym_sec != nullptr); - if (!PatchSymbols(dynsym_sec)) { + if (!oat_file->FixupSymbols(delta_, true)) { return false; } - // Fixup symtab - Elf32_Shdr* symtab_sec = oat_file_->FindSectionByName(".symtab"); - if (symtab_sec != nullptr) { - if (!PatchSymbols(symtab_sec)) { - return false; - } + if (!oat_file->FixupSymbols(delta_, false)) { + return false; } t.NewTiming("Fixup Debug Sections"); - if (!oat_file_->FixupDebugSections(delta_)) { + if (!oat_file->FixupDebugSections(delta_)) { return false; } return true; } -bool PatchOat::PatchSymbols(Elf32_Shdr* section) { - Elf32_Sym* syms = reinterpret_cast<Elf32_Sym*>(oat_file_->Begin() + section->sh_offset); - const Elf32_Sym* last_sym = - reinterpret_cast<Elf32_Sym*>(oat_file_->Begin() + section->sh_offset + section->sh_size); - CHECK_EQ(section->sh_size % sizeof(Elf32_Sym), 0u) - << "Symtab section size is not multiple of symbol size"; - for (; syms < last_sym; syms++) { - uint8_t sttype = ELF32_ST_TYPE(syms->st_info); - Elf32_Word shndx = syms->st_shndx; - if (shndx != SHN_ABS && shndx != SHN_COMMON && shndx != SHN_UNDEF && - (sttype == STT_FUNC || sttype == STT_OBJECT)) { - CHECK_NE(syms->st_value, 0u); - syms->st_value += delta_; - } - } - return true; -} - -bool PatchOat::PatchTextSection() { - Elf32_Shdr* patches_sec = oat_file_->FindSectionByName(".oat_patches"); +template <typename ElfFileImpl> +bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) { + auto patches_sec = oat_file->FindSectionByName(".oat_patches"); if (patches_sec == nullptr) { LOG(ERROR) << ".oat_patches section not found. Aborting patch"; return false; @@ -611,9 +589,9 @@ bool PatchOat::PatchTextSection() { switch (patches_sec->sh_entsize) { case sizeof(uint32_t): - return PatchTextSection<uint32_t>(*patches_sec); + return PatchTextSection<ElfFileImpl, uint32_t>(oat_file); case sizeof(uint64_t): - return PatchTextSection<uint64_t>(*patches_sec); + return PatchTextSection<ElfFileImpl, uint64_t>(oat_file); default: LOG(ERROR) << ".oat_patches Entsize of " << patches_sec->sh_entsize << "bits " << "is not valid"; @@ -621,14 +599,16 @@ bool PatchOat::PatchTextSection() { } } -template <typename ptr_t> -bool PatchOat::PatchTextSection(const Elf32_Shdr& patches_sec) { - DCHECK(CheckOatFile<ptr_t>(patches_sec)) << "Oat file invalid"; - ptr_t* patches = reinterpret_cast<ptr_t*>(oat_file_->Begin() + patches_sec.sh_offset); - ptr_t* patches_end = patches + (patches_sec.sh_size / sizeof(ptr_t)); - Elf32_Shdr* oat_text_sec = oat_file_->FindSectionByName(".text"); +template <typename ElfFileImpl, typename patch_loc_t> +bool PatchOat::PatchTextSection(ElfFileImpl* oat_file) { + bool oat_file_valid = CheckOatFile<ElfFileImpl, patch_loc_t>(oat_file); + CHECK(oat_file_valid) << "Oat file invalid"; + auto patches_sec = oat_file->FindSectionByName(".oat_patches"); + patch_loc_t* patches = reinterpret_cast<patch_loc_t*>(oat_file->Begin() + patches_sec->sh_offset); + patch_loc_t* patches_end = patches + (patches_sec->sh_size / sizeof(patch_loc_t)); + auto oat_text_sec = oat_file->FindSectionByName(".text"); CHECK(oat_text_sec != nullptr); - byte* to_patch = oat_file_->Begin() + oat_text_sec->sh_offset; + byte* to_patch = oat_file->Begin() + oat_text_sec->sh_offset; uintptr_t to_patch_end = reinterpret_cast<uintptr_t>(to_patch) + oat_text_sec->sh_size; for (; patches < patches_end; patches++) { diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index 9086d58..7dd95f5 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -76,12 +76,15 @@ class PatchOat { // Patches oat in place, modifying the oat_file given to the constructor. bool PatchElf(); - bool PatchTextSection(); + template <typename ElfFileImpl> + bool PatchElf(ElfFileImpl* oat_file); + template <typename ElfFileImpl> + bool PatchTextSection(ElfFileImpl* oat_file); // Templatized version to actually do the patching with the right sized offsets. - template <typename ptr_t> bool PatchTextSection(const Elf32_Shdr& patches_sec); - template <typename ptr_t> bool CheckOatFile(const Elf32_Shdr& patches_sec); - bool PatchOatHeader(); - bool PatchSymbols(Elf32_Shdr* section); + template <typename ElfFileImpl, typename patch_loc_t> bool PatchTextSection(ElfFileImpl* oat_file); + template <typename ElfFileImpl, typename patch_loc_t> bool CheckOatFile(ElfFileImpl* oat_filec); + template <typename ElfFileImpl> + bool PatchOatHeader(ElfFileImpl* oat_file); bool PatchImage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/elf.h b/runtime/elf.h index 6e007a2..60b5248 100644 --- a/runtime/elf.h +++ b/runtime/elf.h @@ -1411,6 +1411,7 @@ struct Elf32_Sym { // BEGIN android-added for <elf.h> compat static inline unsigned char ELF32_ST_TYPE(unsigned char st_info) { return st_info & 0x0f; } +static inline unsigned char ELF64_ST_TYPE(unsigned char st_info) { return st_info & 0x0f; } // END android-added for <elf.h> compat // Symbol table entries for ELF64. diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index 65a557b..3b8358d 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -16,6 +16,7 @@ #include "elf_file.h" +#include <inttypes.h> #include <sys/types.h> #include <unistd.h> @@ -106,7 +107,12 @@ static void UnregisterCodeEntry(JITCodeEntry* entry) { delete entry; } -ElfFile::ElfFile(File* file, bool writable, bool program_header_only) +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::ElfFileImpl(File* file, bool writable, bool program_header_only) : file_(file), writable_(writable), program_header_only_(program_header_only), @@ -128,9 +134,20 @@ ElfFile::ElfFile(File* file, bool writable, bool program_header_only) CHECK(file != nullptr); } -ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, - std::string* error_msg) { - std::unique_ptr<ElfFile> elf_file(new ElfFile(file, writable, program_header_only)); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>* + ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::Open(File* file, bool writable, bool program_header_only, + std::string* error_msg) { + std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>> + elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + (file, writable, program_header_only)); int prot; int flags; if (writable) { @@ -146,15 +163,31 @@ ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, return elf_file.release(); } -ElfFile* ElfFile::Open(File* file, int prot, int flags, std::string* error_msg) { - std::unique_ptr<ElfFile> elf_file(new ElfFile(file, (prot & PROT_WRITE) == PROT_WRITE, false)); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>* + ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::Open(File* file, int prot, int flags, std::string* error_msg) { + std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>> + elf_file(new ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + (file, (prot & PROT_WRITE) == PROT_WRITE, false)); if (!elf_file->Setup(prot, flags, error_msg)) { return nullptr; } return elf_file.release(); } -bool ElfFile::Setup(int prot, int flags, std::string* error_msg) { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::Setup(int prot, int flags, std::string* error_msg) { int64_t temp_file_length = file_->GetLength(); if (temp_file_length < 0) { errno = -temp_file_length; @@ -163,16 +196,16 @@ bool ElfFile::Setup(int prot, int flags, std::string* error_msg) { return false; } size_t file_length = static_cast<size_t>(temp_file_length); - if (file_length < sizeof(Elf32_Ehdr)) { + if (file_length < sizeof(Elf_Ehdr)) { *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF header of " - "%zd bytes: '%s'", file_length, sizeof(Elf32_Ehdr), + "%zd bytes: '%s'", file_length, sizeof(Elf_Ehdr), file_->GetPath().c_str()); return false; } if (program_header_only_) { // first just map ELF header to get program header size information - size_t elf_header_size = sizeof(Elf32_Ehdr); + size_t elf_header_size = sizeof(Elf_Ehdr); if (!SetMap(MemMap::MapFile(elf_header_size, prot, flags, file_->Fd(), 0, file_->GetPath().c_str(), error_msg), error_msg)) { @@ -183,7 +216,7 @@ bool ElfFile::Setup(int prot, int flags, std::string* error_msg) { if (file_length < program_header_size) { *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF program " "header of %zd bytes: '%s'", file_length, - sizeof(Elf32_Ehdr), file_->GetPath().c_str()); + sizeof(Elf_Ehdr), file_->GetPath().c_str()); return false; } if (!SetMap(MemMap::MapFile(program_header_size, prot, flags, file_->Fd(), 0, @@ -215,7 +248,7 @@ bool ElfFile::Setup(int prot, int flags, std::string* error_msg) { } // Find shstrtab. - Elf32_Shdr* shstrtab_section_header = GetSectionNameStringSection(); + Elf_Shdr* shstrtab_section_header = GetSectionNameStringSection(); if (shstrtab_section_header == nullptr) { *error_msg = StringPrintf("Failed to find shstrtab section header in ELF file: '%s'", file_->GetPath().c_str()); @@ -236,8 +269,8 @@ bool ElfFile::Setup(int prot, int flags, std::string* error_msg) { } // Find other sections from section headers - for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) { - Elf32_Shdr* section_header = GetSectionHeader(i); + for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) { + Elf_Shdr* section_header = GetSectionHeader(i); if (section_header == nullptr) { *error_msg = StringPrintf("Failed to find section header for section %d in ELF file: '%s'", i, file_->GetPath().c_str()); @@ -311,7 +344,12 @@ bool ElfFile::Setup(int prot, int flags, std::string* error_msg) { return true; } -ElfFile::~ElfFile() { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::~ElfFileImpl() { STLDeleteElements(&segments_); delete symtab_symbol_table_; delete dynsym_symbol_table_; @@ -321,8 +359,13 @@ ElfFile::~ElfFile() { } } -bool ElfFile::CheckAndSet(Elf32_Off offset, const char* label, - byte** target, std::string* error_msg) { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::CheckAndSet(Elf32_Off offset, const char* label, + byte** target, std::string* error_msg) { if (Begin() + offset >= End()) { *error_msg = StringPrintf("Offset %d is out of range for %s in ELF file: '%s'", offset, label, file_->GetPath().c_str()); @@ -332,18 +375,23 @@ bool ElfFile::CheckAndSet(Elf32_Off offset, const char* label, return true; } -bool ElfFile::CheckSectionsLinked(const byte* source, const byte* target) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::CheckSectionsLinked(const byte* source, const byte* target) const { // Only works in whole-program mode, as we need to iterate over the sections. // Note that we normally can't search by type, as duplicates are allowed for most section types. if (program_header_only_) { return true; } - Elf32_Shdr* source_section = nullptr; - Elf32_Word target_index = 0; + Elf_Shdr* source_section = nullptr; + Elf_Word target_index = 0; bool target_found = false; - for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) { - Elf32_Shdr* section_header = GetSectionHeader(i); + for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) { + Elf_Shdr* section_header = GetSectionHeader(i); if (Begin() + section_header->sh_offset == source) { // Found the source. @@ -363,7 +411,12 @@ bool ElfFile::CheckSectionsLinked(const byte* source, const byte* target) const return target_found && source_section != nullptr && source_section->sh_link == target_index; } -bool ElfFile::CheckSectionsExist(std::string* error_msg) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::CheckSectionsExist(std::string* error_msg) const { if (!program_header_only_) { // If in full mode, need section headers. if (section_headers_start_ == nullptr) { @@ -432,7 +485,12 @@ bool ElfFile::CheckSectionsExist(std::string* error_msg) const { return true; } -bool ElfFile::SetMap(MemMap* map, std::string* error_msg) { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::SetMap(MemMap* map, std::string* error_msg) { if (map == nullptr) { // MemMap::Open should have already set an error. DCHECK(!error_msg->empty()); @@ -442,7 +500,7 @@ bool ElfFile::SetMap(MemMap* map, std::string* error_msg) { CHECK(map_.get() != nullptr) << file_->GetPath(); CHECK(map_->Begin() != nullptr) << file_->GetPath(); - header_ = reinterpret_cast<Elf32_Ehdr*>(map_->Begin()); + header_ = reinterpret_cast<Elf_Ehdr*>(map_->Begin()); if ((ELFMAG0 != header_->e_ident[EI_MAG0]) || (ELFMAG1 != header_->e_ident[EI_MAG1]) || (ELFMAG2 != header_->e_ident[EI_MAG2]) @@ -456,9 +514,10 @@ bool ElfFile::SetMap(MemMap* map, std::string* error_msg) { header_->e_ident[EI_MAG3]); return false; } - if (ELFCLASS32 != header_->e_ident[EI_CLASS]) { + uint8_t elf_class = (sizeof(Elf_Addr) == sizeof(Elf64_Addr)) ? ELFCLASS64 : ELFCLASS32; + if (elf_class != header_->e_ident[EI_CLASS]) { *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d in %s, found %d", - ELFCLASS32, + elf_class, file_->GetPath().c_str(), header_->e_ident[EI_CLASS]); return false; @@ -495,7 +554,7 @@ bool ElfFile::SetMap(MemMap* map, std::string* error_msg) { *error_msg = StringPrintf("Failed to find expected e_entry value %d in %s, found %d", 0, file_->GetPath().c_str(), - header_->e_entry); + static_cast<int32_t>(header_->e_entry)); return false; } if (0 == header_->e_phoff) { @@ -548,15 +607,15 @@ bool ElfFile::SetMap(MemMap* map, std::string* error_msg) { if (!program_header_only_) { if (header_->e_phoff >= Size()) { - *error_msg = StringPrintf("Failed to find e_phoff value %d less than %zd in %s", - header_->e_phoff, + *error_msg = StringPrintf("Failed to find e_phoff value %" PRIu64 " less than %zd in %s", + static_cast<uint64_t>(header_->e_phoff), Size(), file_->GetPath().c_str()); return false; } if (header_->e_shoff >= Size()) { - *error_msg = StringPrintf("Failed to find e_shoff value %d less than %zd in %s", - header_->e_shoff, + *error_msg = StringPrintf("Failed to find e_shoff value %" PRIu64 " less than %zd in %s", + static_cast<uint64_t>(header_->e_shoff), Size(), file_->GetPath().c_str()); return false; @@ -565,39 +624,64 @@ bool ElfFile::SetMap(MemMap* map, std::string* error_msg) { return true; } - -Elf32_Ehdr& ElfFile::GetHeader() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Ehdr& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetHeader() const { CHECK(header_ != nullptr); // Header has been checked in SetMap. This is a sanity check. return *header_; } -byte* ElfFile::GetProgramHeadersStart() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +byte* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetProgramHeadersStart() const { CHECK(program_headers_start_ != nullptr); // Header has been set in Setup. This is a sanity // check. return program_headers_start_; } -byte* ElfFile::GetSectionHeadersStart() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +byte* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSectionHeadersStart() const { CHECK(!program_header_only_); // Only used in "full" mode. CHECK(section_headers_start_ != nullptr); // Is checked in CheckSectionsExist. Sanity check. return section_headers_start_; } -Elf32_Phdr& ElfFile::GetDynamicProgramHeader() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Phdr& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetDynamicProgramHeader() const { CHECK(dynamic_program_header_ != nullptr); // Is checked in CheckSectionsExist. Sanity check. return *dynamic_program_header_; } -Elf32_Dyn* ElfFile::GetDynamicSectionStart() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Dyn* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetDynamicSectionStart() const { CHECK(dynamic_section_start_ != nullptr); // Is checked in CheckSectionsExist. Sanity check. return dynamic_section_start_; } -static bool IsSymbolSectionType(Elf32_Word section_type) { - return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM)); -} - -Elf32_Sym* ElfFile::GetSymbolSectionStart(Elf32_Word section_type) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSymbolSectionStart(Elf_Word section_type) const { CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; switch (section_type) { case SHT_SYMTAB: { @@ -615,7 +699,12 @@ Elf32_Sym* ElfFile::GetSymbolSectionStart(Elf32_Word section_type) const { } } -const char* ElfFile::GetStringSectionStart(Elf32_Word section_type) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetStringSectionStart(Elf_Word section_type) const { CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; switch (section_type) { case SHT_SYMTAB: { @@ -631,7 +720,12 @@ const char* ElfFile::GetStringSectionStart(Elf32_Word section_type) const { } } -const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetString(Elf_Word section_type, Elf_Word i) const { CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; if (i == 0) { return nullptr; @@ -646,19 +740,39 @@ const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const { // WARNING: The following methods do not check for an error condition (non-existent hash section). // It is the caller's job to do this. -Elf32_Word* ElfFile::GetHashSectionStart() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetHashSectionStart() const { return hash_section_start_; } -Elf32_Word ElfFile::GetHashBucketNum() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetHashBucketNum() const { return GetHashSectionStart()[0]; } -Elf32_Word ElfFile::GetHashChainNum() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetHashChainNum() const { return GetHashSectionStart()[1]; } -Elf32_Word ElfFile::GetHashBucket(size_t i, bool* ok) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetHashBucket(size_t i, bool* ok) const { if (i >= GetHashBucketNum()) { *ok = false; return 0; @@ -668,7 +782,12 @@ Elf32_Word ElfFile::GetHashBucket(size_t i, bool* ok) const { return GetHashSectionStart()[2 + i]; } -Elf32_Word ElfFile::GetHashChain(size_t i, bool* ok) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetHashChain(size_t i, bool* ok) const { if (i >= GetHashBucketNum()) { *ok = false; return 0; @@ -678,22 +797,37 @@ Elf32_Word ElfFile::GetHashChain(size_t i, bool* ok) const { return GetHashSectionStart()[2 + GetHashBucketNum() + i]; } -Elf32_Word ElfFile::GetProgramHeaderNum() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetProgramHeaderNum() const { return GetHeader().e_phnum; } -Elf32_Phdr* ElfFile::GetProgramHeader(Elf32_Word i) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Phdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetProgramHeader(Elf_Word i) const { CHECK_LT(i, GetProgramHeaderNum()) << file_->GetPath(); // Sanity check for caller. byte* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize); if (program_header >= End()) { return nullptr; // Failure condition. } - return reinterpret_cast<Elf32_Phdr*>(program_header); + return reinterpret_cast<Elf_Phdr*>(program_header); } -Elf32_Phdr* ElfFile::FindProgamHeaderByType(Elf32_Word type) const { - for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) { - Elf32_Phdr* program_header = GetProgramHeader(i); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Phdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindProgamHeaderByType(Elf_Word type) const { + for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) { + Elf_Phdr* program_header = GetProgramHeader(i); if (program_header->p_type == type) { return program_header; } @@ -701,11 +835,21 @@ Elf32_Phdr* ElfFile::FindProgamHeaderByType(Elf32_Word type) const { return nullptr; } -Elf32_Word ElfFile::GetSectionHeaderNum() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSectionHeaderNum() const { return GetHeader().e_shnum; } -Elf32_Shdr* ElfFile::GetSectionHeader(Elf32_Word i) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSectionHeader(Elf_Word i) const { // Can only access arbitrary sections when we have the whole file, not just program header. // Even if we Load(), it doesn't bring in all the sections. CHECK(!program_header_only_) << file_->GetPath(); @@ -716,15 +860,20 @@ Elf32_Shdr* ElfFile::GetSectionHeader(Elf32_Word i) const { if (section_header >= End()) { return nullptr; // Failure condition. } - return reinterpret_cast<Elf32_Shdr*>(section_header); + return reinterpret_cast<Elf_Shdr*>(section_header); } -Elf32_Shdr* ElfFile::FindSectionByType(Elf32_Word type) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindSectionByType(Elf_Word type) const { // Can only access arbitrary sections when we have the whole file, not just program header. // We could change this to switch on known types if they were detected during loading. CHECK(!program_header_only_) << file_->GetPath(); - for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) { - Elf32_Shdr* section_header = GetSectionHeader(i); + for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) { + Elf_Shdr* section_header = GetSectionHeader(i); if (section_header->sh_type == type) { return section_header; } @@ -746,16 +895,26 @@ static unsigned elfhash(const char *_name) { return h; } -Elf32_Shdr* ElfFile::GetSectionNameStringSection() const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSectionNameStringSection() const { return GetSectionHeader(GetHeader().e_shstrndx); } -const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +const byte* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindDynamicSymbolAddress(const std::string& symbol_name) const { // Check that we have a hash section. if (GetHashSectionStart() == nullptr) { return nullptr; // Failure condition. } - const Elf32_Sym* sym = FindDynamicSymbol(symbol_name); + const Elf_Sym* sym = FindDynamicSymbol(symbol_name); if (sym != nullptr) { return base_address_ + sym->st_value; } else { @@ -764,20 +923,25 @@ const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) co } // WARNING: Only called from FindDynamicSymbolAddress. Elides check for hash section. -const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +const Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindDynamicSymbol(const std::string& symbol_name) const { if (GetHashBucketNum() == 0) { // No dynamic symbols at all. return nullptr; } - Elf32_Word hash = elfhash(symbol_name.c_str()); - Elf32_Word bucket_index = hash % GetHashBucketNum(); + Elf_Word hash = elfhash(symbol_name.c_str()); + Elf_Word bucket_index = hash % GetHashBucketNum(); bool ok; - Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok); + Elf_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok); if (!ok) { return nullptr; } while (symbol_and_chain_index != 0 /* STN_UNDEF */) { - Elf32_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index); + Elf_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index); if (symbol == nullptr) { return nullptr; // Failure condition. } @@ -793,23 +957,49 @@ const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) cons return nullptr; } -Elf32_Word ElfFile::GetSymbolNum(Elf32_Shdr& section_header) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::IsSymbolSectionType(Elf_Word section_type) { + return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM)); +} + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSymbolNum(Elf_Shdr& section_header) const { CHECK(IsSymbolSectionType(section_header.sh_type)) << file_->GetPath() << " " << section_header.sh_type; CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath(); return section_header.sh_size / section_header.sh_entsize; } -Elf32_Sym* ElfFile::GetSymbol(Elf32_Word section_type, - Elf32_Word i) const { - Elf32_Sym* sym_start = GetSymbolSectionStart(section_type); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSymbol(Elf_Word section_type, + Elf_Word i) const { + Elf_Sym* sym_start = GetSymbolSectionStart(section_type); if (sym_start == nullptr) { return nullptr; } return sym_start + i; } -ElfFile::SymbolTable** ElfFile::GetSymbolTable(Elf32_Word section_type) { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +typename ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::SymbolTable** ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetSymbolTable(Elf_Word section_type) { CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; switch (section_type) { case SHT_SYMTAB: { @@ -825,9 +1015,14 @@ ElfFile::SymbolTable** ElfFile::GetSymbolTable(Elf32_Word section_type) { } } -Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, - const std::string& symbol_name, - bool build_map) { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Sym* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindSymbolByName(Elf_Word section_type, + const std::string& symbol_name, + bool build_map) { CHECK(!program_header_only_) << file_->GetPath(); CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type; @@ -836,20 +1031,22 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, if (*symbol_table == nullptr) { DCHECK(build_map); *symbol_table = new SymbolTable; - Elf32_Shdr* symbol_section = FindSectionByType(section_type); + Elf_Shdr* symbol_section = FindSectionByType(section_type); if (symbol_section == nullptr) { return nullptr; // Failure condition. } - Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link); + Elf_Shdr* string_section = GetSectionHeader(symbol_section->sh_link); if (string_section == nullptr) { return nullptr; // Failure condition. } for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) { - Elf32_Sym* symbol = GetSymbol(section_type, i); + Elf_Sym* symbol = GetSymbol(section_type, i); if (symbol == nullptr) { return nullptr; // Failure condition. } - unsigned char type = ELF32_ST_TYPE(symbol->st_info); + unsigned char type = (sizeof(Elf_Addr) == sizeof(Elf64_Addr)) + ? ELF64_ST_TYPE(symbol->st_info) + : ELF32_ST_TYPE(symbol->st_info); if (type == STT_NOTYPE) { continue; } @@ -857,7 +1054,7 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, if (name == nullptr) { continue; } - std::pair<SymbolTable::iterator, bool> result = + std::pair<typename SymbolTable::iterator, bool> result = (*symbol_table)->insert(std::make_pair(name, symbol)); if (!result.second) { // If a duplicate, make sure it has the same logical value. Seen on x86. @@ -872,7 +1069,7 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, } } CHECK(*symbol_table != nullptr); - SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name); + typename SymbolTable::const_iterator it = (*symbol_table)->find(symbol_name); if (it == (*symbol_table)->end()) { return nullptr; } @@ -880,16 +1077,16 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, } // Fall back to linear search - Elf32_Shdr* symbol_section = FindSectionByType(section_type); + Elf_Shdr* symbol_section = FindSectionByType(section_type); if (symbol_section == nullptr) { return nullptr; } - Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link); + Elf_Shdr* string_section = GetSectionHeader(symbol_section->sh_link); if (string_section == nullptr) { return nullptr; } for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) { - Elf32_Sym* symbol = GetSymbol(section_type, i); + Elf_Sym* symbol = GetSymbol(section_type, i); if (symbol == nullptr) { return nullptr; // Failure condition. } @@ -904,20 +1101,30 @@ Elf32_Sym* ElfFile::FindSymbolByName(Elf32_Word section_type, return nullptr; } -Elf32_Addr ElfFile::FindSymbolAddress(Elf32_Word section_type, - const std::string& symbol_name, - bool build_map) { - Elf32_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Addr ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindSymbolAddress(Elf_Word section_type, + const std::string& symbol_name, + bool build_map) { + Elf_Sym* symbol = FindSymbolByName(section_type, symbol_name, build_map); if (symbol == nullptr) { return 0; } return symbol->st_value; } -const char* ElfFile::GetString(Elf32_Shdr& string_section, Elf32_Word i) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +const char* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetString(Elf_Shdr& string_section, Elf_Word i) const { CHECK(!program_header_only_) << file_->GetPath(); // TODO: remove this static_cast from enum when using -std=gnu++0x - if (static_cast<Elf32_Word>(SHT_STRTAB) != string_section.sh_type) { + if (static_cast<Elf_Word>(SHT_STRTAB) != string_section.sh_type) { return nullptr; // Failure condition. } if (i >= string_section.sh_size) { @@ -934,18 +1141,33 @@ const char* ElfFile::GetString(Elf32_Shdr& string_section, Elf32_Word i) const { return reinterpret_cast<const char*>(string); } -Elf32_Word ElfFile::GetDynamicNum() const { - return GetDynamicProgramHeader().p_filesz / sizeof(Elf32_Dyn); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetDynamicNum() const { + return GetDynamicProgramHeader().p_filesz / sizeof(Elf_Dyn); } -Elf32_Dyn& ElfFile::GetDynamic(Elf32_Word i) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Dyn& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetDynamic(Elf_Word i) const { CHECK_LT(i, GetDynamicNum()) << file_->GetPath(); return *(GetDynamicSectionStart() + i); } -Elf32_Dyn* ElfFile::FindDynamicByType(Elf32_Sword type) const { - for (Elf32_Word i = 0; i < GetDynamicNum(); i++) { - Elf32_Dyn* dyn = &GetDynamic(i); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Dyn* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindDynamicByType(Elf_Sword type) const { + for (Elf_Word i = 0; i < GetDynamicNum(); i++) { + Elf_Dyn* dyn = &GetDynamic(i); if (dyn->d_tag == type) { return dyn; } @@ -953,8 +1175,13 @@ Elf32_Dyn* ElfFile::FindDynamicByType(Elf32_Sword type) const { return NULL; } -Elf32_Word ElfFile::FindDynamicValueByType(Elf32_Sword type) const { - Elf32_Dyn* dyn = FindDynamicByType(type); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindDynamicValueByType(Elf_Sword type) const { + Elf_Dyn* dyn = FindDynamicByType(type); if (dyn == NULL) { return 0; } else { @@ -962,53 +1189,88 @@ Elf32_Word ElfFile::FindDynamicValueByType(Elf32_Sword type) const { } } -Elf32_Rel* ElfFile::GetRelSectionStart(Elf32_Shdr& section_header) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Rel* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetRelSectionStart(Elf_Shdr& section_header) const { CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; - return reinterpret_cast<Elf32_Rel*>(Begin() + section_header.sh_offset); + return reinterpret_cast<Elf_Rel*>(Begin() + section_header.sh_offset); } -Elf32_Word ElfFile::GetRelNum(Elf32_Shdr& section_header) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetRelNum(Elf_Shdr& section_header) const { CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; CHECK_NE(0U, section_header.sh_entsize) << file_->GetPath(); return section_header.sh_size / section_header.sh_entsize; } -Elf32_Rel& ElfFile::GetRel(Elf32_Shdr& section_header, Elf32_Word i) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Rel& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetRel(Elf_Shdr& section_header, Elf_Word i) const { CHECK(SHT_REL == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; CHECK_LT(i, GetRelNum(section_header)) << file_->GetPath(); return *(GetRelSectionStart(section_header) + i); } -Elf32_Rela* ElfFile::GetRelaSectionStart(Elf32_Shdr& section_header) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Rela* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetRelaSectionStart(Elf_Shdr& section_header) const { CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; - return reinterpret_cast<Elf32_Rela*>(Begin() + section_header.sh_offset); + return reinterpret_cast<Elf_Rela*>(Begin() + section_header.sh_offset); } -Elf32_Word ElfFile::GetRelaNum(Elf32_Shdr& section_header) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Word ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetRelaNum(Elf_Shdr& section_header) const { CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; return section_header.sh_size / section_header.sh_entsize; } -Elf32_Rela& ElfFile::GetRela(Elf32_Shdr& section_header, Elf32_Word i) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Rela& ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetRela(Elf_Shdr& section_header, Elf_Word i) const { CHECK(SHT_RELA == section_header.sh_type) << file_->GetPath() << " " << section_header.sh_type; CHECK_LT(i, GetRelaNum(section_header)) << file_->GetPath(); return *(GetRelaSectionStart(section_header) + i); } // Base on bionic phdr_table_get_load_size -size_t ElfFile::GetLoadedSize() const { - Elf32_Addr min_vaddr = 0xFFFFFFFFu; - Elf32_Addr max_vaddr = 0x00000000u; - for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) { - Elf32_Phdr* program_header = GetProgramHeader(i); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +size_t ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GetLoadedSize() const { + Elf_Addr min_vaddr = 0xFFFFFFFFu; + Elf_Addr max_vaddr = 0x00000000u; + for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) { + Elf_Phdr* program_header = GetProgramHeader(i); if (program_header->p_type != PT_LOAD) { continue; } - Elf32_Addr begin_vaddr = program_header->p_vaddr; + Elf_Addr begin_vaddr = program_header->p_vaddr; if (begin_vaddr < min_vaddr) { min_vaddr = begin_vaddr; } - Elf32_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz; + Elf_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz; if (end_vaddr > max_vaddr) { max_vaddr = end_vaddr; } @@ -1020,7 +1282,12 @@ size_t ElfFile::GetLoadedSize() const { return loaded_size; } -bool ElfFile::Load(bool executable, std::string* error_msg) { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::Load(bool executable, std::string* error_msg) { CHECK(program_header_only_) << file_->GetPath(); if (executable) { @@ -1057,8 +1324,8 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { } bool reserved = false; - for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) { - Elf32_Phdr* program_header = GetProgramHeader(i); + for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) { + Elf_Phdr* program_header = GetProgramHeader(i); if (program_header == nullptr) { *error_msg = StringPrintf("No program header for entry %d in ELF file %s.", i, file_->GetPath().c_str()); @@ -1137,8 +1404,8 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { } if (file_length < (program_header->p_offset + program_header->p_memsz)) { *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment " - "%d of %d bytes: '%s'", file_length, i, - program_header->p_offset + program_header->p_memsz, + "%d of %" PRIu64 " bytes: '%s'", file_length, i, + static_cast<uint64_t>(program_header->p_offset + program_header->p_memsz), file_->GetPath().c_str()); return false; } @@ -1170,10 +1437,10 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { file_->GetPath().c_str()); return false; } - dynamic_section_start_ = reinterpret_cast<Elf32_Dyn*>(dsptr); + dynamic_section_start_ = reinterpret_cast<Elf_Dyn*>(dsptr); - for (Elf32_Word i = 0; i < GetDynamicNum(); i++) { - Elf32_Dyn& elf_dyn = GetDynamic(i); + for (Elf_Word i = 0; i < GetDynamicNum(); i++) { + Elf_Dyn& elf_dyn = GetDynamic(i); byte* d_ptr = base_address_ + elf_dyn.d_un.d_ptr; switch (elf_dyn.d_tag) { case DT_HASH: { @@ -1182,7 +1449,7 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { d_ptr, file_->GetPath().c_str()); return false; } - hash_section_start_ = reinterpret_cast<Elf32_Word*>(d_ptr); + hash_section_start_ = reinterpret_cast<Elf_Word*>(d_ptr); break; } case DT_STRTAB: { @@ -1200,7 +1467,7 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { d_ptr, file_->GetPath().c_str()); return false; } - dynsym_section_start_ = reinterpret_cast<Elf32_Sym*>(d_ptr); + dynsym_section_start_ = reinterpret_cast<Elf_Sym*>(d_ptr); break; } case DT_NULL: { @@ -1228,7 +1495,12 @@ bool ElfFile::Load(bool executable, std::string* error_msg) { return true; } -bool ElfFile::ValidPointer(const byte* start) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::ValidPointer(const byte* start) const { for (size_t i = 0; i < segments_.size(); ++i) { const MemMap* segment = segments_[i]; if (segment->Begin() <= start && start < segment->End()) { @@ -1239,14 +1511,19 @@ bool ElfFile::ValidPointer(const byte* start) const { } -Elf32_Shdr* ElfFile::FindSectionByName(const std::string& name) const { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +Elf_Shdr* ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FindSectionByName(const std::string& name) const { CHECK(!program_header_only_); - Elf32_Shdr* shstrtab_sec = GetSectionNameStringSection(); + Elf_Shdr* shstrtab_sec = GetSectionNameStringSection(); if (shstrtab_sec == nullptr) { return nullptr; } for (uint32_t i = 0; i < GetSectionHeaderNum(); i++) { - Elf32_Shdr* shdr = GetSectionHeader(i); + Elf_Shdr* shdr = GetSectionHeader(i); if (shdr == nullptr) { return nullptr; } @@ -1731,14 +2008,19 @@ static bool FixupDebugInfo(off_t base_address_delta, DebugInfoIterator* iter) { return true; } -bool ElfFile::FixupDebugSections(off_t base_address_delta) { - const Elf32_Shdr* debug_info = FindSectionByName(".debug_info"); - const Elf32_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev"); - const Elf32_Shdr* eh_frame = FindSectionByName(".eh_frame"); - const Elf32_Shdr* debug_str = FindSectionByName(".debug_str"); - const Elf32_Shdr* debug_line = FindSectionByName(".debug_line"); - const Elf32_Shdr* strtab_sec = FindSectionByName(".strtab"); - const Elf32_Shdr* symtab_sec = FindSectionByName(".symtab"); +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FixupDebugSections(off_t base_address_delta) { + const Elf_Shdr* debug_info = FindSectionByName(".debug_info"); + const Elf_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev"); + const Elf_Shdr* eh_frame = FindSectionByName(".eh_frame"); + const Elf_Shdr* debug_str = FindSectionByName(".debug_str"); + const Elf_Shdr* debug_line = FindSectionByName(".debug_line"); + const Elf_Shdr* strtab_sec = FindSectionByName(".strtab"); + const Elf_Shdr* symtab_sec = FindSectionByName(".symtab"); if (debug_info == nullptr || debug_abbrev == nullptr || debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) { @@ -1781,7 +2063,12 @@ bool ElfFile::FixupDebugSections(off_t base_address_delta) { return FixupDebugInfo(base_address_delta, info_iter.get()); } -void ElfFile::GdbJITSupport() { +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +void ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::GdbJITSupport() { // We only get here if we only are mapping the program header. DCHECK(program_header_only_); @@ -1789,15 +2076,18 @@ void ElfFile::GdbJITSupport() { std::string error_msg; // Make it MAP_PRIVATE so we can just give it to gdb if all the necessary // sections are there. - std::unique_ptr<ElfFile> all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE, - MAP_PRIVATE, &error_msg)); + std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>> + all_ptr(Open(const_cast<File*>(file_), PROT_READ | PROT_WRITE, + MAP_PRIVATE, &error_msg)); if (all_ptr.get() == nullptr) { return; } - ElfFile& all = *all_ptr; + ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off>& all = *all_ptr; // We need the eh_frame for gdb but debug info might be present without it. - const Elf32_Shdr* eh_frame = all.FindSectionByName(".eh_frame"); + const Elf_Shdr* eh_frame = all.FindSectionByName(".eh_frame"); if (eh_frame == nullptr) { return; } @@ -1806,7 +2096,7 @@ void ElfFile::GdbJITSupport() { // We need to add in a strtab and symtab to the image. // all is MAP_PRIVATE so it can be written to freely. // We also already have strtab and symtab so we are fine there. - Elf32_Ehdr& elf_hdr = all.GetHeader(); + Elf_Ehdr& elf_hdr = all.GetHeader(); elf_hdr.e_entry = 0; elf_hdr.e_phoff = 0; elf_hdr.e_phnum = 0; @@ -1824,4 +2114,477 @@ void ElfFile::GdbJITSupport() { gdb_file_mapping_.reset(all_ptr.release()); } +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::Strip(std::string* error_msg) { + // ELF files produced by MCLinker look roughly like this + // + // +------------+ + // | Elf_Ehdr | contains number of Elf_Shdr and offset to first + // +------------+ + // | Elf_Phdr | program headers + // | Elf_Phdr | + // | ... | + // | Elf_Phdr | + // +------------+ + // | section | mixture of needed and unneeded sections + // +------------+ + // | section | + // +------------+ + // | ... | + // +------------+ + // | section | + // +------------+ + // | Elf_Shdr | section headers + // | Elf_Shdr | + // | ... | contains offset to section start + // | Elf_Shdr | + // +------------+ + // + // To strip: + // - leave the Elf_Ehdr and Elf_Phdr values in place. + // - walk the sections making a new set of Elf_Shdr section headers for what we want to keep + // - move the sections are keeping up to fill in gaps of sections we want to strip + // - write new Elf_Shdr section headers to end of file, updating Elf_Ehdr + // - truncate rest of file + // + + std::vector<Elf_Shdr> section_headers; + std::vector<Elf_Word> section_headers_original_indexes; + section_headers.reserve(GetSectionHeaderNum()); + + + Elf_Shdr* string_section = GetSectionNameStringSection(); + CHECK(string_section != nullptr); + for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) { + Elf_Shdr* sh = GetSectionHeader(i); + CHECK(sh != nullptr); + const char* name = GetString(*string_section, sh->sh_name); + if (name == nullptr) { + CHECK_EQ(0U, i); + section_headers.push_back(*sh); + section_headers_original_indexes.push_back(0); + continue; + } + if (StartsWith(name, ".debug") + || (strcmp(name, ".strtab") == 0) + || (strcmp(name, ".symtab") == 0)) { + continue; + } + section_headers.push_back(*sh); + section_headers_original_indexes.push_back(i); + } + CHECK_NE(0U, section_headers.size()); + CHECK_EQ(section_headers.size(), section_headers_original_indexes.size()); + + // section 0 is the NULL section, sections start at offset of first section + CHECK(GetSectionHeader(1) != nullptr); + Elf_Off offset = GetSectionHeader(1)->sh_offset; + for (size_t i = 1; i < section_headers.size(); i++) { + Elf_Shdr& new_sh = section_headers[i]; + Elf_Shdr* old_sh = GetSectionHeader(section_headers_original_indexes[i]); + CHECK(old_sh != nullptr); + CHECK_EQ(new_sh.sh_name, old_sh->sh_name); + if (old_sh->sh_addralign > 1) { + offset = RoundUp(offset, old_sh->sh_addralign); + } + if (old_sh->sh_offset == offset) { + // already in place + offset += old_sh->sh_size; + continue; + } + // shift section earlier + memmove(Begin() + offset, + Begin() + old_sh->sh_offset, + old_sh->sh_size); + new_sh.sh_offset = offset; + offset += old_sh->sh_size; + } + + Elf_Off shoff = offset; + size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf_Shdr); + memcpy(Begin() + offset, §ion_headers[0], section_headers_size_in_bytes); + offset += section_headers_size_in_bytes; + + GetHeader().e_shnum = section_headers.size(); + GetHeader().e_shoff = shoff; + int result = ftruncate(file_->Fd(), offset); + if (result != 0) { + *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s", + file_->GetPath().c_str(), strerror(errno)); + return false; + } + return true; +} + +static const bool DEBUG_FIXUP = false; + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::Fixup(uintptr_t base_address) { + if (!FixupDynamic(base_address)) { + LOG(WARNING) << "Failed to fixup .dynamic in " << file_->GetPath(); + return false; + } + if (!FixupSectionHeaders(base_address)) { + LOG(WARNING) << "Failed to fixup section headers in " << file_->GetPath(); + return false; + } + if (!FixupProgramHeaders(base_address)) { + LOG(WARNING) << "Failed to fixup program headers in " << file_->GetPath(); + return false; + } + if (!FixupSymbols(base_address, true)) { + LOG(WARNING) << "Failed to fixup .dynsym in " << file_->GetPath(); + return false; + } + if (!FixupSymbols(base_address, false)) { + LOG(WARNING) << "Failed to fixup .symtab in " << file_->GetPath(); + return false; + } + if (!FixupRelocations(base_address)) { + LOG(WARNING) << "Failed to fixup .rel.dyn in " << file_->GetPath(); + return false; + } + if (!FixupDebugSections(base_address)) { + LOG(WARNING) << "Failed to fixup debug sections in " << file_->GetPath(); + return false; + } + return true; +} + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FixupDynamic(uintptr_t base_address) { + for (Elf_Word i = 0; i < GetDynamicNum(); i++) { + Elf_Dyn& elf_dyn = GetDynamic(i); + Elf_Word d_tag = elf_dyn.d_tag; + if (IsDynamicSectionPointer(d_tag, GetHeader().e_machine)) { + Elf_Addr d_ptr = elf_dyn.d_un.d_ptr; + if (DEBUG_FIXUP) { + LOG(INFO) << StringPrintf("In %s moving Elf_Dyn[%d] from 0x%" PRIx64 " to 0x%" PRIx64, + GetFile().GetPath().c_str(), i, + static_cast<uint64_t>(d_ptr), + static_cast<uint64_t>(d_ptr + base_address)); + } + d_ptr += base_address; + elf_dyn.d_un.d_ptr = d_ptr; + } + } + return true; +} + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FixupSectionHeaders(uintptr_t base_address) { + for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) { + Elf_Shdr* sh = GetSectionHeader(i); + CHECK(sh != nullptr); + // 0 implies that the section will not exist in the memory of the process + if (sh->sh_addr == 0) { + continue; + } + if (DEBUG_FIXUP) { + LOG(INFO) << StringPrintf("In %s moving Elf_Shdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64, + GetFile().GetPath().c_str(), i, + static_cast<uint64_t>(sh->sh_addr), + static_cast<uint64_t>(sh->sh_addr + base_address)); + } + sh->sh_addr += base_address; + } + return true; +} + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FixupProgramHeaders(uintptr_t base_address) { + // TODO: ELFObjectFile doesn't have give to Elf_Phdr, so we do that ourselves for now. + for (Elf_Word i = 0; i < GetProgramHeaderNum(); i++) { + Elf_Phdr* ph = GetProgramHeader(i); + CHECK(ph != nullptr); + CHECK_EQ(ph->p_vaddr, ph->p_paddr) << GetFile().GetPath() << " i=" << i; + CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)))) + << GetFile().GetPath() << " i=" << i; + if (DEBUG_FIXUP) { + LOG(INFO) << StringPrintf("In %s moving Elf_Phdr[%d] from 0x%" PRIx64 " to 0x%" PRIx64, + GetFile().GetPath().c_str(), i, + static_cast<uint64_t>(ph->p_vaddr), + static_cast<uint64_t>(ph->p_vaddr + base_address)); + } + ph->p_vaddr += base_address; + ph->p_paddr += base_address; + CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)))) + << GetFile().GetPath() << " i=" << i; + } + return true; +} + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FixupSymbols(uintptr_t base_address, bool dynamic) { + Elf_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB; + // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile + Elf_Shdr* symbol_section = FindSectionByType(section_type); + if (symbol_section == nullptr) { + // file is missing optional .symtab + CHECK(!dynamic) << GetFile().GetPath(); + return true; + } + for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) { + Elf_Sym* symbol = GetSymbol(section_type, i); + CHECK(symbol != nullptr); + if (symbol->st_value != 0) { + if (DEBUG_FIXUP) { + LOG(INFO) << StringPrintf("In %s moving Elf_Sym[%d] from 0x%" PRIx64 " to 0x%" PRIx64, + GetFile().GetPath().c_str(), i, + static_cast<uint64_t>(symbol->st_value), + static_cast<uint64_t>(symbol->st_value + base_address)); + } + symbol->st_value += base_address; + } + } + return true; +} + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, Elf_Rela, Elf_Dyn, Elf_Off> + ::FixupRelocations(uintptr_t base_address) { + for (Elf_Word i = 0; i < GetSectionHeaderNum(); i++) { + Elf_Shdr* sh = GetSectionHeader(i); + CHECK(sh != nullptr); + if (sh->sh_type == SHT_REL) { + for (uint32_t i = 0; i < GetRelNum(*sh); i++) { + Elf_Rel& rel = GetRel(*sh, i); + if (DEBUG_FIXUP) { + LOG(INFO) << StringPrintf("In %s moving Elf_Rel[%d] from 0x%" PRIx64 " to 0x%" PRIx64, + GetFile().GetPath().c_str(), i, + static_cast<uint64_t>(rel.r_offset), + static_cast<uint64_t>(rel.r_offset + base_address)); + } + rel.r_offset += base_address; + } + } else if (sh->sh_type == SHT_RELA) { + for (uint32_t i = 0; i < GetRelaNum(*sh); i++) { + Elf_Rela& rela = GetRela(*sh, i); + if (DEBUG_FIXUP) { + LOG(INFO) << StringPrintf("In %s moving Elf_Rela[%d] from 0x%" PRIx64 " to 0x%" PRIx64, + GetFile().GetPath().c_str(), i, + static_cast<uint64_t>(rela.r_offset), + static_cast<uint64_t>(rela.r_offset + base_address)); + } + rela.r_offset += base_address; + } + } + } + return true; +} + +// Explicit instantiations +template class ElfFileImpl<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Word, + Elf32_Sword, Elf32_Addr, Elf32_Sym, Elf32_Rel, Elf32_Rela, Elf32_Dyn, Elf32_Off>; +template class ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word, + Elf64_Sword, Elf64_Addr, Elf64_Sym, Elf64_Rel, Elf64_Rela, Elf64_Dyn, Elf64_Off>; + +ElfFile::ElfFile(ElfFileImpl32* elf32) : is_elf64_(false) { + CHECK_NE(elf32, static_cast<ElfFileImpl32*>(nullptr)); + elf_.elf32_ = elf32; +} + +ElfFile::ElfFile(ElfFileImpl64* elf64) : is_elf64_(true) { + CHECK_NE(elf64, static_cast<ElfFileImpl64*>(nullptr)); + elf_.elf64_ = elf64; +} + +ElfFile::~ElfFile() { + if (is_elf64_) { + CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr)); + delete elf_.elf64_; + } else { + CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr)); + delete elf_.elf32_; + } +} + +ElfFile* ElfFile::Open(File* file, bool writable, bool program_header_only, std::string* error_msg) { + if (file->GetLength() < EI_NIDENT) { + *error_msg = StringPrintf("File %s is too short to be a valid ELF file", + file->GetPath().c_str()); + return nullptr; + } + std::unique_ptr<MemMap> map(MemMap::MapFile(EI_NIDENT, PROT_READ, MAP_PRIVATE, file->Fd(), 0, + file->GetPath().c_str(), error_msg)); + if (map == nullptr && map->Size() != EI_NIDENT) { + return nullptr; + } + byte *header = map->Begin(); + if (header[EI_CLASS] == ELFCLASS64) { + ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, writable, program_header_only, error_msg); + if (elf_file_impl == nullptr) + return nullptr; + return new ElfFile(elf_file_impl); + } else if (header[EI_CLASS] == ELFCLASS32) { + ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, writable, program_header_only, error_msg); + if (elf_file_impl == nullptr) + return nullptr; + return new ElfFile(elf_file_impl); + } else { + *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d", + ELFCLASS32, ELFCLASS64, + file->GetPath().c_str(), + header[EI_CLASS]); + return nullptr; + } +} + +ElfFile* ElfFile::Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg) { + if (file->GetLength() < EI_NIDENT) { + *error_msg = StringPrintf("File %s is too short to be a valid ELF file", + file->GetPath().c_str()); + return nullptr; + } + std::unique_ptr<MemMap> map(MemMap::MapFile(EI_NIDENT, PROT_READ, MAP_PRIVATE, file->Fd(), 0, + file->GetPath().c_str(), error_msg)); + if (map == nullptr && map->Size() != EI_NIDENT) { + return nullptr; + } + byte *header = map->Begin(); + if (header[EI_CLASS] == ELFCLASS64) { + ElfFileImpl64* elf_file_impl = ElfFileImpl64::Open(file, mmap_prot, mmap_flags, error_msg); + if (elf_file_impl == nullptr) + return nullptr; + return new ElfFile(elf_file_impl); + } else if (header[EI_CLASS] == ELFCLASS32) { + ElfFileImpl32* elf_file_impl = ElfFileImpl32::Open(file, mmap_prot, mmap_flags, error_msg); + if (elf_file_impl == nullptr) + return nullptr; + return new ElfFile(elf_file_impl); + } else { + *error_msg = StringPrintf("Failed to find expected EI_CLASS value %d or %d in %s, found %d", + ELFCLASS32, ELFCLASS64, + file->GetPath().c_str(), + header[EI_CLASS]); + return nullptr; + } +} + +#define DELEGATE_TO_IMPL(func, ...) \ + if (is_elf64_) { \ + CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr)); \ + return elf_.elf64_->func(__VA_ARGS__); \ + } else { \ + CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr)); \ + return elf_.elf32_->func(__VA_ARGS__); \ + } + +bool ElfFile::Load(bool executable, std::string* error_msg) { + DELEGATE_TO_IMPL(Load, executable, error_msg); +} + +const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const { + DELEGATE_TO_IMPL(FindDynamicSymbolAddress, symbol_name); +} + +size_t ElfFile::Size() const { + DELEGATE_TO_IMPL(Size); +} + +byte* ElfFile::Begin() const { + DELEGATE_TO_IMPL(Begin); +} + +byte* ElfFile::End() const { + DELEGATE_TO_IMPL(End); +} + +const File& ElfFile::GetFile() const { + DELEGATE_TO_IMPL(GetFile); +} + +bool ElfFile::GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size) { + if (is_elf64_) { + CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr)); + + Elf64_Shdr *shdr = elf_.elf64_->FindSectionByName(section_name); + if (shdr == nullptr) + return false; + + if (offset != nullptr) + *offset = shdr->sh_offset; + if (size != nullptr) + *size = shdr->sh_size; + return true; + } else { + CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr)); + + Elf32_Shdr *shdr = elf_.elf32_->FindSectionByName(section_name); + if (shdr == nullptr) + return false; + + if (offset != nullptr) + *offset = shdr->sh_offset; + if (size != nullptr) + *size = shdr->sh_size; + return true; + } +} + +uint64_t ElfFile::FindSymbolAddress(unsigned section_type, + const std::string& symbol_name, + bool build_map) { + DELEGATE_TO_IMPL(FindSymbolAddress, section_type, symbol_name, build_map); +} + +size_t ElfFile::GetLoadedSize() const { + DELEGATE_TO_IMPL(GetLoadedSize); +} + +bool ElfFile::Strip(File* file, std::string* error_msg) { + std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg)); + if (elf_file.get() == nullptr) { + return false; + } + + if (elf_file->is_elf64_) + return elf_file->elf_.elf64_->Strip(error_msg); + else + return elf_file->elf_.elf32_->Strip(error_msg); +} + +bool ElfFile::Fixup(uintptr_t base_address) { + DELEGATE_TO_IMPL(Fixup, base_address); +} + +ElfFileImpl32* ElfFile::GetImpl32() const { + CHECK(!is_elf64_); + CHECK_NE(elf_.elf32_, static_cast<ElfFileImpl32*>(nullptr)); + return elf_.elf32_; +} + +ElfFileImpl64* ElfFile::GetImpl64() const { + CHECK(is_elf64_); + CHECK_NE(elf_.elf64_, static_cast<ElfFileImpl64*>(nullptr)); + return elf_.elf64_; +} + } // namespace art diff --git a/runtime/elf_file.h b/runtime/elf_file.h index 916d693..ea6538b 100644 --- a/runtime/elf_file.h +++ b/runtime/elf_file.h @@ -17,24 +17,13 @@ #ifndef ART_RUNTIME_ELF_FILE_H_ #define ART_RUNTIME_ELF_FILE_H_ -#include <map> -#include <memory> -#include <vector> +#include <string> #include "base/unix_file/fd_file.h" -#include "globals.h" -#include "elf_utils.h" -#include "mem_map.h" -#include "os.h" +#include "elf_file_impl.h" namespace art { -// Interface to GDB JIT for backtrace information. -extern "C" { - struct JITCodeEntry; -} - - // Used for compile time and runtime for ElfFile access. Because of // the need for use at runtime, cannot directly use LLVM classes such as // ELFObjectFile. @@ -46,162 +35,50 @@ class ElfFile { static ElfFile* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg); ~ElfFile(); - // Load segments into memory based on PT_LOAD program headers - - const File& GetFile() const { - return *file_; - } - - byte* Begin() const { - return map_->Begin(); - } - - byte* End() const { - return map_->End(); - } - - size_t Size() const { - return map_->Size(); - } - - Elf32_Ehdr& GetHeader() const; + const bool is_elf64_; - Elf32_Word GetProgramHeaderNum() const; - Elf32_Phdr* GetProgramHeader(Elf32_Word) const; - - Elf32_Word GetSectionHeaderNum() const; - Elf32_Shdr* GetSectionHeader(Elf32_Word) const; - Elf32_Shdr* FindSectionByType(Elf32_Word type) const; - Elf32_Shdr* FindSectionByName(const std::string& name) const; - - Elf32_Shdr* GetSectionNameStringSection() const; + // Load segments into memory based on PT_LOAD program headers + bool Load(bool executable, std::string* error_msg); - // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress. const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const; - Elf32_Word GetSymbolNum(Elf32_Shdr&) const; - Elf32_Sym* GetSymbol(Elf32_Word section_type, Elf32_Word i) const; + size_t Size() const; - // Find address of symbol in specified table, returning 0 if it is - // not found. See FindSymbolByName for an explanation of build_map. - Elf32_Addr FindSymbolAddress(Elf32_Word section_type, - const std::string& symbol_name, - bool build_map); + byte* Begin() const; - // Lookup a string given string section and offset. Returns nullptr for - // special 0 offset. - const char* GetString(Elf32_Shdr&, Elf32_Word) const; + byte* End() const; - Elf32_Word GetDynamicNum() const; - Elf32_Dyn& GetDynamic(Elf32_Word) const; + const File& GetFile() const; - Elf32_Word GetRelNum(Elf32_Shdr&) const; - Elf32_Rel& GetRel(Elf32_Shdr&, Elf32_Word) const; + bool GetSectionOffsetAndSize(const char* section_name, uint64_t* offset, uint64_t* size); - Elf32_Word GetRelaNum(Elf32_Shdr&) const; - Elf32_Rela& GetRela(Elf32_Shdr&, Elf32_Word) const; + uint64_t FindSymbolAddress(unsigned section_type, + const std::string& symbol_name, + bool build_map); - // Returns the expected size when the file is loaded at runtime size_t GetLoadedSize() const; - // Load segments into memory based on PT_LOAD program headers. - // executable is true at run time, false at compile time. - bool Load(bool executable, std::string* error_msg); + // Strip an ELF file of unneeded debugging information. + // Returns true on success, false on failure. + static bool Strip(File* file, std::string* error_msg); + + // Fixup an ELF file so that that oat header will be loaded at oat_begin. + // Returns true on success, false on failure. + static bool Fixup(File* file, uintptr_t oat_data_begin); - bool FixupDebugSections(off_t base_address_delta); + bool Fixup(uintptr_t base_address); + + ElfFileImpl32* GetImpl32() const; + ElfFileImpl64* GetImpl64() const; private: - ElfFile(File* file, bool writable, bool program_header_only); - - bool Setup(int prot, int flags, std::string* error_msg); - - bool SetMap(MemMap* map, std::string* error_msg); - - byte* GetProgramHeadersStart() const; - byte* GetSectionHeadersStart() const; - Elf32_Phdr& GetDynamicProgramHeader() const; - Elf32_Dyn* GetDynamicSectionStart() const; - Elf32_Sym* GetSymbolSectionStart(Elf32_Word section_type) const; - const char* GetStringSectionStart(Elf32_Word section_type) const; - Elf32_Rel* GetRelSectionStart(Elf32_Shdr&) const; - Elf32_Rela* GetRelaSectionStart(Elf32_Shdr&) const; - Elf32_Word* GetHashSectionStart() const; - Elf32_Word GetHashBucketNum() const; - Elf32_Word GetHashChainNum() const; - Elf32_Word GetHashBucket(size_t i, bool* ok) const; - Elf32_Word GetHashChain(size_t i, bool* ok) const; - - typedef std::map<std::string, Elf32_Sym*> SymbolTable; - SymbolTable** GetSymbolTable(Elf32_Word section_type); - - bool ValidPointer(const byte* start) const; - - const Elf32_Sym* FindDynamicSymbol(const std::string& symbol_name) const; - - // Check that certain sections and their dependencies exist. - bool CheckSectionsExist(std::string* error_msg) const; - - // Check that the link of the first section links to the second section. - bool CheckSectionsLinked(const byte* source, const byte* target) const; - - // Check whether the offset is in range, and set to target to Begin() + offset if OK. - bool CheckAndSet(Elf32_Off offset, const char* label, byte** target, std::string* error_msg); - - // Find symbol in specified table, returning nullptr if it is not found. - // - // If build_map is true, builds a map to speed repeated access. The - // map does not included untyped symbol values (aka STT_NOTYPE) - // since they can contain duplicates. If build_map is false, the map - // will be used if it was already created. Typically build_map - // should be set unless only a small number of symbols will be - // looked up. - Elf32_Sym* FindSymbolByName(Elf32_Word section_type, - const std::string& symbol_name, - bool build_map); - - Elf32_Phdr* FindProgamHeaderByType(Elf32_Word type) const; - - Elf32_Dyn* FindDynamicByType(Elf32_Sword type) const; - Elf32_Word FindDynamicValueByType(Elf32_Sword type) const; - - // Lookup a string by section type. Returns nullptr for special 0 offset. - const char* GetString(Elf32_Word section_type, Elf32_Word) const; - - const File* const file_; - const bool writable_; - const bool program_header_only_; - - // ELF header mapping. If program_header_only_ is false, will - // actually point to the entire elf file. - std::unique_ptr<MemMap> map_; - Elf32_Ehdr* header_; - std::vector<MemMap*> segments_; - - // Pointer to start of first PT_LOAD program segment after Load() - // when program_header_only_ is true. - byte* base_address_; - - // The program header should always available but use GetProgramHeadersStart() to be sure. - byte* program_headers_start_; - - // Conditionally available values. Use accessors to ensure they exist if they are required. - byte* section_headers_start_; - Elf32_Phdr* dynamic_program_header_; - Elf32_Dyn* dynamic_section_start_; - Elf32_Sym* symtab_section_start_; - Elf32_Sym* dynsym_section_start_; - char* strtab_section_start_; - char* dynstr_section_start_; - Elf32_Word* hash_section_start_; - - SymbolTable* symtab_symbol_table_; - SymbolTable* dynsym_symbol_table_; - - // Support for GDB JIT - byte* jit_elf_image_; - JITCodeEntry* jit_gdb_entry_; - std::unique_ptr<ElfFile> gdb_file_mapping_; - void GdbJITSupport(); + explicit ElfFile(ElfFileImpl32* elf32); + explicit ElfFile(ElfFileImpl64* elf64); + + union ElfFileContainer { + ElfFileImpl32* elf32_; + ElfFileImpl64* elf64_; + } elf_; }; } // namespace art diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h new file mode 100644 index 0000000..942dc29 --- /dev/null +++ b/runtime/elf_file_impl.h @@ -0,0 +1,220 @@ +/* + * 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_RUNTIME_ELF_FILE_IMPL_H_ +#define ART_RUNTIME_ELF_FILE_IMPL_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "base/unix_file/fd_file.h" +#include "globals.h" +#include "elf_utils.h" +#include "mem_map.h" +#include "os.h" + +namespace art { + +extern "C" { + struct JITCodeEntry; +} + +template <typename Elf_Ehdr, typename Elf_Phdr, typename Elf_Shdr, typename Elf_Word, + typename Elf_Sword, typename Elf_Addr, typename Elf_Sym, typename Elf_Rel, + typename Elf_Rela, typename Elf_Dyn, typename Elf_Off> +class ElfFileImpl { + public: + static ElfFileImpl* Open(File* file, bool writable, bool program_header_only, std::string* error_msg); + static ElfFileImpl* Open(File* file, int mmap_prot, int mmap_flags, std::string* error_msg); + ~ElfFileImpl(); + + const File& GetFile() const { + return *file_; + } + + byte* Begin() const { + return map_->Begin(); + } + + byte* End() const { + return map_->End(); + } + + size_t Size() const { + return map_->Size(); + } + + Elf_Ehdr& GetHeader() const; + + Elf_Word GetProgramHeaderNum() const; + Elf_Phdr* GetProgramHeader(Elf_Word) const; + + Elf_Word GetSectionHeaderNum() const; + Elf_Shdr* GetSectionHeader(Elf_Word) const; + Elf_Shdr* FindSectionByType(Elf_Word type) const; + Elf_Shdr* FindSectionByName(const std::string& name) const; + + Elf_Shdr* GetSectionNameStringSection() const; + + // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress. + const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const; + + static bool IsSymbolSectionType(Elf_Word section_type); + Elf_Word GetSymbolNum(Elf_Shdr&) const; + Elf_Sym* GetSymbol(Elf_Word section_type, Elf_Word i) const; + + // Find address of symbol in specified table, returning 0 if it is + // not found. See FindSymbolByName for an explanation of build_map. + Elf_Addr FindSymbolAddress(Elf_Word section_type, + const std::string& symbol_name, + bool build_map); + + // Lookup a string given string section and offset. Returns nullptr for + // special 0 offset. + const char* GetString(Elf_Shdr&, Elf_Word) const; + + Elf_Word GetDynamicNum() const; + Elf_Dyn& GetDynamic(Elf_Word) const; + + Elf_Word GetRelNum(Elf_Shdr&) const; + Elf_Rel& GetRel(Elf_Shdr&, Elf_Word) const; + + Elf_Word GetRelaNum(Elf_Shdr&) const; + Elf_Rela& GetRela(Elf_Shdr&, Elf_Word) const; + + // Returns the expected size when the file is loaded at runtime + size_t GetLoadedSize() const; + + // Load segments into memory based on PT_LOAD program headers. + // executable is true at run time, false at compile time. + bool Load(bool executable, std::string* error_msg); + + bool Fixup(uintptr_t base_address); + bool FixupDynamic(uintptr_t base_address); + bool FixupSectionHeaders(uintptr_t base_address); + bool FixupProgramHeaders(uintptr_t base_address); + bool FixupSymbols(uintptr_t base_address, bool dynamic); + bool FixupRelocations(uintptr_t base_address); + bool FixupDebugSections(off_t base_address_delta); + + bool Strip(std::string* error_msg); + + private: + ElfFileImpl(File* file, bool writable, bool program_header_only); + + bool Setup(int prot, int flags, std::string* error_msg); + + bool SetMap(MemMap* map, std::string* error_msg); + + byte* GetProgramHeadersStart() const; + byte* GetSectionHeadersStart() const; + Elf_Phdr& GetDynamicProgramHeader() const; + Elf_Dyn* GetDynamicSectionStart() const; + Elf_Sym* GetSymbolSectionStart(Elf_Word section_type) const; + const char* GetStringSectionStart(Elf_Word section_type) const; + Elf_Rel* GetRelSectionStart(Elf_Shdr&) const; + Elf_Rela* GetRelaSectionStart(Elf_Shdr&) const; + Elf_Word* GetHashSectionStart() const; + Elf_Word GetHashBucketNum() const; + Elf_Word GetHashChainNum() const; + Elf_Word GetHashBucket(size_t i, bool* ok) const; + Elf_Word GetHashChain(size_t i, bool* ok) const; + + typedef std::map<std::string, Elf_Sym*> SymbolTable; + SymbolTable** GetSymbolTable(Elf_Word section_type); + + bool ValidPointer(const byte* start) const; + + const Elf_Sym* FindDynamicSymbol(const std::string& symbol_name) const; + + // Check that certain sections and their dependencies exist. + bool CheckSectionsExist(std::string* error_msg) const; + + // Check that the link of the first section links to the second section. + bool CheckSectionsLinked(const byte* source, const byte* target) const; + + // Check whether the offset is in range, and set to target to Begin() + offset if OK. + bool CheckAndSet(Elf32_Off offset, const char* label, byte** target, std::string* error_msg); + + // Find symbol in specified table, returning nullptr if it is not found. + // + // If build_map is true, builds a map to speed repeated access. The + // map does not included untyped symbol values (aka STT_NOTYPE) + // since they can contain duplicates. If build_map is false, the map + // will be used if it was already created. Typically build_map + // should be set unless only a small number of symbols will be + // looked up. + Elf_Sym* FindSymbolByName(Elf_Word section_type, + const std::string& symbol_name, + bool build_map); + + Elf_Phdr* FindProgamHeaderByType(Elf_Word type) const; + + Elf_Dyn* FindDynamicByType(Elf_Sword type) const; + Elf_Word FindDynamicValueByType(Elf_Sword type) const; + + // Lookup a string by section type. Returns nullptr for special 0 offset. + const char* GetString(Elf_Word section_type, Elf_Word) const; + + const File* const file_; + const bool writable_; + const bool program_header_only_; + + // ELF header mapping. If program_header_only_ is false, will + // actually point to the entire elf file. + std::unique_ptr<MemMap> map_; + Elf_Ehdr* header_; + std::vector<MemMap*> segments_; + + // Pointer to start of first PT_LOAD program segment after Load() + // when program_header_only_ is true. + byte* base_address_; + + // The program header should always available but use GetProgramHeadersStart() to be sure. + byte* program_headers_start_; + + // Conditionally available values. Use accessors to ensure they exist if they are required. + byte* section_headers_start_; + Elf_Phdr* dynamic_program_header_; + Elf_Dyn* dynamic_section_start_; + Elf_Sym* symtab_section_start_; + Elf_Sym* dynsym_section_start_; + char* strtab_section_start_; + char* dynstr_section_start_; + Elf_Word* hash_section_start_; + + SymbolTable* symtab_symbol_table_; + SymbolTable* dynsym_symbol_table_; + + // Support for GDB JIT + byte* jit_elf_image_; + JITCodeEntry* jit_gdb_entry_; + std::unique_ptr<ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, + Elf_Sword, Elf_Addr, Elf_Sym, Elf_Rel, + Elf_Rela, Elf_Dyn, Elf_Off>> gdb_file_mapping_; + void GdbJITSupport(); +}; + +// Explicitly instantiated in elf_file.cc +typedef ElfFileImpl<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Word, Elf32_Sword, + Elf32_Addr, Elf32_Sym, Elf32_Rel, Elf32_Rela, Elf32_Dyn, Elf32_Off> ElfFileImpl32; +typedef ElfFileImpl<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Word, Elf64_Sword, + Elf64_Addr, Elf64_Sym, Elf64_Rel, Elf64_Rela, Elf64_Dyn, Elf64_Off> ElfFileImpl64; + +} // namespace art + +#endif // ART_RUNTIME_ELF_FILE_IMPL_H_ diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index a896f3e..a8a8307 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -47,9 +47,11 @@ OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file, std::string* error_msg) { std::unique_ptr<OatFile> oat_file(new OatFile(location, false)); oat_file->elf_file_.reset(elf_file); - Elf32_Shdr* hdr = elf_file->FindSectionByName(".rodata"); - oat_file->begin_ = elf_file->Begin() + hdr->sh_offset; - oat_file->end_ = elf_file->Begin() + hdr->sh_size + hdr->sh_offset; + uint64_t offset, size; + bool has_section = elf_file->GetSectionOffsetAndSize(".rodata", &offset, &size); + CHECK(has_section); + oat_file->begin_ = elf_file->Begin() + offset; + oat_file->end_ = elf_file->Begin() + size + offset; return oat_file->Setup(error_msg) ? oat_file.release() : nullptr; } |