10b57cec5SDimitry Andric //===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
9480093f4SDimitry Andric // This file implements the unwind opcode assembler for ARM exception handling
100b57cec5SDimitry Andric // table.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "ARMUnwindOpAsm.h"
15*5f757f3fSDimitry Andric #include "llvm/ADT/bit.h"
160b57cec5SDimitry Andric #include "llvm/Support/ARMEHABI.h"
170b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
180b57cec5SDimitry Andric #include <cassert>
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric namespace {
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes
250b57cec5SDimitry Andric /// with MSB to LSB per uint32_t ordering. For example, the first byte will
260b57cec5SDimitry Andric /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,
270b57cec5SDimitry Andric /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.
280b57cec5SDimitry Andric class UnwindOpcodeStreamer {
290b57cec5SDimitry Andric private:
300b57cec5SDimitry Andric SmallVectorImpl<uint8_t> &Vec;
310b57cec5SDimitry Andric size_t Pos = 3;
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric public:
UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> & V)340b57cec5SDimitry Andric UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V) {}
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric /// Emit the byte in MSB to LSB per uint32_t order.
EmitByte(uint8_t elem)370b57cec5SDimitry Andric void EmitByte(uint8_t elem) {
380b57cec5SDimitry Andric Vec[Pos] = elem;
390b57cec5SDimitry Andric Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric /// Emit the size prefix.
EmitSize(size_t Size)430b57cec5SDimitry Andric void EmitSize(size_t Size) {
440b57cec5SDimitry Andric size_t SizeInWords = (Size + 3) / 4;
450b57cec5SDimitry Andric assert(SizeInWords <= 0x100u &&
460b57cec5SDimitry Andric "Only 256 additional words are allowed for unwind opcodes");
470b57cec5SDimitry Andric EmitByte(static_cast<uint8_t>(SizeInWords - 1));
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric /// Emit the personality index prefix.
EmitPersonalityIndex(unsigned PI)510b57cec5SDimitry Andric void EmitPersonalityIndex(unsigned PI) {
520b57cec5SDimitry Andric assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&
530b57cec5SDimitry Andric "Invalid personality prefix");
540b57cec5SDimitry Andric EmitByte(ARM::EHABI::EHT_COMPACT | PI);
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric /// Fill the rest of bytes with FINISH opcode.
FillFinishOpcode()580b57cec5SDimitry Andric void FillFinishOpcode() {
590b57cec5SDimitry Andric while (Pos < Vec.size())
600b57cec5SDimitry Andric EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric };
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric } // end anonymous namespace
650b57cec5SDimitry Andric
EmitRegSave(uint32_t RegSave)660b57cec5SDimitry Andric void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
670eae32dcSDimitry Andric if (RegSave == 0u) {
680eae32dcSDimitry Andric // That's the special case for RA PAC.
690eae32dcSDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_RA_AUTH_CODE);
700b57cec5SDimitry Andric return;
710eae32dcSDimitry Andric }
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric // One byte opcode to save register r14 and r11-r4
740b57cec5SDimitry Andric if (RegSave & (1u << 4)) {
750b57cec5SDimitry Andric // The one byte opcode will always save r4, thus we can't use the one byte
760b57cec5SDimitry Andric // opcode when r4 is not in .save directive.
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric // Compute the consecutive registers from r4 to r11.
790b57cec5SDimitry Andric uint32_t Mask = RegSave & 0xff0u;
8006c3fb27SDimitry Andric uint32_t Range = llvm::countr_one(Mask >> 5); // Exclude r4.
810b57cec5SDimitry Andric // Mask off non-consecutive registers. Keep r4.
820b57cec5SDimitry Andric Mask &= ~(0xffffffe0u << Range);
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric // Emit this opcode when the mask covers every registers.
850b57cec5SDimitry Andric uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
860b57cec5SDimitry Andric if (UnmaskedReg == 0u) {
870b57cec5SDimitry Andric // Pop r[4 : (4 + n)]
880b57cec5SDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
890b57cec5SDimitry Andric RegSave &= 0x000fu;
900b57cec5SDimitry Andric } else if (UnmaskedReg == (1u << 14)) {
910b57cec5SDimitry Andric // Pop r[14] + r[4 : (4 + n)]
920b57cec5SDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
930b57cec5SDimitry Andric RegSave &= 0x000fu;
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric // Two bytes opcode to save register r15-r4
980b57cec5SDimitry Andric if ((RegSave & 0xfff0u) != 0)
990b57cec5SDimitry Andric EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric // Opcode to save register r3-r0
1020b57cec5SDimitry Andric if ((RegSave & 0x000fu) != 0)
1030b57cec5SDimitry Andric EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric
1060b57cec5SDimitry Andric /// Emit unwind opcodes for .vsave directives
EmitVFPRegSave(uint32_t VFPRegSave)1070b57cec5SDimitry Andric void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
1080b57cec5SDimitry Andric // We only have 4 bits to save the offset in the opcode so look at the lower
1090b57cec5SDimitry Andric // and upper 16 bits separately.
1100b57cec5SDimitry Andric for (uint32_t Regs : {VFPRegSave & 0xffff0000u, VFPRegSave & 0x0000ffffu}) {
1110b57cec5SDimitry Andric while (Regs) {
1120b57cec5SDimitry Andric // Now look for a run of set bits. Remember the MSB and LSB of the run.
113bdd1243dSDimitry Andric auto RangeMSB = llvm::bit_width(Regs);
11406c3fb27SDimitry Andric auto RangeLen = llvm::countl_one(Regs << (32 - RangeMSB));
1150b57cec5SDimitry Andric auto RangeLSB = RangeMSB - RangeLen;
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric int Opcode = RangeLSB >= 16
1180b57cec5SDimitry Andric ? ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16
1190b57cec5SDimitry Andric : ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD;
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric EmitInt16(Opcode | ((RangeLSB % 16) << 4) | (RangeLen - 1));
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric // Zero out bits we're done with.
1240b57cec5SDimitry Andric Regs &= ~(-1u << RangeLSB);
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric /// Emit unwind opcodes to copy address from source register to $sp.
EmitSetSP(uint16_t Reg)1300b57cec5SDimitry Andric void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {
1310b57cec5SDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric /// Emit unwind opcodes to add $sp with an offset.
EmitSPOffset(int64_t Offset)1350b57cec5SDimitry Andric void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
1360b57cec5SDimitry Andric if (Offset > 0x200) {
1370b57cec5SDimitry Andric uint8_t Buff[16];
1380b57cec5SDimitry Andric Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;
1390b57cec5SDimitry Andric size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);
1405ffd83dbSDimitry Andric emitBytes(Buff, ULEBSize + 1);
1410b57cec5SDimitry Andric } else if (Offset > 0) {
1420b57cec5SDimitry Andric if (Offset > 0x100) {
1430b57cec5SDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);
1440b57cec5SDimitry Andric Offset -= 0x100;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |
1470b57cec5SDimitry Andric static_cast<uint8_t>((Offset - 4) >> 2));
1480b57cec5SDimitry Andric } else if (Offset < 0) {
1490b57cec5SDimitry Andric while (Offset < -0x100) {
1500b57cec5SDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);
1510b57cec5SDimitry Andric Offset += 0x100;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |
1540b57cec5SDimitry Andric static_cast<uint8_t>(((-Offset) - 4) >> 2));
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric
Finalize(unsigned & PersonalityIndex,SmallVectorImpl<uint8_t> & Result)1580b57cec5SDimitry Andric void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,
1590b57cec5SDimitry Andric SmallVectorImpl<uint8_t> &Result) {
1600b57cec5SDimitry Andric UnwindOpcodeStreamer OpStreamer(Result);
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric if (HasPersonality) {
1630b57cec5SDimitry Andric // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]
1640b57cec5SDimitry Andric PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;
1650b57cec5SDimitry Andric size_t TotalSize = Ops.size() + 1;
1660b57cec5SDimitry Andric size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
1670b57cec5SDimitry Andric Result.resize(RoundUpSize);
1680b57cec5SDimitry Andric OpStreamer.EmitSize(RoundUpSize);
1690b57cec5SDimitry Andric } else {
1700b57cec5SDimitry Andric // If no personalityindex is specified, select ane
1710b57cec5SDimitry Andric if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)
1720b57cec5SDimitry Andric PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0
1730b57cec5SDimitry Andric : ARM::EHABI::AEABI_UNWIND_CPP_PR1;
1740b57cec5SDimitry Andric if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {
1750b57cec5SDimitry Andric // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
1760b57cec5SDimitry Andric assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");
1770b57cec5SDimitry Andric Result.resize(4);
1780b57cec5SDimitry Andric OpStreamer.EmitPersonalityIndex(PersonalityIndex);
1790b57cec5SDimitry Andric } else {
1800b57cec5SDimitry Andric // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]
1810b57cec5SDimitry Andric size_t TotalSize = Ops.size() + 2;
1820b57cec5SDimitry Andric size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
1830b57cec5SDimitry Andric Result.resize(RoundUpSize);
1840b57cec5SDimitry Andric OpStreamer.EmitPersonalityIndex(PersonalityIndex);
1850b57cec5SDimitry Andric OpStreamer.EmitSize(RoundUpSize);
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric // Copy the unwind opcodes
1900b57cec5SDimitry Andric for (size_t i = OpBegins.size() - 1; i > 0; --i)
1910b57cec5SDimitry Andric for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)
1920b57cec5SDimitry Andric OpStreamer.EmitByte(Ops[j]);
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric // Emit the padding finish opcodes if the size is not multiple of 4.
1950b57cec5SDimitry Andric OpStreamer.FillFinishOpcode();
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric // Reset the assembler state
1980b57cec5SDimitry Andric Reset();
1990b57cec5SDimitry Andric }
200