1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/disassembler_elf_32_arm.h" 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <algorithm> 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string> 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <vector> 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/basictypes.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h" 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/assembly_program.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/courgette.h" 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "courgette/encoded_program.h" 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace courgette { 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)CheckBool DisassemblerElf32ARM::Compress(ARM_RVA type, uint32 arm_op, RVA rva, 21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint16* c_op, uint32* addr) { 22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // This method takes an ARM or thumb opcode, extracts the relative 23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // target address from it (addr), and creates a corresponding 24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Courgette opcode (c_op). 25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // 26a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Details on ARM the opcodes, and how the relative targets are 27a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // computed were taken from the "ARM Architecture Reference Manual", 28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // section A4.1.5 and the "Thumb-2 supplement", section 4.6.12. 29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // ARM_OFF24 is for the ARM opcode. The rest are for thumb opcodes. 30a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) switch (type) { 31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF8: { 32a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // The offset is given by lower 8 bits of the op. It is a 9-bit 33a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // offset, shifted right one bit and signed extended. 34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp = (arm_op & 0x00FF) << 1; 35a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (temp & 0x0100) 36a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch temp |= 0xFFFFFE00; 37a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch temp += 4; // Offset from _next_ PC. 38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) fflush(stdout); 39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*addr) = temp; 41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*c_op) = (arm_op >> 8) | 0x1000; 42a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch break; 43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF11: { 45a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // The offset is given by lower 11 bits of the op, and is a 46a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch // 12-bit offset, shifted right one bit and sign extended. 47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp = (arm_op & 0x07FF) << 1; 48a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch if (temp & 0x00000800) 49a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch temp |= 0xFFFFF000; 50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch temp += 4; // Offset from _next_ PC. 51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*addr) = temp; 53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*c_op) = (arm_op >> 11) | 0x2000; 54a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch break; 55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF24: { 57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // The offset is given by the lower 24-bits of the op, shifted 58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // left 2 bits, and sign extended. 59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp = (arm_op & 0x00FFFFFF) << 2; 60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (temp & 0x02000000) 61a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= 0xFC000000; 62a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp += 8; 63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 64a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*addr) = temp; 65a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*c_op) = (arm_op >> 24) | 0x3000; 66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF25: { 69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp = 0; 70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (arm_op & 0x000007FF) << 1; // imm11 71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (arm_op & 0x03FF0000) >> 4; // imm10 72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 S = (arm_op & (1 << 26)) >> 26; 74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j2 = (arm_op & (1 << 11)) >> 11; 75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j1 = (arm_op & (1 << 13)) >> 13; 76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool bit12 = ((arm_op & (1 << 12)) >> 12) != 0; 77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool bit14 = ((arm_op & (1 << 14)) >> 14) != 0; 78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 79a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 i2 = ~(j2 ^ S) & 1; 80a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 i1 = ~(j1 ^ S) & 1; 81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool toARM = bit14 && !bit12; 82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (S << 24) | (i1 << 23) | (i2 << 22); 84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (temp & 0x01000000) // sign extension 86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= 0xFE000000; 87a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 prefetch; 88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (toARM) { 89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Align PC on 4-byte boundary 90a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 align4byte = (rva % 4) ? 2 : 4; 91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) prefetch = align4byte; 92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 93a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) prefetch = 4; 94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp += prefetch; 96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*addr) = temp; 97a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp2 = 0x4000; 99a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp2 |= (arm_op & (1 << 12)) >> 12; 100a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp2 |= (arm_op & (1 << 14)) >> 13; 101a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp2 |= (arm_op & (1 << 15)) >> 13; 102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp2 |= (arm_op & 0xF8000000) >> 24; 103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp2 |= (prefetch & 0x0000000F) << 8; 104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*c_op) = temp2; 105a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 106a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 107a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF21: { 108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp = 0; 10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) temp |= (arm_op & 0x000007FF) << 1; // imm11 11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) temp |= (arm_op & 0x003F0000) >> 4; // imm6 111a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 S = (arm_op & (1 << 26)) >> 26; 113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j2 = (arm_op & (1 << 11)) >> 11; 114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j1 = (arm_op & (1 << 13)) >> 13; 115a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (S << 20) | (j1 << 19) | (j2 << 18); 117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) if (temp & 0x00100000) // sign extension 119a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= 0xFFE00000; 120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp += 4; 121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*addr) = temp; 122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp2 = 0x5000; 124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp2 |= (arm_op & 0x03C00000) >> 22; // just save the cond 125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*c_op) = temp2; 126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 128a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch default: 129a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return false; 130a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch } 131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return true; 132a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)CheckBool DisassemblerElf32ARM::Decompress(ARM_RVA type, uint16 c_op, 135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 addr, uint32* arm_op) { 136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Reverses the process in the compress() method. Takes the 137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Courgette op and relative address and reconstructs the original 138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // ARM or thumb op. 139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) switch (type) { 140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF8: 141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*arm_op) = ((c_op & 0x0FFF) << 8) | (((addr - 4) >> 1) & 0x000000FF); 142a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 143a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF11: 144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*arm_op) = ((c_op & 0x0FFF) << 11) | (((addr - 4) >> 1) & 0x000007FF); 145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF24: 147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*arm_op) = ((c_op & 0x0FFF) << 24) | (((addr - 8) >> 2) & 0x00FFFFFF); 148a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 149a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF25: { 150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp = 0; 151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (c_op & (1 << 0)) << 12; 152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (c_op & (1 << 1)) << 13; 153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (c_op & (1 << 2)) << 13; 154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (c_op & (0xF8000000 >> 24)) << 24; 155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 156a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 prefetch = (c_op & 0x0F00) >> 8; 157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) addr -= prefetch; 158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) addr &= 0x01FFFFFF; 160a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 S = (addr & (1 << 24)) >> 24; 162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 i1 = (addr & (1 << 23)) >> 23; 163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 i2 = (addr & (1 << 22)) >> 22; 164a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 165a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j1 = ((~i1) ^ S) & 1; 166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j2 = ((~i2) ^ S) & 1; 167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= S << 26; 169a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= j2 << 11; 170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= j1 << 13; 171a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (addr & (0x000007FF << 1)) >> 1; 173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (addr & (0x03FF0000 >> 4)) << 4; 174a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*arm_op) = temp; 176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 177a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 178a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF21: { 179a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 temp = 0xF0008000; 180a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (c_op & (0x03C00000 >> 22)) << 22; 181a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 182a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) addr -= 4; 183a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) addr &= 0x001FFFFF; 184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 S = (addr & (1 << 20)) >> 20; 186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j1 = (addr & (1 << 19)) >> 19; 187a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 j2 = (addr & (1 << 18)) >> 18; 188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= S << 26; 190a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= j2 << 11; 191a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= j1 << 13; 192a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 193a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (addr & (0x000007FF << 1)) >> 1; 194a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) temp |= (addr & (0x003F0000 >> 4)) << 4; 195a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 196a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) (*arm_op) = temp; 197a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) break; 198a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 199a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) default: 200a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 201a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 202a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch return true; 203a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch} 204a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch 205a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)uint16 DisassemblerElf32ARM::TypedRVAARM::op_size() const { 206a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) switch (type_) { 207a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF8: 208a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return 2; 209a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF11: 210a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return 2; 211a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF24: 212a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return 4; 213a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF25: 214a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return 4; 215a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF21: 216a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return 4; 217a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) default: 218a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return -1; 219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 220a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 221a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 222a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)CheckBool DisassemblerElf32ARM::TypedRVAARM::ComputeRelativeTarget( 223a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const uint8* op_pointer) { 224a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) arm_op_ = op_pointer; 225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) switch (type_) { 226a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF8: 227a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Fall through 228a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF11: { 229a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA relative_target; 230a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) CheckBool ret = Compress(type_, Read16LittleEndian(op_pointer), rva(), 231a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) &c_op_, &relative_target); 232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) set_relative_target(relative_target); 233a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return ret; 234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 235a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF24: { 236a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA relative_target; 237a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) CheckBool ret = Compress(type_, Read32LittleEndian(op_pointer), rva(), 238a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) &c_op_, &relative_target); 239a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) set_relative_target(relative_target); 240a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return ret; 241a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 242a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF25: 243a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Fall through 244a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) case ARM_OFF21: { 245a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // A thumb-2 op is 32 bits stored as two 16-bit words 246a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 pval = (Read16LittleEndian(op_pointer) << 16) 247a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) | Read16LittleEndian(op_pointer + 2); 248a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA relative_target; 249a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) CheckBool ret = Compress(type_, pval, rva(), &c_op_, &relative_target); 250a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) set_relative_target(relative_target); 251a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return ret; 252a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 253a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) default: 254a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 255a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 256a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 257a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 258a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)CheckBool DisassemblerElf32ARM::TypedRVAARM::EmitInstruction( 259a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) AssemblyProgram* program, 260a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA target_rva) { 261a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return program->EmitRel32ARM(c_op(), 262a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) program->FindOrMakeRel32Label(target_rva), 263a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) arm_op_, 264a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) op_size()); 265a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)} 266a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochDisassemblerElf32ARM::DisassemblerElf32ARM(const void* start, size_t length) 268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch : DisassemblerElf32(start, length) { 269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Convert an ELF relocation struction into an RVA 272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochCheckBool DisassemblerElf32ARM::RelToRVA(Elf32_Rel rel, RVA* result) const { 273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The rightmost byte of r_info is the type... 275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch elf32_rel_arm_type_values type = 276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (elf32_rel_arm_type_values)(unsigned char)rel.r_info; 277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The other 3 bytes of r_info are the symbol 279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32 symbol = rel.r_info >> 8; 280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch switch(type) 282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch { 283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch case R_ARM_RELATIVE: 284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (symbol != 0) 285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // This is a basic ABS32 relocation address 288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *result = rel.r_offset; 289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch default: 292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochCheckBool DisassemblerElf32ARM::ParseRelocationSection( 297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Elf32_Shdr *section_header, 298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AssemblyProgram* program) { 299ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // This method compresses a contiguous stretch of R_ARM_RELATIVE 300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // entries in the relocation table with a Courgette relocation table 301ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // instruction. It skips any entries at the beginning that appear 302ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // in a section that Courgette doesn't support, e.g. INIT. 303ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Specifically, the entries should be 304ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // (1) In the same relocation table 305ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // (2) Are consecutive 306ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // (3) Are sorted in memory address order 307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // 308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Happily, this is normally the case, but it's not required by spec 309eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // so we check, and just don't do it if we don't match up. 310ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // 311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The expectation is that one relocation section will contain 312ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // all of our R_ARM_RELATIVE entries in the expected order followed 313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // by assorted other entries we can't use special handling for. 314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool match = true; 316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Walk all the bytes in the section, matching relocation table or not 318eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch size_t file_offset = section_header->sh_offset; 319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch size_t section_end = section_header->sh_offset + section_header->sh_size; 320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Elf32_Rel *section_relocs_iter = 322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (Elf32_Rel *)OffsetToPointer(section_header->sh_offset); 323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch uint32 section_relocs_count = section_header->sh_size / 325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch section_header->sh_entsize; 326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (abs32_locations_.size() > section_relocs_count) 328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch match = false; 329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!abs32_locations_.empty()) { 331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch std::vector<RVA>::iterator reloc_iter = abs32_locations_.begin(); 332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch for (uint32 i = 0; i < section_relocs_count; i++) { 334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (section_relocs_iter->r_offset == *reloc_iter) 335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch break; 336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 337ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!ParseSimpleRegion(file_offset, file_offset + sizeof(Elf32_Rel), 338ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch program)) 339ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return false; 340ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 341ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch file_offset += sizeof(Elf32_Rel); 342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch ++section_relocs_iter; 343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch while (match && (reloc_iter != abs32_locations_.end())) { 346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (section_relocs_iter->r_info != R_ARM_RELATIVE || 347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch section_relocs_iter->r_offset != *reloc_iter) 348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch match = false; 349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch section_relocs_iter++; 351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch reloc_iter++; 352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch file_offset += sizeof(Elf32_Rel); 353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (match) { 356ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch // Skip over relocation tables 357ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (!program->EmitElfARMRelocationInstruction()) 358ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return false; 359ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch } 360eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 361eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 362eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return ParseSimpleRegion(file_offset, section_end, program); 363eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 365eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochCheckBool DisassemblerElf32ARM::ParseRel32RelocsFromSection( 366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const Elf32_Shdr* section_header) { 367a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 368a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 start_file_offset = section_header->sh_offset; 369a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 end_file_offset = start_file_offset + section_header->sh_size; 370a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 371a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const uint8* start_pointer = OffsetToPointer(start_file_offset); 372a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const uint8* end_pointer = OffsetToPointer(end_file_offset); 373a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 374a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Quick way to convert from Pointer to RVA within a single Section is to 375a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // subtract 'pointer_to_rva'. 376a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const uint8* const adjust_pointer_to_rva = start_pointer - 377a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) section_header->sh_addr; 378a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 379a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Find the rel32 relocations. 380a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) const uint8* p = start_pointer; 381a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool on_32bit = 1; // 32-bit ARM ops appear on 32-bit boundaries, so track it 382a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) while (p < end_pointer) { 383a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Heuristic discovery of rel32 locations in instruction stream: are the 384a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // next few bytes the start of an instruction containing a rel32 385a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // addressing mode? 386a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 387a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) TypedRVAARM* rel32_rva = NULL; 388c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch RVA target_rva = 0; 389a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bool found = false; 390a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 391a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // 16-bit thumb ops 392a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!found && (p + 3) <= end_pointer) { 393a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint16 pval = Read16LittleEndian(p); 394a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if ((pval & 0xF000) == 0xD000) { 395a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA rva = static_cast<RVA>(p - adjust_pointer_to_rva); 396a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 397a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) rel32_rva = new TypedRVAARM(ARM_OFF8, rva); 398a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!rel32_rva->ComputeRelativeTarget((uint8*) p)) { 399a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 400a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 401a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) target_rva = rel32_rva->rva() + rel32_rva->relative_target(); 402a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) found = true; 403a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else if ((pval & 0xF800) == 0xE000) { 404a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA rva = static_cast<RVA>(p - adjust_pointer_to_rva); 405a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 406a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) rel32_rva = new TypedRVAARM(ARM_OFF11, rva); 407a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!rel32_rva->ComputeRelativeTarget((uint8*) p)) { 408a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 409a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 410a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) target_rva = rel32_rva->rva() + rel32_rva->relative_target(); 411a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) found = true; 412a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 413a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 414a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 415a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // thumb-2 ops comprised of two 16-bit words 416a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!found && (p + 5) <= end_pointer) { 417a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // This is really two 16-bit words, not one 32-bit word. 418a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 pval = (Read16LittleEndian(p) << 16) | Read16LittleEndian(p + 2); 419a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if ((pval & 0xF8008000) == 0xF0008000) { 420a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Covers thumb-2's 32-bit conditional/unconditional branches 421a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 422a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if ( (pval & (1 << 14)) || (pval & (1 << 12)) ) { 423a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // A branch, with link, or with link and exchange. 424a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA rva = static_cast<RVA>(p - adjust_pointer_to_rva); 425a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 426a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) rel32_rva = new TypedRVAARM(ARM_OFF25, rva); 427a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!rel32_rva->ComputeRelativeTarget((uint8*) p)) { 428a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 429a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 430a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) target_rva = rel32_rva->rva() + rel32_rva->relative_target(); 431a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) found = true; 432a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 433a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // TODO(paulgazz) make sure cond is not 111 434a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // A conditional branch instruction 435a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA rva = static_cast<RVA>(p - adjust_pointer_to_rva); 436a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 437a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) rel32_rva = new TypedRVAARM(ARM_OFF21, rva); 438a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!rel32_rva->ComputeRelativeTarget((uint8*) p)) { 439a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 440a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 441a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) target_rva = rel32_rva->rva() + rel32_rva->relative_target(); 442a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) found = true; 443a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 444a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 445a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 446a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 447a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // 32-bit ARM ops 448a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!found && on_32bit && (p + 5) <= end_pointer) { 449a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) uint32 pval = Read32LittleEndian(p); 450a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if ((pval & 0x0E000000) == 0x0A000000) { 451a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Covers both 0x0A 0x0B ARM relative branches 452a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) RVA rva = static_cast<RVA>(p - adjust_pointer_to_rva); 453a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 454a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) rel32_rva = new TypedRVAARM(ARM_OFF24, rva); 455a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!rel32_rva->ComputeRelativeTarget((uint8*) p)) { 456a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return false; 457a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 458a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) target_rva = rel32_rva->rva() + rel32_rva->relative_target(); 459a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) found = true; 460a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 461a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 462a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 463a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (found && IsValidRVA(target_rva)) { 464a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) rel32_locations_.push_back(rel32_rva); 465a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#if COURGETTE_HISTOGRAM_TARGETS 466a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) ++rel32_target_rvas_[target_rva]; 467a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#endif 468a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) p += rel32_rva->op_size(); 469a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 470a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // A tricky way to update the on_32bit flag. Here is the truth table: 471a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // on_32bit | on_32bit size is 4 472a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // ---------+--------------------- 473a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // 1 | 0 0 474a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // 0 | 0 1 475a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // 0 | 1 0 476a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // 1 | 1 1 477a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) on_32bit = (~(on_32bit ^ (rel32_rva->op_size() == 4))) != 0; 478a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } else { 479a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // Move 2 bytes at a time, but track 32-bit boundaries 480a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) p += 2; 481a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) on_32bit = ((on_32bit + 1) % 2) != 0; 482a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 483a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) } 484a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace courgette 489