1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "elf_stripper.h" 18 19 #include <vector> 20 21 #include <llvm/Support/ELF.h> 22 23 #include "UniquePtr.h" 24 #include "base/logging.h" 25 #include "elf_file.h" 26 #include "utils.h" 27 28 namespace art { 29 30 bool ElfStripper::Strip(File* file) { 31 UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false)); 32 CHECK(elf_file.get() != NULL); 33 34 // ELF files produced by MCLinker look roughly like this 35 // 36 // +------------+ 37 // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first 38 // +------------+ 39 // | Elf32_Phdr | program headers 40 // | Elf32_Phdr | 41 // | ... | 42 // | Elf32_Phdr | 43 // +------------+ 44 // | section | mixture of needed and unneeded sections 45 // +------------+ 46 // | section | 47 // +------------+ 48 // | ... | 49 // +------------+ 50 // | section | 51 // +------------+ 52 // | Elf32_Shdr | section headers 53 // | Elf32_Shdr | 54 // | ... | contains offset to section start 55 // | Elf32_Shdr | 56 // +------------+ 57 // 58 // To strip: 59 // - leave the Elf32_Ehdr and Elf32_Phdr values in place. 60 // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep 61 // - move the sections are keeping up to fill in gaps of sections we want to strip 62 // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr 63 // - truncate rest of file 64 // 65 66 std::vector<llvm::ELF::Elf32_Shdr> section_headers; 67 std::vector<llvm::ELF::Elf32_Word> section_headers_original_indexes; 68 section_headers.reserve(elf_file->GetSectionHeaderNum()); 69 70 71 llvm::ELF::Elf32_Shdr& string_section = elf_file->GetSectionNameStringSection(); 72 for (llvm::ELF::Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) { 73 llvm::ELF::Elf32_Shdr& sh = elf_file->GetSectionHeader(i); 74 const char* name = elf_file->GetString(string_section, sh.sh_name); 75 if (name == NULL) { 76 CHECK_EQ(0U, i); 77 section_headers.push_back(sh); 78 section_headers_original_indexes.push_back(0); 79 continue; 80 } 81 if (StartsWith(name, ".debug") 82 || (strcmp(name, ".strtab") == 0) 83 || (strcmp(name, ".symtab") == 0)) { 84 continue; 85 } 86 section_headers.push_back(sh); 87 section_headers_original_indexes.push_back(i); 88 } 89 CHECK_NE(0U, section_headers.size()); 90 CHECK_EQ(section_headers.size(), section_headers_original_indexes.size()); 91 92 // section 0 is the NULL section, sections start at offset of first section 93 llvm::ELF::Elf32_Off offset = elf_file->GetSectionHeader(1).sh_offset; 94 for (size_t i = 1; i < section_headers.size(); i++) { 95 llvm::ELF::Elf32_Shdr& new_sh = section_headers[i]; 96 llvm::ELF::Elf32_Shdr& old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]); 97 CHECK_EQ(new_sh.sh_name, old_sh.sh_name); 98 if (old_sh.sh_addralign > 1) { 99 offset = RoundUp(offset, old_sh.sh_addralign); 100 } 101 if (old_sh.sh_offset == offset) { 102 // already in place 103 offset += old_sh.sh_size; 104 continue; 105 } 106 // shift section earlier 107 memmove(elf_file->Begin() + offset, 108 elf_file->Begin() + old_sh.sh_offset, 109 old_sh.sh_size); 110 new_sh.sh_offset = offset; 111 offset += old_sh.sh_size; 112 } 113 114 llvm::ELF::Elf32_Off shoff = offset; 115 size_t section_headers_size_in_bytes = section_headers.size() * sizeof(llvm::ELF::Elf32_Shdr); 116 memcpy(elf_file->Begin() + offset, §ion_headers[0], section_headers_size_in_bytes); 117 offset += section_headers_size_in_bytes; 118 119 elf_file->GetHeader().e_shnum = section_headers.size(); 120 elf_file->GetHeader().e_shoff = shoff; 121 int result = ftruncate(file->Fd(), offset); 122 if (result != 0) { 123 PLOG(ERROR) << "Failed to truncate while stripping ELF file: " << file->GetPath(); 124 return false; 125 } 126 return true; 127 } 128 129 } // namespace art 130