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 <unistd.h> 20 #include <sys/types.h> 21 #include <memory> 22 #include <vector> 23 24 #include "base/logging.h" 25 #include "base/stringprintf.h" 26 #include "elf_file.h" 27 #include "elf_utils.h" 28 #include "utils.h" 29 30 namespace art { 31 32 bool ElfStripper::Strip(File* file, std::string* error_msg) { 33 std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg)); 34 if (elf_file.get() == nullptr) { 35 return false; 36 } 37 38 // ELF files produced by MCLinker look roughly like this 39 // 40 // +------------+ 41 // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first 42 // +------------+ 43 // | Elf32_Phdr | program headers 44 // | Elf32_Phdr | 45 // | ... | 46 // | Elf32_Phdr | 47 // +------------+ 48 // | section | mixture of needed and unneeded sections 49 // +------------+ 50 // | section | 51 // +------------+ 52 // | ... | 53 // +------------+ 54 // | section | 55 // +------------+ 56 // | Elf32_Shdr | section headers 57 // | Elf32_Shdr | 58 // | ... | contains offset to section start 59 // | Elf32_Shdr | 60 // +------------+ 61 // 62 // To strip: 63 // - leave the Elf32_Ehdr and Elf32_Phdr values in place. 64 // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep 65 // - move the sections are keeping up to fill in gaps of sections we want to strip 66 // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr 67 // - truncate rest of file 68 // 69 70 std::vector<Elf32_Shdr> section_headers; 71 std::vector<Elf32_Word> section_headers_original_indexes; 72 section_headers.reserve(elf_file->GetSectionHeaderNum()); 73 74 75 Elf32_Shdr* string_section = elf_file->GetSectionNameStringSection(); 76 CHECK(string_section != nullptr); 77 for (Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) { 78 Elf32_Shdr* sh = elf_file->GetSectionHeader(i); 79 CHECK(sh != nullptr); 80 const char* name = elf_file->GetString(*string_section, sh->sh_name); 81 if (name == nullptr) { 82 CHECK_EQ(0U, i); 83 section_headers.push_back(*sh); 84 section_headers_original_indexes.push_back(0); 85 continue; 86 } 87 if (StartsWith(name, ".debug") 88 || (strcmp(name, ".strtab") == 0) 89 || (strcmp(name, ".symtab") == 0)) { 90 continue; 91 } 92 section_headers.push_back(*sh); 93 section_headers_original_indexes.push_back(i); 94 } 95 CHECK_NE(0U, section_headers.size()); 96 CHECK_EQ(section_headers.size(), section_headers_original_indexes.size()); 97 98 // section 0 is the NULL section, sections start at offset of first section 99 CHECK(elf_file->GetSectionHeader(1) != nullptr); 100 Elf32_Off offset = elf_file->GetSectionHeader(1)->sh_offset; 101 for (size_t i = 1; i < section_headers.size(); i++) { 102 Elf32_Shdr& new_sh = section_headers[i]; 103 Elf32_Shdr* old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]); 104 CHECK(old_sh != nullptr); 105 CHECK_EQ(new_sh.sh_name, old_sh->sh_name); 106 if (old_sh->sh_addralign > 1) { 107 offset = RoundUp(offset, old_sh->sh_addralign); 108 } 109 if (old_sh->sh_offset == offset) { 110 // already in place 111 offset += old_sh->sh_size; 112 continue; 113 } 114 // shift section earlier 115 memmove(elf_file->Begin() + offset, 116 elf_file->Begin() + old_sh->sh_offset, 117 old_sh->sh_size); 118 new_sh.sh_offset = offset; 119 offset += old_sh->sh_size; 120 } 121 122 Elf32_Off shoff = offset; 123 size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf32_Shdr); 124 memcpy(elf_file->Begin() + offset, §ion_headers[0], section_headers_size_in_bytes); 125 offset += section_headers_size_in_bytes; 126 127 elf_file->GetHeader().e_shnum = section_headers.size(); 128 elf_file->GetHeader().e_shoff = shoff; 129 int result = ftruncate(file->Fd(), offset); 130 if (result != 0) { 131 *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s", 132 file->GetPath().c_str(), strerror(errno)); 133 return false; 134 } 135 return true; 136 } 137 138 } // namespace art 139