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: plain_reloc_iterator(rel_t * rel_array,size_t count)48 plain_reloc_iterator(rel_t* rel_array, size_t count) 49 : begin_(rel_array), end_(begin_ + count), current_(begin_) {} 50 has_next()51 bool has_next() { 52 return current_ < end_; 53 } 54 next()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: packed_reloc_iterator(decoder_t && decoder)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 has_next()85 bool has_next() const { 86 return relocation_index_ < relocation_count_; 87 } 88 next()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: read_group_fields()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 is_relocation_grouped_by_info()151 bool is_relocation_grouped_by_info() { 152 return (group_flags_ & RELOCATION_GROUPED_BY_INFO_FLAG) != 0; 153 } 154 is_relocation_grouped_by_offset_delta()155 bool is_relocation_grouped_by_offset_delta() { 156 return (group_flags_ & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0; 157 } 158 is_relocation_grouped_by_addend()159 bool is_relocation_grouped_by_addend() { 160 return (group_flags_ & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0; 161 } 162 is_relocation_group_has_addend()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