Home | History | Annotate | Download | only in courgette
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "courgette/disassembler_elf_32_x86.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/logging.h"
     13 
     14 #include "courgette/assembly_program.h"
     15 #include "courgette/courgette.h"
     16 #include "courgette/encoded_program.h"
     17 
     18 namespace courgette {
     19 
     20 DisassemblerElf32X86::DisassemblerElf32X86(const void* start, size_t length)
     21   : DisassemblerElf32(start, length) {
     22 }
     23 
     24 // Convert an ELF relocation struction into an RVA
     25 CheckBool DisassemblerElf32X86::RelToRVA(Elf32_Rel rel, RVA* result) const {
     26 
     27   // The rightmost byte of r_info is the type...
     28   elf32_rel_386_type_values type =
     29       (elf32_rel_386_type_values)(unsigned char)rel.r_info;
     30 
     31   // The other 3 bytes of r_info are the symbol
     32   uint32 symbol =  rel.r_info >> 8;
     33 
     34   switch(type)
     35   {
     36     case R_386_NONE:
     37     case R_386_32:
     38     case R_386_PC32:
     39     case R_386_GOT32:
     40     case R_386_PLT32:
     41     case R_386_COPY:
     42     case R_386_GLOB_DAT:
     43     case R_386_JMP_SLOT:
     44       return false;
     45 
     46     case R_386_RELATIVE:
     47       if (symbol != 0)
     48         return false;
     49 
     50       // This is a basic ABS32 relocation address
     51       *result = rel.r_offset;
     52       return true;
     53 
     54     case R_386_GOTOFF:
     55     case R_386_GOTPC:
     56     case R_386_TLS_TPOFF:
     57       return false;
     58   }
     59 
     60   return false;
     61 }
     62 
     63 CheckBool DisassemblerElf32X86::ParseRelocationSection(
     64     const Elf32_Shdr *section_header,
     65       AssemblyProgram* program) {
     66   // We can reproduce the R_386_RELATIVE entries in one of the relocation
     67   // table based on other information in the patch, given these
     68   // conditions....
     69   //
     70   // All R_386_RELATIVE entries are:
     71   //   1) In the same relocation table
     72   //   2) Are consecutive
     73   //   3) Are sorted in memory address order
     74   //
     75   // Happily, this is normally the case, but it's not required by spec
     76   // so we check, and just don't do it if we don't match up.
     77 
     78   // The expectation is that one relocation section will contain
     79   // all of our R_386_RELATIVE entries in the expected order followed
     80   // by assorted other entries we can't use special handling for.
     81 
     82   bool match = true;
     83 
     84   // Walk all the bytes in the section, matching relocation table or not
     85   size_t file_offset = section_header->sh_offset;
     86   size_t section_end = section_header->sh_offset + section_header->sh_size;
     87 
     88   Elf32_Rel *section_relocs_iter =
     89       (Elf32_Rel *)OffsetToPointer(section_header->sh_offset);
     90 
     91   uint32 section_relocs_count = section_header->sh_size /
     92                                 section_header->sh_entsize;
     93 
     94   if (abs32_locations_.size() > section_relocs_count)
     95     match = false;
     96 
     97   std::vector<RVA>::iterator reloc_iter = abs32_locations_.begin();
     98 
     99   while (match && (reloc_iter !=  abs32_locations_.end())) {
    100     if (section_relocs_iter->r_info != R_386_RELATIVE ||
    101         section_relocs_iter->r_offset != *reloc_iter)
    102       match = false;
    103     section_relocs_iter++;
    104     reloc_iter++;
    105   }
    106 
    107   if (match) {
    108     // Skip over relocation tables
    109     if (!program->EmitElfRelocationInstruction())
    110       return false;
    111     file_offset += sizeof(Elf32_Rel) * abs32_locations_.size();
    112   }
    113 
    114   return ParseSimpleRegion(file_offset, section_end, program);
    115 }
    116 
    117 CheckBool DisassemblerElf32X86::ParseRel32RelocsFromSection(
    118     const Elf32_Shdr* section_header) {
    119 
    120   uint32 start_file_offset = section_header->sh_offset;
    121   uint32 end_file_offset = start_file_offset + section_header->sh_size;
    122 
    123   const uint8* start_pointer = OffsetToPointer(start_file_offset);
    124   const uint8* end_pointer = OffsetToPointer(end_file_offset);
    125 
    126   // Quick way to convert from Pointer to RVA within a single Section is to
    127   // subtract 'pointer_to_rva'.
    128   const uint8* const adjust_pointer_to_rva = start_pointer -
    129                                              section_header->sh_addr;
    130 
    131   // Find the rel32 relocations.
    132   const uint8* p = start_pointer;
    133   while (p < end_pointer) {
    134     //RVA current_rva = static_cast<RVA>(p - adjust_pointer_to_rva);
    135 
    136     // Heuristic discovery of rel32 locations in instruction stream: are the
    137     // next few bytes the start of an instruction containing a rel32
    138     // addressing mode?
    139     const uint8* rel32 = NULL;
    140 
    141     if (p + 5 <= end_pointer) {
    142       if (*p == 0xE8 || *p == 0xE9) {  // jmp rel32 and call rel32
    143         rel32 = p + 1;
    144       }
    145     }
    146     if (p + 6 <= end_pointer) {
    147       if (*p == 0x0F  &&  (*(p+1) & 0xF0) == 0x80) {  // Jcc long form
    148         if (p[1] != 0x8A && p[1] != 0x8B)  // JPE/JPO unlikely
    149           rel32 = p + 2;
    150       }
    151     }
    152     if (rel32) {
    153       RVA rva = static_cast<RVA>(rel32 - adjust_pointer_to_rva);
    154       TypedRVAX86* rel32_rva = new TypedRVAX86(rva);
    155 
    156       if (!rel32_rva->ComputeRelativeTarget(rel32)) {
    157         return false;
    158       }
    159 
    160       RVA target_rva = rel32_rva->rva() + rel32_rva->relative_target();
    161       // To be valid, rel32 target must be within image, and within this
    162       // section.
    163       if (IsValidRVA(target_rva)) {
    164         rel32_locations_.push_back(rel32_rva);
    165 #if COURGETTE_HISTOGRAM_TARGETS
    166         ++rel32_target_rvas_[target_rva];
    167 #endif
    168         p = rel32 + 4;
    169         continue;
    170       } else {
    171         delete rel32_rva;
    172       }
    173     }
    174     p += 1;
    175   }
    176 
    177   return true;
    178 }
    179 
    180 }  // namespace courgette
    181