Home | History | Annotate | Download | only in linker
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #ifndef __LINKER_RELOC_ITERATORS_H
     30 #define __LINKER_RELOC_ITERATORS_H
     31 
     32 #include "linker.h"
     33 
     34 #include <string.h>
     35 
     36 const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1;
     37 const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
     38 const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
     39 const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
     40 
     41 class plain_reloc_iterator {
     42 #if defined(USE_RELA)
     43   typedef ElfW(Rela) rel_t;
     44 #else
     45   typedef ElfW(Rel) rel_t;
     46 #endif
     47  public:
     48   plain_reloc_iterator(rel_t* rel_array, size_t count)
     49       : begin_(rel_array), end_(begin_ + count), current_(begin_) {}
     50 
     51   bool has_next() {
     52     return current_ < end_;
     53   }
     54 
     55   rel_t* next() {
     56     return current_++;
     57   }
     58  private:
     59   rel_t* const begin_;
     60   rel_t* const end_;
     61   rel_t* current_;
     62 
     63   DISALLOW_COPY_AND_ASSIGN(plain_reloc_iterator);
     64 };
     65 
     66 template <typename decoder_t>
     67 class packed_reloc_iterator {
     68 #if defined(USE_RELA)
     69   typedef ElfW(Rela) rel_t;
     70 #else
     71   typedef ElfW(Rel) rel_t;
     72 #endif
     73  public:
     74   explicit packed_reloc_iterator(decoder_t&& decoder)
     75       : decoder_(decoder) {
     76     // initialize fields
     77     memset(&reloc_, 0, sizeof(reloc_));
     78     relocation_count_ = decoder_.pop_front();
     79     reloc_.r_offset = decoder_.pop_front();
     80     relocation_index_ = 0;
     81     relocation_group_index_ = 0;
     82     group_size_ = 0;
     83   }
     84 
     85   bool has_next() const {
     86     return relocation_index_ < relocation_count_;
     87   }
     88 
     89   rel_t* next() {
     90     if (relocation_group_index_ == group_size_) {
     91       if (!read_group_fields()) {
     92         // Iterator is inconsistent state; it should not be called again
     93         // but in case it is let's make sure has_next() returns false.
     94         relocation_index_ = relocation_count_ = 0;
     95         return nullptr;
     96       }
     97     }
     98 
     99     if (is_relocation_grouped_by_offset_delta()) {
    100       reloc_.r_offset += group_r_offset_delta_;
    101     } else {
    102       reloc_.r_offset += decoder_.pop_front();
    103     }
    104 
    105     if (!is_relocation_grouped_by_info()) {
    106       reloc_.r_info = decoder_.pop_front();
    107     }
    108 
    109 #if defined(USE_RELA)
    110     if (is_relocation_group_has_addend() &&
    111         !is_relocation_grouped_by_addend()) {
    112       reloc_.r_addend += decoder_.pop_front();
    113     }
    114 #endif
    115 
    116     relocation_index_++;
    117     relocation_group_index_++;
    118 
    119     return &reloc_;
    120   }
    121  private:
    122   bool read_group_fields() {
    123     group_size_ = decoder_.pop_front();
    124     group_flags_ = decoder_.pop_front();
    125 
    126     if (is_relocation_grouped_by_offset_delta()) {
    127       group_r_offset_delta_ = decoder_.pop_front();
    128     }
    129 
    130     if (is_relocation_grouped_by_info()) {
    131       reloc_.r_info = decoder_.pop_front();
    132     }
    133 
    134     if (is_relocation_group_has_addend() &&
    135         is_relocation_grouped_by_addend()) {
    136 #if !defined(USE_RELA)
    137       // This platform does not support rela, and yet we have it encoded in android_rel section.
    138       DL_ERR("unexpected r_addend in android.rel section");
    139       return false;
    140 #else
    141       reloc_.r_addend += decoder_.pop_front();
    142     } else if (!is_relocation_group_has_addend()) {
    143       reloc_.r_addend = 0;
    144 #endif
    145     }
    146 
    147     relocation_group_index_ = 0;
    148     return true;
    149   }
    150 
    151   bool is_relocation_grouped_by_info() {
    152     return (group_flags_ & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
    153   }
    154 
    155   bool is_relocation_grouped_by_offset_delta() {
    156     return (group_flags_ & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
    157   }
    158 
    159   bool is_relocation_grouped_by_addend() {
    160     return (group_flags_ & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
    161   }
    162 
    163   bool is_relocation_group_has_addend() {
    164     return (group_flags_ & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
    165   }
    166 
    167   decoder_t decoder_;
    168   size_t relocation_count_;
    169   size_t group_size_;
    170   size_t group_flags_;
    171   size_t group_r_offset_delta_;
    172   size_t relocation_index_;
    173   size_t relocation_group_index_;
    174   rel_t reloc_;
    175 };
    176 
    177 #endif  // __LINKER_RELOC_ITERATORS_H
    178