brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.9 KiB · c62d17f Raw
200 lines · cpp
1//===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the unwind opcode assembler for ARM exception handling10// table.11//12//===----------------------------------------------------------------------===//13 14#include "ARMUnwindOpAsm.h"15#include "llvm/ADT/bit.h"16#include "llvm/Support/ARMEHABI.h"17#include "llvm/Support/LEB128.h"18#include <cassert>19 20using namespace llvm;21 22namespace {23 24  /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes25  /// with MSB to LSB per uint32_t ordering.  For example, the first byte will26  /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,27  /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.28  class UnwindOpcodeStreamer {29  private:30    SmallVectorImpl<uint8_t> &Vec;31    size_t Pos = 3;32 33  public:34    UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V) {}35 36    /// Emit the byte in MSB to LSB per uint32_t order.37    void EmitByte(uint8_t elem) {38      Vec[Pos] = elem;39      Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);40    }41 42    /// Emit the size prefix.43    void EmitSize(size_t Size) {44      size_t SizeInWords = (Size + 3) / 4;45      assert(SizeInWords <= 0x100u &&46             "Only 256 additional words are allowed for unwind opcodes");47      EmitByte(static_cast<uint8_t>(SizeInWords - 1));48    }49 50    /// Emit the personality index prefix.51    void EmitPersonalityIndex(unsigned PI) {52      assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&53             "Invalid personality prefix");54      EmitByte(ARM::EHABI::EHT_COMPACT | PI);55    }56 57    /// Fill the rest of bytes with FINISH opcode.58    void FillFinishOpcode() {59      while (Pos < Vec.size())60        EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);61    }62  };63 64} // end anonymous namespace65 66void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {67  if (RegSave == 0u) {68    // That's the special case for RA PAC.69    EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_RA_AUTH_CODE);70    return;71  }72 73  // One byte opcode to save register r14 and r11-r474  if (RegSave & (1u << 4)) {75    // The one byte opcode will always save r4, thus we can't use the one byte76    // opcode when r4 is not in .save directive.77 78    // Compute the consecutive registers from r4 to r11.79    uint32_t Mask = RegSave & 0xff0u;80    uint32_t Range = llvm::countr_one(Mask >> 5); // Exclude r4.81    // Mask off non-consecutive registers. Keep r4.82    Mask &= ~(0xffffffe0u << Range);83 84    // Emit this opcode when the mask covers every registers.85    uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);86    if (UnmaskedReg == 0u) {87      // Pop r[4 : (4 + n)]88      EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);89      RegSave &= 0x000fu;90    } else if (UnmaskedReg == (1u << 14)) {91      // Pop r[14] + r[4 : (4 + n)]92      EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);93      RegSave &= 0x000fu;94    }95  }96 97  // Two bytes opcode to save register r15-r498  if ((RegSave & 0xfff0u) != 0)99    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));100 101  // Opcode to save register r3-r0102  if ((RegSave & 0x000fu) != 0)103    EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));104}105 106/// Emit unwind opcodes for .vsave directives107void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {108  // We only have 4 bits to save the offset in the opcode so look at the lower109  // and upper 16 bits separately.110  for (uint32_t Regs : {VFPRegSave & 0xffff0000u, VFPRegSave & 0x0000ffffu}) {111    while (Regs) {112      // Now look for a run of set bits. Remember the MSB and LSB of the run.113      auto RangeMSB = llvm::bit_width(Regs);114      auto RangeLen = llvm::countl_one(Regs << (32 - RangeMSB));115      auto RangeLSB = RangeMSB - RangeLen;116 117      int Opcode = RangeLSB >= 16118                       ? ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16119                       : ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD;120 121      EmitInt16(Opcode | ((RangeLSB % 16) << 4) | (RangeLen - 1));122 123      // Zero out bits we're done with.124      Regs &= ~(-1u << RangeLSB);125    }126  }127}128 129/// Emit unwind opcodes to copy address from source register to $sp.130void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {131  EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);132}133 134/// Emit unwind opcodes to add $sp with an offset.135void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {136  if (Offset > 0x200) {137    uint8_t Buff[16];138    Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;139    size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);140    emitBytes(Buff, ULEBSize + 1);141  } else if (Offset > 0) {142    if (Offset > 0x100) {143      EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);144      Offset -= 0x100;145    }146    EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |147             static_cast<uint8_t>((Offset - 4) >> 2));148  } else if (Offset < 0) {149    while (Offset < -0x100) {150      EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);151      Offset += 0x100;152    }153    EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |154             static_cast<uint8_t>(((-Offset) - 4) >> 2));155  }156}157 158void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,159                                     SmallVectorImpl<uint8_t> &Result) {160  UnwindOpcodeStreamer OpStreamer(Result);161 162  if (HasPersonality) {163    // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]164    PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;165    size_t TotalSize = Ops.size() + 1;166    size_t RoundUpSize = (TotalSize + 3) / 4 * 4;167    Result.resize(RoundUpSize);168    OpStreamer.EmitSize(RoundUpSize);169  } else {170    // If no personalityindex is specified, select ane171    if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)172      PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0173                                           : ARM::EHABI::AEABI_UNWIND_CPP_PR1;174    if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {175      // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]176      assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");177      Result.resize(4);178      OpStreamer.EmitPersonalityIndex(PersonalityIndex);179    } else {180      // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]181      size_t TotalSize = Ops.size() + 2;182      size_t RoundUpSize = (TotalSize + 3) / 4 * 4;183      Result.resize(RoundUpSize);184      OpStreamer.EmitPersonalityIndex(PersonalityIndex);185      OpStreamer.EmitSize(RoundUpSize);186    }187  }188 189  // Copy the unwind opcodes190  for (size_t i = OpBegins.size() - 1; i > 0; --i)191    for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)192      OpStreamer.EmitByte(Ops[j]);193 194  // Emit the padding finish opcodes if the size is not multiple of 4.195  OpStreamer.FillFinishOpcode();196 197  // Reset the assembler state198  Reset();199}200