1fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov/* 2fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov * Copyright (C) 2015 The Android Open Source Project 3bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * All rights reserved. 4fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov * 5bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * Redistribution and use in source and binary forms, with or without 6bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * modification, are permitted provided that the following conditions 7bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * are met: 8bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * * Redistributions of source code must retain the above copyright 9bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * notice, this list of conditions and the following disclaimer. 10bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * * Redistributions in binary form must reproduce the above copyright 11bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * notice, this list of conditions and the following disclaimer in 12bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * the documentation and/or other materials provided with the 13bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * distribution. 14fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov * 15bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26bcc4da9b752f0def46d63ed7b31f3f49cc2435adDimitry Ivanov * SUCH DAMAGE. 27fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov */ 28fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 29cbc80ba9d839675a0c4891e2ab33f39ba51b04b2Elliott Hughes#pragma once 30fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 31fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#include "linker.h" 32fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 3318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#include <string.h> 3418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 3520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovconst size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1; 3620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovconst size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2; 3720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovconst size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4; 3820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanovconst size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8; 3918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 40fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanovclass plain_reloc_iterator { 41fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#if defined(USE_RELA) 42fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov typedef ElfW(Rela) rel_t; 43fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#else 44fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov typedef ElfW(Rel) rel_t; 45fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov#endif 46fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov public: 47fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov plain_reloc_iterator(rel_t* rel_array, size_t count) 48fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov : begin_(rel_array), end_(begin_ + count), current_(begin_) {} 49fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 50fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov bool has_next() { 51fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov return current_ < end_; 52fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov } 53fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 54fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov rel_t* next() { 55fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov return current_++; 56fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov } 57fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov private: 58fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov rel_t* const begin_; 59fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov rel_t* const end_; 60fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov rel_t* current_; 61fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 62fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov DISALLOW_COPY_AND_ASSIGN(plain_reloc_iterator); 63fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov}; 64fa26eee77685e8dee7986e62a7d263003f5bd25aDmitriy Ivanov 6518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovtemplate <typename decoder_t> 6618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanovclass packed_reloc_iterator { 6718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#if defined(USE_RELA) 6818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov typedef ElfW(Rela) rel_t; 6918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#else 7018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov typedef ElfW(Rel) rel_t; 7118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#endif 7218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov public: 7318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov explicit packed_reloc_iterator(decoder_t&& decoder) 7418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov : decoder_(decoder) { 7518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov // initialize fields 7618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov memset(&reloc_, 0, sizeof(reloc_)); 7718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov relocation_count_ = decoder_.pop_front(); 7818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_offset = decoder_.pop_front(); 7918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov relocation_index_ = 0; 8018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov relocation_group_index_ = 0; 8118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov group_size_ = 0; 8218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 8318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 8418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov bool has_next() const { 8518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return relocation_index_ < relocation_count_; 8618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 8718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 8818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov rel_t* next() { 8918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (relocation_group_index_ == group_size_) { 9018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov if (!read_group_fields()) { 9118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov // Iterator is inconsistent state; it should not be called again 9218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov // but in case it is let's make sure has_next() returns false. 9318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov relocation_index_ = relocation_count_ = 0; 9418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return nullptr; 9518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 9618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 9718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 9820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (is_relocation_grouped_by_offset_delta()) { 9918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_offset += group_r_offset_delta_; 10018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } else { 10118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_offset += decoder_.pop_front(); 10218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 10318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 10420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (!is_relocation_grouped_by_info()) { 10518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_info = decoder_.pop_front(); 10618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 10718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 10818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#if defined(USE_RELA) 10920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (is_relocation_group_has_addend() && 11020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov !is_relocation_grouped_by_addend()) { 11118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_addend += decoder_.pop_front(); 11218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 11318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#endif 11418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 11518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov relocation_index_++; 11618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov relocation_group_index_++; 11718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 11818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return &reloc_; 11918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 12018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov private: 12118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov bool read_group_fields() { 12218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov group_size_ = decoder_.pop_front(); 12318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov group_flags_ = decoder_.pop_front(); 12418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 12520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (is_relocation_grouped_by_offset_delta()) { 12618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov group_r_offset_delta_ = decoder_.pop_front(); 12718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 12818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 12920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (is_relocation_grouped_by_info()) { 13018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_info = decoder_.pop_front(); 13118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 13218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 13320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov if (is_relocation_group_has_addend() && 13420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov is_relocation_grouped_by_addend()) { 13518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#if !defined(USE_RELA) 13618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov // This platform does not support rela, and yet we have it encoded in android_rel section. 13718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov DL_ERR("unexpected r_addend in android.rel section"); 13818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return false; 13918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#else 14018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_addend += decoder_.pop_front(); 14120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } else if (!is_relocation_group_has_addend()) { 14218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov reloc_.r_addend = 0; 14318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov#endif 14418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 14518a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 14618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov relocation_group_index_ = 0; 14718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov return true; 14818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov } 14918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov 15020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov bool is_relocation_grouped_by_info() { 15120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return (group_flags_ & RELOCATION_GROUPED_BY_INFO_FLAG) != 0; 15220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 15320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov 15420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov bool is_relocation_grouped_by_offset_delta() { 15520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return (group_flags_ & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0; 15620d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 15720d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov 15820d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov bool is_relocation_grouped_by_addend() { 15920d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return (group_flags_ & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0; 16020d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 16120d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov 16220d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov bool is_relocation_group_has_addend() { 16320d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov return (group_flags_ & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0; 16420d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov } 16520d89cb5b0d5eb7546a8fe8da44bbd91564dbddaDmitriy Ivanov 16618a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov decoder_t decoder_; 16718a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov size_t relocation_count_; 16818a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov size_t group_size_; 16918a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov size_t group_flags_; 17018a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov size_t group_r_offset_delta_; 17118a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov size_t relocation_index_; 17218a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov size_t relocation_group_index_; 17318a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov rel_t reloc_; 17418a6956b76a071097fc658c5fe13ef010e31864aDmitriy Ivanov}; 175