17330f729Sjoerg //===-- ARMUnwindOpAsm.cpp - ARM Unwind Opcodes Assembler -------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
9*82d56013Sjoerg // This file implements the unwind opcode assembler for ARM exception handling
107330f729Sjoerg // table.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg
147330f729Sjoerg #include "ARMUnwindOpAsm.h"
157330f729Sjoerg #include "llvm/Support/ARMEHABI.h"
167330f729Sjoerg #include "llvm/Support/LEB128.h"
177330f729Sjoerg #include "llvm/Support/MathExtras.h"
187330f729Sjoerg #include <cassert>
197330f729Sjoerg
207330f729Sjoerg using namespace llvm;
217330f729Sjoerg
227330f729Sjoerg namespace {
237330f729Sjoerg
247330f729Sjoerg /// UnwindOpcodeStreamer - The simple wrapper over SmallVector to emit bytes
257330f729Sjoerg /// with MSB to LSB per uint32_t ordering. For example, the first byte will
267330f729Sjoerg /// be placed in Vec[3], and the following bytes will be placed in 2, 1, 0,
277330f729Sjoerg /// 7, 6, 5, 4, 11, 10, 9, 8, and so on.
287330f729Sjoerg class UnwindOpcodeStreamer {
297330f729Sjoerg private:
307330f729Sjoerg SmallVectorImpl<uint8_t> &Vec;
317330f729Sjoerg size_t Pos = 3;
327330f729Sjoerg
337330f729Sjoerg public:
UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> & V)347330f729Sjoerg UnwindOpcodeStreamer(SmallVectorImpl<uint8_t> &V) : Vec(V) {}
357330f729Sjoerg
367330f729Sjoerg /// Emit the byte in MSB to LSB per uint32_t order.
EmitByte(uint8_t elem)377330f729Sjoerg void EmitByte(uint8_t elem) {
387330f729Sjoerg Vec[Pos] = elem;
397330f729Sjoerg Pos = (((Pos ^ 0x3u) + 1) ^ 0x3u);
407330f729Sjoerg }
417330f729Sjoerg
427330f729Sjoerg /// Emit the size prefix.
EmitSize(size_t Size)437330f729Sjoerg void EmitSize(size_t Size) {
447330f729Sjoerg size_t SizeInWords = (Size + 3) / 4;
457330f729Sjoerg assert(SizeInWords <= 0x100u &&
467330f729Sjoerg "Only 256 additional words are allowed for unwind opcodes");
477330f729Sjoerg EmitByte(static_cast<uint8_t>(SizeInWords - 1));
487330f729Sjoerg }
497330f729Sjoerg
507330f729Sjoerg /// Emit the personality index prefix.
EmitPersonalityIndex(unsigned PI)517330f729Sjoerg void EmitPersonalityIndex(unsigned PI) {
527330f729Sjoerg assert(PI < ARM::EHABI::NUM_PERSONALITY_INDEX &&
537330f729Sjoerg "Invalid personality prefix");
547330f729Sjoerg EmitByte(ARM::EHABI::EHT_COMPACT | PI);
557330f729Sjoerg }
567330f729Sjoerg
577330f729Sjoerg /// Fill the rest of bytes with FINISH opcode.
FillFinishOpcode()587330f729Sjoerg void FillFinishOpcode() {
597330f729Sjoerg while (Pos < Vec.size())
607330f729Sjoerg EmitByte(ARM::EHABI::UNWIND_OPCODE_FINISH);
617330f729Sjoerg }
627330f729Sjoerg };
637330f729Sjoerg
647330f729Sjoerg } // end anonymous namespace
657330f729Sjoerg
EmitRegSave(uint32_t RegSave)667330f729Sjoerg void UnwindOpcodeAssembler::EmitRegSave(uint32_t RegSave) {
677330f729Sjoerg if (RegSave == 0u)
687330f729Sjoerg return;
697330f729Sjoerg
707330f729Sjoerg // One byte opcode to save register r14 and r11-r4
717330f729Sjoerg if (RegSave & (1u << 4)) {
727330f729Sjoerg // The one byte opcode will always save r4, thus we can't use the one byte
737330f729Sjoerg // opcode when r4 is not in .save directive.
747330f729Sjoerg
757330f729Sjoerg // Compute the consecutive registers from r4 to r11.
767330f729Sjoerg uint32_t Mask = RegSave & 0xff0u;
777330f729Sjoerg uint32_t Range = countTrailingOnes(Mask >> 5); // Exclude r4.
787330f729Sjoerg // Mask off non-consecutive registers. Keep r4.
797330f729Sjoerg Mask &= ~(0xffffffe0u << Range);
807330f729Sjoerg
817330f729Sjoerg // Emit this opcode when the mask covers every registers.
827330f729Sjoerg uint32_t UnmaskedReg = RegSave & 0xfff0u & (~Mask);
837330f729Sjoerg if (UnmaskedReg == 0u) {
847330f729Sjoerg // Pop r[4 : (4 + n)]
857330f729Sjoerg EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4 | Range);
867330f729Sjoerg RegSave &= 0x000fu;
877330f729Sjoerg } else if (UnmaskedReg == (1u << 14)) {
887330f729Sjoerg // Pop r[14] + r[4 : (4 + n)]
897330f729Sjoerg EmitInt8(ARM::EHABI::UNWIND_OPCODE_POP_REG_RANGE_R4_R14 | Range);
907330f729Sjoerg RegSave &= 0x000fu;
917330f729Sjoerg }
927330f729Sjoerg }
937330f729Sjoerg
947330f729Sjoerg // Two bytes opcode to save register r15-r4
957330f729Sjoerg if ((RegSave & 0xfff0u) != 0)
967330f729Sjoerg EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK_R4 | (RegSave >> 4));
977330f729Sjoerg
987330f729Sjoerg // Opcode to save register r3-r0
997330f729Sjoerg if ((RegSave & 0x000fu) != 0)
1007330f729Sjoerg EmitInt16(ARM::EHABI::UNWIND_OPCODE_POP_REG_MASK | (RegSave & 0x000fu));
1017330f729Sjoerg }
1027330f729Sjoerg
1037330f729Sjoerg /// Emit unwind opcodes for .vsave directives
EmitVFPRegSave(uint32_t VFPRegSave)1047330f729Sjoerg void UnwindOpcodeAssembler::EmitVFPRegSave(uint32_t VFPRegSave) {
1057330f729Sjoerg // We only have 4 bits to save the offset in the opcode so look at the lower
1067330f729Sjoerg // and upper 16 bits separately.
1077330f729Sjoerg for (uint32_t Regs : {VFPRegSave & 0xffff0000u, VFPRegSave & 0x0000ffffu}) {
1087330f729Sjoerg while (Regs) {
1097330f729Sjoerg // Now look for a run of set bits. Remember the MSB and LSB of the run.
1107330f729Sjoerg auto RangeMSB = 32 - countLeadingZeros(Regs);
1117330f729Sjoerg auto RangeLen = countLeadingOnes(Regs << (32 - RangeMSB));
1127330f729Sjoerg auto RangeLSB = RangeMSB - RangeLen;
1137330f729Sjoerg
1147330f729Sjoerg int Opcode = RangeLSB >= 16
1157330f729Sjoerg ? ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD_D16
1167330f729Sjoerg : ARM::EHABI::UNWIND_OPCODE_POP_VFP_REG_RANGE_FSTMFDD;
1177330f729Sjoerg
1187330f729Sjoerg EmitInt16(Opcode | ((RangeLSB % 16) << 4) | (RangeLen - 1));
1197330f729Sjoerg
1207330f729Sjoerg // Zero out bits we're done with.
1217330f729Sjoerg Regs &= ~(-1u << RangeLSB);
1227330f729Sjoerg }
1237330f729Sjoerg }
1247330f729Sjoerg }
1257330f729Sjoerg
1267330f729Sjoerg /// Emit unwind opcodes to copy address from source register to $sp.
EmitSetSP(uint16_t Reg)1277330f729Sjoerg void UnwindOpcodeAssembler::EmitSetSP(uint16_t Reg) {
1287330f729Sjoerg EmitInt8(ARM::EHABI::UNWIND_OPCODE_SET_VSP | Reg);
1297330f729Sjoerg }
1307330f729Sjoerg
1317330f729Sjoerg /// Emit unwind opcodes to add $sp with an offset.
EmitSPOffset(int64_t Offset)1327330f729Sjoerg void UnwindOpcodeAssembler::EmitSPOffset(int64_t Offset) {
1337330f729Sjoerg if (Offset > 0x200) {
1347330f729Sjoerg uint8_t Buff[16];
1357330f729Sjoerg Buff[0] = ARM::EHABI::UNWIND_OPCODE_INC_VSP_ULEB128;
1367330f729Sjoerg size_t ULEBSize = encodeULEB128((Offset - 0x204) >> 2, Buff + 1);
137*82d56013Sjoerg emitBytes(Buff, ULEBSize + 1);
1387330f729Sjoerg } else if (Offset > 0) {
1397330f729Sjoerg if (Offset > 0x100) {
1407330f729Sjoerg EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP | 0x3fu);
1417330f729Sjoerg Offset -= 0x100;
1427330f729Sjoerg }
1437330f729Sjoerg EmitInt8(ARM::EHABI::UNWIND_OPCODE_INC_VSP |
1447330f729Sjoerg static_cast<uint8_t>((Offset - 4) >> 2));
1457330f729Sjoerg } else if (Offset < 0) {
1467330f729Sjoerg while (Offset < -0x100) {
1477330f729Sjoerg EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP | 0x3fu);
1487330f729Sjoerg Offset += 0x100;
1497330f729Sjoerg }
1507330f729Sjoerg EmitInt8(ARM::EHABI::UNWIND_OPCODE_DEC_VSP |
1517330f729Sjoerg static_cast<uint8_t>(((-Offset) - 4) >> 2));
1527330f729Sjoerg }
1537330f729Sjoerg }
1547330f729Sjoerg
Finalize(unsigned & PersonalityIndex,SmallVectorImpl<uint8_t> & Result)1557330f729Sjoerg void UnwindOpcodeAssembler::Finalize(unsigned &PersonalityIndex,
1567330f729Sjoerg SmallVectorImpl<uint8_t> &Result) {
1577330f729Sjoerg UnwindOpcodeStreamer OpStreamer(Result);
1587330f729Sjoerg
1597330f729Sjoerg if (HasPersonality) {
1607330f729Sjoerg // User-specifed personality routine: [ SIZE , OP1 , OP2 , ... ]
1617330f729Sjoerg PersonalityIndex = ARM::EHABI::NUM_PERSONALITY_INDEX;
1627330f729Sjoerg size_t TotalSize = Ops.size() + 1;
1637330f729Sjoerg size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
1647330f729Sjoerg Result.resize(RoundUpSize);
1657330f729Sjoerg OpStreamer.EmitSize(RoundUpSize);
1667330f729Sjoerg } else {
1677330f729Sjoerg // If no personalityindex is specified, select ane
1687330f729Sjoerg if (PersonalityIndex == ARM::EHABI::NUM_PERSONALITY_INDEX)
1697330f729Sjoerg PersonalityIndex = (Ops.size() <= 3) ? ARM::EHABI::AEABI_UNWIND_CPP_PR0
1707330f729Sjoerg : ARM::EHABI::AEABI_UNWIND_CPP_PR1;
1717330f729Sjoerg if (PersonalityIndex == ARM::EHABI::AEABI_UNWIND_CPP_PR0) {
1727330f729Sjoerg // __aeabi_unwind_cpp_pr0: [ 0x80 , OP1 , OP2 , OP3 ]
1737330f729Sjoerg assert(Ops.size() <= 3 && "too many opcodes for __aeabi_unwind_cpp_pr0");
1747330f729Sjoerg Result.resize(4);
1757330f729Sjoerg OpStreamer.EmitPersonalityIndex(PersonalityIndex);
1767330f729Sjoerg } else {
1777330f729Sjoerg // __aeabi_unwind_cpp_pr{1,2}: [ {0x81,0x82} , SIZE , OP1 , OP2 , ... ]
1787330f729Sjoerg size_t TotalSize = Ops.size() + 2;
1797330f729Sjoerg size_t RoundUpSize = (TotalSize + 3) / 4 * 4;
1807330f729Sjoerg Result.resize(RoundUpSize);
1817330f729Sjoerg OpStreamer.EmitPersonalityIndex(PersonalityIndex);
1827330f729Sjoerg OpStreamer.EmitSize(RoundUpSize);
1837330f729Sjoerg }
1847330f729Sjoerg }
1857330f729Sjoerg
1867330f729Sjoerg // Copy the unwind opcodes
1877330f729Sjoerg for (size_t i = OpBegins.size() - 1; i > 0; --i)
1887330f729Sjoerg for (size_t j = OpBegins[i - 1], end = OpBegins[i]; j < end; ++j)
1897330f729Sjoerg OpStreamer.EmitByte(Ops[j]);
1907330f729Sjoerg
1917330f729Sjoerg // Emit the padding finish opcodes if the size is not multiple of 4.
1927330f729Sjoerg OpStreamer.FillFinishOpcode();
1937330f729Sjoerg
1947330f729Sjoerg // Reset the assembler state
1957330f729Sjoerg Reset();
1967330f729Sjoerg }
197