Home | History | Annotate | Download | only in compiler
      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_fixup.h"
     18 
     19 #include <inttypes.h>
     20 #include <memory>
     21 
     22 #include "base/logging.h"
     23 #include "base/stringprintf.h"
     24 #include "elf_file.h"
     25 #include "elf_writer.h"
     26 
     27 namespace art {
     28 
     29 static const bool DEBUG_FIXUP = false;
     30 
     31 bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) {
     32   std::string error_msg;
     33   std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
     34   CHECK(elf_file.get() != nullptr) << error_msg;
     35 
     36   // Lookup "oatdata" symbol address.
     37   Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
     38   Elf32_Off base_address = oat_data_begin - oatdata_address;
     39 
     40   if (!FixupDynamic(*elf_file.get(), base_address)) {
     41       LOG(WARNING) << "Failed fo fixup .dynamic in " << file->GetPath();
     42       return false;
     43   }
     44   if (!FixupSectionHeaders(*elf_file.get(), base_address)) {
     45       LOG(WARNING) << "Failed fo fixup section headers in " << file->GetPath();
     46       return false;
     47   }
     48   if (!FixupProgramHeaders(*elf_file.get(), base_address)) {
     49       LOG(WARNING) << "Failed fo fixup program headers in " << file->GetPath();
     50       return false;
     51   }
     52   if (!FixupSymbols(*elf_file.get(), base_address, true)) {
     53       LOG(WARNING) << "Failed fo fixup .dynsym in " << file->GetPath();
     54       return false;
     55   }
     56   if (!FixupSymbols(*elf_file.get(), base_address, false)) {
     57       LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath();
     58       return false;
     59   }
     60   if (!FixupRelocations(*elf_file.get(), base_address)) {
     61       LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath();
     62       return false;
     63   }
     64   return true;
     65 }
     66 
     67 
     68 bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) {
     69   for (Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) {
     70     Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i);
     71     Elf32_Word d_tag = elf_dyn.d_tag;
     72     if (IsDynamicSectionPointer(d_tag, elf_file.GetHeader().e_machine)) {
     73       uint32_t d_ptr = elf_dyn.d_un.d_ptr;
     74       if (DEBUG_FIXUP) {
     75         LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR,
     76                                   elf_file.GetFile().GetPath().c_str(), i,
     77                                   d_ptr, d_ptr + base_address);
     78       }
     79       d_ptr += base_address;
     80       elf_dyn.d_un.d_ptr = d_ptr;
     81     }
     82   }
     83   return true;
     84 }
     85 
     86 bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) {
     87   for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
     88     Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
     89     CHECK(sh != nullptr);
     90     // 0 implies that the section will not exist in the memory of the process
     91     if (sh->sh_addr == 0) {
     92       continue;
     93     }
     94     if (DEBUG_FIXUP) {
     95       LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR,
     96                                 elf_file.GetFile().GetPath().c_str(), i,
     97                                 sh->sh_addr, sh->sh_addr + base_address);
     98     }
     99     sh->sh_addr += base_address;
    100   }
    101   return true;
    102 }
    103 
    104 bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) {
    105   // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now.
    106   for (Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) {
    107     Elf32_Phdr* ph = elf_file.GetProgramHeader(i);
    108     CHECK(ph != nullptr);
    109     CHECK_EQ(ph->p_vaddr, ph->p_paddr) << elf_file.GetFile().GetPath() << " i=" << i;
    110     CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
    111             << elf_file.GetFile().GetPath() << " i=" << i;
    112     if (DEBUG_FIXUP) {
    113       LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR,
    114                                 elf_file.GetFile().GetPath().c_str(), i,
    115                                 ph->p_vaddr, ph->p_vaddr + base_address);
    116     }
    117     ph->p_vaddr += base_address;
    118     ph->p_paddr += base_address;
    119     CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
    120             << elf_file.GetFile().GetPath() << " i=" << i;
    121   }
    122   return true;
    123 }
    124 
    125 bool ElfFixup::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic) {
    126   Elf32_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
    127   // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
    128   Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type);
    129   if (symbol_section == nullptr) {
    130     // file is missing optional .symtab
    131     CHECK(!dynamic) << elf_file.GetFile().GetPath();
    132     return true;
    133   }
    134   for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) {
    135     Elf32_Sym* symbol = elf_file.GetSymbol(section_type, i);
    136     CHECK(symbol != nullptr);
    137     if (symbol->st_value != 0) {
    138       if (DEBUG_FIXUP) {
    139         LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR,
    140                                   elf_file.GetFile().GetPath().c_str(), i,
    141                                   symbol->st_value, symbol->st_value + base_address);
    142       }
    143       symbol->st_value += base_address;
    144     }
    145   }
    146   return true;
    147 }
    148 
    149 bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) {
    150   for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
    151     Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
    152     CHECK(sh != nullptr);
    153     if (sh->sh_type == SHT_REL) {
    154       for (uint32_t i = 0; i < elf_file.GetRelNum(*sh); i++) {
    155         Elf32_Rel& rel = elf_file.GetRel(*sh, i);
    156         if (DEBUG_FIXUP) {
    157           LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR,
    158                                     elf_file.GetFile().GetPath().c_str(), i,
    159                                     rel.r_offset, rel.r_offset + base_address);
    160         }
    161         rel.r_offset += base_address;
    162       }
    163     } else if (sh->sh_type == SHT_RELA) {
    164       for (uint32_t i = 0; i < elf_file.GetRelaNum(*sh); i++) {
    165         Elf32_Rela& rela = elf_file.GetRela(*sh, i);
    166         if (DEBUG_FIXUP) {
    167           LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR,
    168                                     elf_file.GetFile().GetPath().c_str(), i,
    169                                     rela.r_offset, rela.r_offset + base_address);
    170         }
    171         rela.r_offset += base_address;
    172       }
    173     }
    174   }
    175   return true;
    176 }
    177 
    178 }  // namespace art
    179