16a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom/* 26a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * Copyright (C) 2012 The Android Open Source Project 36a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * 46a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 56a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * you may not use this file except in compliance with the License. 66a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * You may obtain a copy of the License at 76a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * 86a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 96a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * 106a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * Unless required by applicable law or agreed to in writing, software 116a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 126a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * See the License for the specific language governing permissions and 146a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom * limitations under the License. 156a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom */ 166a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 176a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom#include "elf_stripper.h" 186a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 19e84bfb5a809310f29b97e18203e99a2126f2f084Nicolas Geoffray#include <unistd.h> 20e84bfb5a809310f29b97e18203e99a2126f2f084Nicolas Geoffray#include <sys/types.h> 21700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers#include <memory> 226a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom#include <vector> 236a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 246a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom#include "base/logging.h" 25576ca0cd692c0b6ae70e776de91015b8ff000a08Ian Rogers#include "base/stringprintf.h" 266a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom#include "elf_file.h" 2750cfe74daaece80853cb3b45d4338329b7d0345bNicolas Geoffray#include "elf_utils.h" 286a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom#include "utils.h" 296a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 306a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstromnamespace art { 316a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 328d31bbd3d6536de12bc20e3d29cfe03fe848f9daIan Rogersbool ElfStripper::Strip(File* file, std::string* error_msg) { 33700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, error_msg)); 348d31bbd3d6536de12bc20e3d29cfe03fe848f9daIan Rogers if (elf_file.get() == nullptr) { 358d31bbd3d6536de12bc20e3d29cfe03fe848f9daIan Rogers return false; 368d31bbd3d6536de12bc20e3d29cfe03fe848f9daIan Rogers } 376a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 386a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // ELF files produced by MCLinker look roughly like this 396a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // 406a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 416a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | Elf32_Ehdr | contains number of Elf32_Shdr and offset to first 426a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 436a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | Elf32_Phdr | program headers 446a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | Elf32_Phdr | 456a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | ... | 466a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | Elf32_Phdr | 476a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 486a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | section | mixture of needed and unneeded sections 496a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 506a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | section | 516a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 526a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | ... | 536a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 546a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | section | 556a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 566a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | Elf32_Shdr | section headers 576a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | Elf32_Shdr | 586a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | ... | contains offset to section start 596a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // | Elf32_Shdr | 606a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // +------------+ 616a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // 626a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // To strip: 636a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // - leave the Elf32_Ehdr and Elf32_Phdr values in place. 646a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // - walk the sections making a new set of Elf32_Shdr section headers for what we want to keep 656a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // - move the sections are keeping up to fill in gaps of sections we want to strip 666a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // - write new Elf32_Shdr section headers to end of file, updating Elf32_Ehdr 676a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // - truncate rest of file 686a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // 696a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 7050cfe74daaece80853cb3b45d4338329b7d0345bNicolas Geoffray std::vector<Elf32_Shdr> section_headers; 7150cfe74daaece80853cb3b45d4338329b7d0345bNicolas Geoffray std::vector<Elf32_Word> section_headers_original_indexes; 726a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom section_headers.reserve(elf_file->GetSectionHeaderNum()); 736a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 746a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 75afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe Elf32_Shdr* string_section = elf_file->GetSectionNameStringSection(); 76afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe CHECK(string_section != nullptr); 7750cfe74daaece80853cb3b45d4338329b7d0345bNicolas Geoffray for (Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) { 78afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe Elf32_Shdr* sh = elf_file->GetSectionHeader(i); 79afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe CHECK(sh != nullptr); 80afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe const char* name = elf_file->GetString(*string_section, sh->sh_name); 81afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe if (name == nullptr) { 826a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom CHECK_EQ(0U, i); 83afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe section_headers.push_back(*sh); 846a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom section_headers_original_indexes.push_back(0); 856a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom continue; 866a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom } 876a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom if (StartsWith(name, ".debug") 886a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom || (strcmp(name, ".strtab") == 0) 896a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom || (strcmp(name, ".symtab") == 0)) { 906a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom continue; 916a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom } 92afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe section_headers.push_back(*sh); 936a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom section_headers_original_indexes.push_back(i); 946a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom } 956a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom CHECK_NE(0U, section_headers.size()); 966a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom CHECK_EQ(section_headers.size(), section_headers_original_indexes.size()); 976a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 986a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // section 0 is the NULL section, sections start at offset of first section 99afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe CHECK(elf_file->GetSectionHeader(1) != nullptr); 100afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe Elf32_Off offset = elf_file->GetSectionHeader(1)->sh_offset; 1016a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom for (size_t i = 1; i < section_headers.size(); i++) { 10250cfe74daaece80853cb3b45d4338329b7d0345bNicolas Geoffray Elf32_Shdr& new_sh = section_headers[i]; 103afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe Elf32_Shdr* old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]); 104afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe CHECK(old_sh != nullptr); 105afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe CHECK_EQ(new_sh.sh_name, old_sh->sh_name); 106afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe if (old_sh->sh_addralign > 1) { 107afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe offset = RoundUp(offset, old_sh->sh_addralign); 1086a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom } 109afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe if (old_sh->sh_offset == offset) { 1106a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // already in place 111afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe offset += old_sh->sh_size; 1126a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom continue; 1136a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom } 1146a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom // shift section earlier 1156a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom memmove(elf_file->Begin() + offset, 116afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe elf_file->Begin() + old_sh->sh_offset, 117afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe old_sh->sh_size); 1186a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom new_sh.sh_offset = offset; 119afa6b8e93a0dc0de33c9d404945c7c5621e20b1aAndreas Gampe offset += old_sh->sh_size; 1206a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom } 1216a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 12250cfe74daaece80853cb3b45d4338329b7d0345bNicolas Geoffray Elf32_Off shoff = offset; 12350cfe74daaece80853cb3b45d4338329b7d0345bNicolas Geoffray size_t section_headers_size_in_bytes = section_headers.size() * sizeof(Elf32_Shdr); 1246a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom memcpy(elf_file->Begin() + offset, §ion_headers[0], section_headers_size_in_bytes); 1256a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom offset += section_headers_size_in_bytes; 1266a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 1276a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom elf_file->GetHeader().e_shnum = section_headers.size(); 1286a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom elf_file->GetHeader().e_shoff = shoff; 1296a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom int result = ftruncate(file->Fd(), offset); 1306a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom if (result != 0) { 1318d31bbd3d6536de12bc20e3d29cfe03fe848f9daIan Rogers *error_msg = StringPrintf("Failed to truncate while stripping ELF file: '%s': %s", 1328d31bbd3d6536de12bc20e3d29cfe03fe848f9daIan Rogers file->GetPath().c_str(), strerror(errno)); 1336a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom return false; 1346a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom } 1356a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom return true; 1366a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom} 1376a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom 1386a47b9dc850b903aabefcfab4adb132cb68bba2eBrian Carlstrom} // namespace art 139