1b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines/* 2b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * Copyright 2011, The Android Open Source Project 3b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * 4b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * Licensed under the Apache License, Version 2.0 (the "License"); 5b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * you may not use this file except in compliance with the License. 6b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * You may obtain a copy of the License at 7b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * 8b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * http://www.apache.org/licenses/LICENSE-2.0 9b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * 10b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * Unless required by applicable law or agreed to in writing, software 11b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * distributed under the License is distributed on an "AS IS" BASIS, 12b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * See the License for the specific language governing permissions and 14b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines * limitations under the License. 15b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines */ 16b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 17b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "StubLayout.h" 18b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 19b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "utils/flush_cpu_cache.h" 20b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "utils/raw_ostream.h" 21b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include "utils/rsl_assert.h" 22b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 23b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include <stdint.h> 24b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include <stdlib.h> 25b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines#include <sys/mman.h> 26b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 27b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen HinesStubLayout::StubLayout() : table(NULL), count(0) { 28b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 29b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 30b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid StubLayout::initStubTable(unsigned char *table_, size_t count_) { 31b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines table = table_; 32b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines count = count_; 33b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 34b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 35b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid *StubLayout::allocateStub(void *addr) { 36b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines // Check if we have created this stub or not. 37b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines std::map<void *, void *>::iterator index_iter = stub_index.find(addr); 38b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 39b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines if (index_iter != stub_index.end()) { 40b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines return index_iter->second; 41b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines } 42b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 43b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines // We have to create a new stub 44b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines if (count == 0) { 45b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines // No free stub slot is available 46b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines return NULL; 47b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines } 48b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 49b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines // Initialize the stub 50b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines unsigned char *stub = table; 51b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines setStubAddress(stub, addr); 52b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub_index.insert(std::make_pair(addr, stub)); 53b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 54b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines // Increase the free stub slot pointer 55b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines table += getUnitStubSize(); 56b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines count--; 57b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 58b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines return stub; 59b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 60b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 61b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinessize_t StubLayout::calcStubTableSize(size_t count) const { 62b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines return count * getUnitStubSize(); 63b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 64b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 65b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinessize_t StubLayoutARM::getUnitStubSize() const { 66b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines return 8; 67b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 68b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 69b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid StubLayoutARM::setStubAddress(void *stub_, void *addr) { 70b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines uint8_t *stub = (uint8_t *)stub_; 71b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[0] = 0x04; // ldr pc, [pc, #-4] 72b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[1] = 0xf0; // ldr pc, [pc, #-4] 73b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[2] = 0x1f; // ldr pc, [pc, #-4] 74b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[3] = 0xe5; // ldr pc, [pc, #-4] 75b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 76b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines void **target = (void **)(stub + 4); 77b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines *target = addr; 78b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 79b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 80b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinessize_t StubLayoutMIPS::getUnitStubSize() const { 81b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines return 16; 82b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 83b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 84b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hinesvoid StubLayoutMIPS::setStubAddress(void *stub_, void *addr) { 85b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines uint32_t addr32 = (uint32_t)(uintptr_t)addr; 86b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines uint16_t addr_hi16 = (addr32 >> 16) & 0xffff; 87b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines uint16_t addr_lo16 = addr32 & 0xffff; 88b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines 89b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines uint32_t *stub = (uint32_t *)stub_; 90b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[0] = 0x3c190000ul | addr_hi16; // lui 91b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[1] = 0x37390000ul | addr_lo16; // ori 92b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[2] = 0x03200008ul; // jr (jump register) 93b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines stub[3] = 0x00000000ul; // nop 94b53c8a59e6f21ed36a0c3d9d4ce5834d4cc3c298Stephen Hines} 95