| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- #include "PrologEncoderMD.h"
- #ifdef _WIN32
- // ----------------------------------------------------------------------------
- // _WIN32 x64 unwind uses PDATA
- // ----------------------------------------------------------------------------
- void PrologEncoder::RecordNonVolRegSave()
- {
- requiredUnwindCodeNodeCount++;
- }
- void PrologEncoder::RecordXmmRegSave()
- {
- requiredUnwindCodeNodeCount += 2;
- }
- void PrologEncoder::RecordAlloca(size_t size)
- {
- Assert(size);
- requiredUnwindCodeNodeCount += PrologEncoderMD::GetRequiredNodeCountForAlloca(size);
- }
- DWORD PrologEncoder::SizeOfPData()
- {
- return sizeof(PData) + (sizeof(UNWIND_CODE) * requiredUnwindCodeNodeCount);
- }
- void PrologEncoder::EncodeSmallProlog(uint8 prologSize, size_t allocaSize)
- {
- Assert(allocaSize <= 128);
- Assert(requiredUnwindCodeNodeCount == 0);
- // Increment requiredUnwindCodeNodeCount to ensure we do the Alloc for the correct size
- currentUnwindCodeNodeIndex = ++requiredUnwindCodeNodeCount;
- currentInstrOffset = prologSize;
- UnwindCode* unwindCode = GetUnwindCode(1);
- size_t slots = (allocaSize - MachPtr) / MachPtr;
- uint8 unwindCodeOpInfo = TO_UNIBBLE(slots);
- unwindCode->SetOffset(prologSize);
- unwindCode->SetOp(TO_UNIBBLE(UWOP_ALLOC_SMALL));
- unwindCode->SetOpInfo(unwindCodeOpInfo);
- }
- void PrologEncoder::EncodeInstr(IR::Instr *instr, unsigned __int8 size)
- {
- Assert(instr);
- Assert(size);
- UnwindCode *unwindCode = nullptr;
- unsigned __int8 unwindCodeOp = PrologEncoderMD::GetOp(instr);
- unsigned __int8 unwindCodeOpInfo = 0;
- unsigned __int16 uint16Val = 0;
- unsigned __int32 uint32Val = 0;
- if (!currentInstrOffset)
- currentUnwindCodeNodeIndex = requiredUnwindCodeNodeCount;
- Assert((currentInstrOffset + size) > currentInstrOffset);
- currentInstrOffset += size;
- switch (unwindCodeOp)
- {
- case UWOP_PUSH_NONVOL:
- {
- unwindCode = GetUnwindCode(1);
- unwindCodeOpInfo = PrologEncoderMD::GetNonVolRegToSave(instr);
- break;
- }
- case UWOP_SAVE_XMM128:
- {
- unwindCode = GetUnwindCode(2);
- unwindCodeOpInfo = PrologEncoderMD::GetXmmRegToSave(instr, &uint16Val);
- *((unsigned __int16 *)&((UNWIND_CODE *)unwindCode)[1]) = uint16Val;
- break;
- }
- case UWOP_ALLOC_SMALL:
- {
- unwindCode = GetUnwindCode(1);
- size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
- Assert((allocaSize - MachPtr) % MachPtr == 0);
- size_t slots = (allocaSize - MachPtr) / MachPtr;
- Assert(IS_UNIBBLE(slots));
- unwindCodeOpInfo = TO_UNIBBLE(slots);
- break;
- }
- case UWOP_ALLOC_LARGE:
- {
- size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
- Assert(allocaSize > 0x80);
- Assert(allocaSize % 8 == 0);
- Assert(IS_UNIBBLE(unwindCodeOp));
- size_t slots = allocaSize / MachPtr;
- if (allocaSize > 0x7FF8)
- {
- unwindCode = GetUnwindCode(3);
- uint32Val = TO_UINT32(allocaSize);
- unwindCodeOpInfo = 1;
- unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
- *((unsigned __int32 *)&((UNWIND_CODE *)unwindCode)[1]) = uint32Val;
- }
- else
- {
- unwindCode = GetUnwindCode(2);
- uint16Val = TO_UINT16(slots);
- unwindCodeOpInfo = 0;
- unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
- *((unsigned __int16 *)&((UNWIND_CODE *)unwindCode)[1]) = uint16Val;
- }
- break;
- }
- case UWOP_IGNORE:
- {
- return;
- }
- default:
- {
- AssertMsg(false, "PrologEncoderMD returned unsupported UnwindCodeOp.");
- }
- }
- Assert(unwindCode);
- unwindCode->SetOffset(currentInstrOffset);
- Assert(IS_UNIBBLE(unwindCodeOp));
- unwindCode->SetOp(TO_UNIBBLE(unwindCodeOp));
- Assert(IS_UNIBBLE(unwindCodeOpInfo));
- unwindCode->SetOpInfo(TO_UNIBBLE(unwindCodeOpInfo));
- }
- BYTE *PrologEncoder::Finalize(BYTE *functionStart,
- DWORD codeSize,
- BYTE *pdataBuffer)
- {
- Assert(pdataBuffer > functionStart);
- Assert((size_t)pdataBuffer % sizeof(DWORD) == 0);
- pdata.runtimeFunction.BeginAddress = 0;
- pdata.runtimeFunction.EndAddress = codeSize;
- pdata.runtimeFunction.UnwindData = (DWORD)((pdataBuffer + sizeof(RUNTIME_FUNCTION)) - functionStart);
- FinalizeUnwindInfo(functionStart, codeSize);
- return (BYTE *)&pdata.runtimeFunction;
- }
- void PrologEncoder::FinalizeUnwindInfo(BYTE *functionStart, DWORD codeSize)
- {
- pdata.unwindInfo.Version = 1;
- pdata.unwindInfo.Flags = 0;
- pdata.unwindInfo.SizeOfProlog = currentInstrOffset;
- pdata.unwindInfo.CountOfCodes = requiredUnwindCodeNodeCount;
- // We don't use the frame pointer in the standard way, and since we don't do dynamic stack allocation, we don't change the
- // stack pointer except during calls. From the perspective of the unwind info, it needs to restore information relative to
- // the stack pointer, so don't register the frame pointer.
- pdata.unwindInfo.FrameRegister = 0;
- pdata.unwindInfo.FrameOffset = 0;
- AssertMsg(requiredUnwindCodeNodeCount <= MaxRequiredUnwindCodeNodeCount, "We allocate 72 bytes for xdata - 34 (UnwindCodes) * 2 + 4 (UnwindInfo)");
- }
- PrologEncoder::UnwindCode *PrologEncoder::GetUnwindCode(unsigned __int8 nodeCount)
- {
- Assert(nodeCount && ((currentUnwindCodeNodeIndex - nodeCount) >= 0));
- currentUnwindCodeNodeIndex -= nodeCount;
- return static_cast<UnwindCode *>(&pdata.unwindInfo.unwindCodes[currentUnwindCodeNodeIndex]);
- }
- DWORD PrologEncoder::SizeOfUnwindInfo()
- {
- return (sizeof(UNWIND_INFO) + (sizeof(UNWIND_CODE) * requiredUnwindCodeNodeCount));
- }
- BYTE *PrologEncoder::GetUnwindInfo()
- {
- return (BYTE *)&pdata.unwindInfo;
- }
- #else // !_WIN32
- // ----------------------------------------------------------------------------
- // !_WIN32 x64 unwind uses .eh_frame
- // ----------------------------------------------------------------------------
- void PrologEncoder::EncodeSmallProlog(uint8 prologSize, size_t size)
- {
- auto fde = ehFrame.GetFDE();
- // prolog: push rbp
- fde->cfi_advance_loc(1); // DW_CFA_advance_loc: 1
- fde->cfi_def_cfa_offset(MachPtr * 2); // DW_CFA_def_cfa_offset: 16
- fde->cfi_offset(GetDwarfRegNum(LowererMDArch::GetRegFramePointer()), 2); // DW_CFA_offset: r6 (rbp) at cfa-16
- ehFrame.End();
- }
- DWORD PrologEncoder::SizeOfPData()
- {
- return ehFrame.Count();
- }
- BYTE* PrologEncoder::Finalize(BYTE *functionStart, DWORD codeSize, BYTE *pdataBuffer)
- {
- auto fde = ehFrame.GetFDE();
- fde->UpdateAddressRange(functionStart, codeSize);
- return ehFrame.Buffer();
- }
- void PrologEncoder::Begin(size_t prologStartOffset)
- {
- Assert(currentInstrOffset == 0);
- currentInstrOffset = prologStartOffset;
- }
- void PrologEncoder::End()
- {
- ehFrame.End();
- }
- void PrologEncoder::FinalizeUnwindInfo(BYTE *functionStart, DWORD codeSize)
- {
- auto fde = ehFrame.GetFDE();
- fde->UpdateAddressRange(functionStart, codeSize);
- }
- void PrologEncoder::EncodeInstr(IR::Instr *instr, unsigned __int8 size)
- {
- auto fde = ehFrame.GetFDE();
- uint8 unwindCodeOp = PrologEncoderMD::GetOp(instr);
- Assert((currentInstrOffset + size) > currentInstrOffset);
- currentInstrOffset += size;
- switch (unwindCodeOp)
- {
- case UWOP_PUSH_NONVOL:
- {
- const uword advance = currentInstrOffset - cfiInstrOffset;
- cfiInstrOffset = currentInstrOffset;
- cfaWordOffset++;
- fde->cfi_advance(advance); // DW_CFA_advance_loc: ?
- fde->cfi_def_cfa_offset(cfaWordOffset * MachPtr); // DW_CFA_def_cfa_offset: ??
- const ubyte reg = PrologEncoderMD::GetNonVolRegToSave(instr) + 1;
- fde->cfi_offset(GetDwarfRegNum(reg), cfaWordOffset); // DW_CFA_offset: r? at cfa-??
- break;
- }
- case UWOP_SAVE_XMM128:
- {
- // TODO
- break;
- }
- case UWOP_ALLOC_SMALL:
- case UWOP_ALLOC_LARGE:
- {
- size_t allocaSize = PrologEncoderMD::GetAllocaSize(instr);
- Assert(allocaSize % MachPtr == 0);
- size_t slots = allocaSize / MachPtr;
- Assert(cfaWordOffset + slots > cfaWordOffset);
- const uword advance = currentInstrOffset - cfiInstrOffset;
- cfiInstrOffset = currentInstrOffset;
- cfaWordOffset += slots;
- fde->cfi_advance(advance); // DW_CFA_advance_loc: ?
- fde->cfi_def_cfa_offset(cfaWordOffset * MachPtr); // DW_CFA_def_cfa_offset: ??
- break;
- }
- case UWOP_IGNORE:
- {
- return;
- }
- default:
- {
- AssertMsg(false, "PrologEncoderMD returned unsupported UnwindCodeOp.");
- }
- }
- }
- #endif // !_WIN32
|