1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 #include "perfcounters.h"
17 #include "stublink.inl"
19 #include "rtlfunctions.h"
21 #define S_BYTEPTR(x) S_SIZE_T((SIZE_T)(x))
23 #ifndef DACCESS_COMPILE
26 //************************************************************************
29 // There are two types of CodeElements: CodeRuns (a stream of uninterpreted
30 // code bytes) and LabelRefs (an instruction containing
32 //************************************************************************
35 enum CodeElementType {
41 CodeElementType m_type; // kCodeRun or kLabelRef
42 CodeElement *m_next; // ptr to next CodeElement
44 // Used as workspace during Link(): holds the offset relative to
45 // the start of the final stub.
51 //************************************************************************
52 // CodeRun: A run of uninterrupted code bytes.
53 //************************************************************************
58 #define CODERUNSIZE 32
61 struct CodeRun : public CodeElement
63 UINT m_numcodebytes; // how many bytes are actually used
64 BYTE m_codebytes[CODERUNSIZE];
67 //************************************************************************
68 // LabelRef: An instruction containing an embedded label reference
69 //************************************************************************
70 struct LabelRef : public CodeElement
72 // provides platform-specific information about the instruction
73 InstructionFormat *m_pInstructionFormat;
75 // a variation code (interpretation is specific to the InstructionFormat)
76 // typically used to customize an instruction (e.g. with a condition
83 // Workspace during the link phase
87 // Pointer to next LabelRef
88 LabelRef *m_nextLabelRef;
92 //************************************************************************
93 // IntermediateUnwindInfo
94 //************************************************************************
96 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
100 // List of unwind operations, queued in StubLinker::m_pUnwindInfoList.
101 struct IntermediateUnwindInfo
103 IntermediateUnwindInfo *pNext;
106 UNWIND_CODE rgUnwindCode[1]; // variable length, depends on first entry's UnwindOp
108 #endif // _TARGET_AMD64_
111 StubUnwindInfoHeapSegment *g_StubHeapSegments;
112 CrstStatic g_StubUnwindInfoHeapSegmentsCrst;
113 #ifdef _DEBUG // for unit test
114 void *__DEBUG__g_StubHeapSegments = &g_StubHeapSegments;
119 // Callback registered via RtlInstallFunctionTableCallback. Called by
120 // RtlpLookupDynamicFunctionEntry to locate RUNTIME_FUNCTION entry for a PC
121 // found within a portion of a heap that contains stub code.
124 FindStubFunctionEntry (
125 WIN64_ONLY(IN ULONG64 ControlPc)
126 NOT_WIN64(IN ULONG ControlPc),
139 CONSISTENCY_CHECK(DYNFNTABLE_STUB == IdentifyDynamicFunctionTableTypeFromContext(Context));
141 StubUnwindInfoHeapSegment *pStubHeapSegment = (StubUnwindInfoHeapSegment*)DecodeDynamicFunctionTableContext(Context);
144 // The RUNTIME_FUNCTION entry contains ULONG offsets relative to the
145 // segment base. Stub::EmitUnwindInfo ensures that this cast is valid.
147 ULONG RelativeAddress = (ULONG)((BYTE*)ControlPc - pStubHeapSegment->pbBaseAddress);
149 LOG((LF_STUBS, LL_INFO100000, "ControlPc %p, RelativeAddress 0x%x, pStubHeapSegment %p, pStubHeapSegment->pbBaseAddress %p\n",
153 pStubHeapSegment->pbBaseAddress));
156 // Search this segment's list of stubs for an entry that includes the
157 // segment-relative offset.
159 for (StubUnwindInfoHeader *pHeader = pStubHeapSegment->pUnwindHeaderList;
161 pHeader = pHeader->pNext)
163 // The entry points are in increasing address order.
164 if (RelativeAddress >= RUNTIME_FUNCTION__BeginAddress(&pHeader->FunctionEntry))
166 T_RUNTIME_FUNCTION *pCurFunction = &pHeader->FunctionEntry;
167 T_RUNTIME_FUNCTION *pPrevFunction = NULL;
169 LOG((LF_STUBS, LL_INFO100000, "pCurFunction %p, pCurFunction->BeginAddress 0x%x, pCurFunction->EndAddress 0x%x\n",
171 RUNTIME_FUNCTION__BeginAddress(pCurFunction),
172 RUNTIME_FUNCTION__EndAddress(pCurFunction, (TADDR)pStubHeapSegment->pbBaseAddress)));
174 CONSISTENCY_CHECK((RUNTIME_FUNCTION__EndAddress(pCurFunction, (TADDR)pStubHeapSegment->pbBaseAddress) > RUNTIME_FUNCTION__BeginAddress(pCurFunction)));
175 CONSISTENCY_CHECK((!pPrevFunction || RUNTIME_FUNCTION__EndAddress(pPrevFunction, (TADDR)pStubHeapSegment->pbBaseAddress) <= RUNTIME_FUNCTION__BeginAddress(pCurFunction)));
177 // The entry points are in increasing address order. They're
178 // also contiguous, so after we're sure it's after the start of
179 // the first function (checked above), we only need to test
181 if (RelativeAddress < RUNTIME_FUNCTION__EndAddress(pCurFunction, (TADDR)pStubHeapSegment->pbBaseAddress))
183 CONSISTENCY_CHECK((RelativeAddress >= RUNTIME_FUNCTION__BeginAddress(pCurFunction)));
191 // Return NULL to indicate that there is no RUNTIME_FUNCTION/unwind
192 // information for this offset.
198 bool UnregisterUnwindInfoInLoaderHeapCallback (PVOID pvArgs, PVOID pvAllocationBase, SIZE_T cbReserved)
208 // There may be multiple StubUnwindInfoHeapSegment's associated with a region.
211 LOG((LF_STUBS, LL_INFO1000, "Looking for stub unwind info for LoaderHeap segment %p size %p\n", pvAllocationBase, cbReserved));
213 CrstHolder crst(&g_StubUnwindInfoHeapSegmentsCrst);
215 StubUnwindInfoHeapSegment *pStubHeapSegment;
216 for (StubUnwindInfoHeapSegment **ppPrevStubHeapSegment = &g_StubHeapSegments;
217 (pStubHeapSegment = *ppPrevStubHeapSegment); )
219 LOG((LF_STUBS, LL_INFO10000, " have unwind info for address %p size %p\n", pStubHeapSegment->pbBaseAddress, pStubHeapSegment->cbSegment));
221 // If heap region ends before stub segment
222 if ((BYTE*)pvAllocationBase + cbReserved <= pStubHeapSegment->pbBaseAddress)
224 // The list is ordered, so address range is between segments
228 // The given heap segment base address may fall within a prereserved
229 // region that was given to the heap when the heap was constructed, so
230 // pvAllocationBase may be > pbBaseAddress. Also, there could be
231 // multiple segments for each heap region, so pvAllocationBase may be
232 // < pbBaseAddress. So...there is no meaningful relationship between
233 // pvAllocationBase and pbBaseAddress.
235 // If heap region starts before end of stub segment
236 if ((BYTE*)pvAllocationBase < pStubHeapSegment->pbBaseAddress + pStubHeapSegment->cbSegment)
238 _ASSERTE((BYTE*)pvAllocationBase + cbReserved <= pStubHeapSegment->pbBaseAddress + pStubHeapSegment->cbSegment);
240 DeleteEEFunctionTable(pStubHeapSegment);
241 #ifdef _TARGET_AMD64_
242 if (pStubHeapSegment->pUnwindInfoTable != 0)
243 delete pStubHeapSegment->pUnwindInfoTable;
245 *ppPrevStubHeapSegment = pStubHeapSegment->pNext;
247 delete pStubHeapSegment;
251 ppPrevStubHeapSegment = &pStubHeapSegment->pNext;
255 return false; // Keep enumerating
259 VOID UnregisterUnwindInfoInLoaderHeap (UnlockedLoaderHeap *pHeap)
265 PRECONDITION(pHeap->m_fPermitStubsWithUnwindInfo);
269 pHeap->EnumPageRegions(&UnregisterUnwindInfoInLoaderHeapCallback, NULL /* pvArgs */);
272 pHeap->m_fStubUnwindInfoUnregistered = TRUE;
277 class StubUnwindInfoSegmentBoundaryReservationList
279 struct ReservationList
281 ReservationList *pNext;
283 static ReservationList *FromStub (Stub *pStub)
285 return (ReservationList*)(pStub+1);
290 return (Stub*)this - 1;
294 ReservationList *m_pList;
298 StubUnwindInfoSegmentBoundaryReservationList ()
300 LIMITED_METHOD_CONTRACT;
305 ~StubUnwindInfoSegmentBoundaryReservationList ()
307 LIMITED_METHOD_CONTRACT;
309 ReservationList *pList = m_pList;
312 ReservationList *pNext = pList->pNext;
314 pList->GetStub()->DecRef();
320 void AddStub (Stub *pStub)
322 LIMITED_METHOD_CONTRACT;
324 ReservationList *pList = ReservationList::FromStub(pStub);
326 pList->pNext = m_pList;
332 #endif // STUBLINKER_GENERATES_UNWIND_INFO
335 //************************************************************************
337 //************************************************************************
339 //---------------------------------------------------------------
341 //---------------------------------------------------------------
342 StubLinker::StubLinker()
352 m_pCodeElements = NULL;
353 m_pFirstCodeLabel = NULL;
354 m_pFirstLabelRef = NULL;
355 m_pPatchLabel = NULL;
360 m_cCalleeSavedRegs = 0;
362 m_fPushArgRegs = FALSE;
364 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
366 m_pUnwindInfoCheckLabel = NULL;
368 #ifdef _TARGET_AMD64_
369 m_pUnwindInfoList = NULL;
371 m_fHaveFramePointer = FALSE;
373 #ifdef _TARGET_ARM64_
377 m_cCalleeSavedRegs = 0;
380 #endif // STUBLINKER_GENERATES_UNWIND_INFO
385 //---------------------------------------------------------------
386 // Append code bytes.
387 //---------------------------------------------------------------
388 VOID StubLinker::EmitBytes(const BYTE *pBytes, UINT numBytes)
398 CodeElement *pLastCodeElement = GetLastCodeElement();
399 while (numBytes != 0) {
401 if (pLastCodeElement != NULL &&
402 pLastCodeElement->m_type == CodeElement::kCodeRun) {
403 CodeRun *pCodeRun = (CodeRun*)pLastCodeElement;
404 UINT numbytessrc = numBytes;
405 UINT numbytesdst = CODERUNSIZE - pCodeRun->m_numcodebytes;
406 if (numbytesdst <= numbytessrc) {
407 CopyMemory(&(pCodeRun->m_codebytes[pCodeRun->m_numcodebytes]),
410 pCodeRun->m_numcodebytes = CODERUNSIZE;
411 pLastCodeElement = NULL;
412 pBytes += numbytesdst;
413 numBytes -= numbytesdst;
415 CopyMemory(&(pCodeRun->m_codebytes[pCodeRun->m_numcodebytes]),
418 pCodeRun->m_numcodebytes += numbytessrc;
419 pBytes += numbytessrc;
424 pLastCodeElement = AppendNewEmptyCodeRun();
430 //---------------------------------------------------------------
431 // Append code bytes.
432 //---------------------------------------------------------------
433 VOID StubLinker::Emit8 (unsigned __int8 val)
442 CodeRun *pCodeRun = GetLastCodeRunIfAny();
443 if (pCodeRun && (CODERUNSIZE - pCodeRun->m_numcodebytes) >= sizeof(val)) {
444 *((unsigned __int8 *)(pCodeRun->m_codebytes + pCodeRun->m_numcodebytes)) = val;
445 pCodeRun->m_numcodebytes += sizeof(val);
447 EmitBytes((BYTE*)&val, sizeof(val));
451 //---------------------------------------------------------------
452 // Append code bytes.
453 //---------------------------------------------------------------
454 VOID StubLinker::Emit16(unsigned __int16 val)
464 CodeRun *pCodeRun = GetLastCodeRunIfAny();
465 if (pCodeRun && (CODERUNSIZE - pCodeRun->m_numcodebytes) >= sizeof(val)) {
466 SET_UNALIGNED_16(pCodeRun->m_codebytes + pCodeRun->m_numcodebytes, val);
467 pCodeRun->m_numcodebytes += sizeof(val);
469 EmitBytes((BYTE*)&val, sizeof(val));
473 //---------------------------------------------------------------
474 // Append code bytes.
475 //---------------------------------------------------------------
476 VOID StubLinker::Emit32(unsigned __int32 val)
486 CodeRun *pCodeRun = GetLastCodeRunIfAny();
487 if (pCodeRun && (CODERUNSIZE - pCodeRun->m_numcodebytes) >= sizeof(val)) {
488 SET_UNALIGNED_32(pCodeRun->m_codebytes + pCodeRun->m_numcodebytes, val);
489 pCodeRun->m_numcodebytes += sizeof(val);
491 EmitBytes((BYTE*)&val, sizeof(val));
495 //---------------------------------------------------------------
496 // Append code bytes.
497 //---------------------------------------------------------------
498 VOID StubLinker::Emit64(unsigned __int64 val)
507 CodeRun *pCodeRun = GetLastCodeRunIfAny();
508 if (pCodeRun && (CODERUNSIZE - pCodeRun->m_numcodebytes) >= sizeof(val)) {
509 SET_UNALIGNED_64(pCodeRun->m_codebytes + pCodeRun->m_numcodebytes, val);
510 pCodeRun->m_numcodebytes += sizeof(val);
512 EmitBytes((BYTE*)&val, sizeof(val));
516 //---------------------------------------------------------------
517 // Append pointer value.
518 //---------------------------------------------------------------
519 VOID StubLinker::EmitPtr(const VOID *val)
529 CodeRun *pCodeRun = GetLastCodeRunIfAny();
530 if (pCodeRun && (CODERUNSIZE - pCodeRun->m_numcodebytes) >= sizeof(val)) {
531 SET_UNALIGNED_PTR(pCodeRun->m_codebytes + pCodeRun->m_numcodebytes, (UINT_PTR)val);
532 pCodeRun->m_numcodebytes += sizeof(val);
534 EmitBytes((BYTE*)&val, sizeof(val));
539 //---------------------------------------------------------------
540 // Create a new undefined label. Label must be assigned to a code
541 // location using EmitLabel() prior to final linking.
542 // Throws COM+ exception on failure.
543 //---------------------------------------------------------------
544 CodeLabel* StubLinker::NewCodeLabel()
554 CodeLabel *pCodeLabel = (CodeLabel*)(m_quickHeap.Alloc(sizeof(CodeLabel)));
555 _ASSERTE(pCodeLabel); // QuickHeap throws exceptions rather than returning NULL
556 pCodeLabel->m_next = m_pFirstCodeLabel;
557 pCodeLabel->m_fExternal = FALSE;
558 pCodeLabel->m_fAbsolute = FALSE;
559 pCodeLabel->i.m_pCodeRun = NULL;
560 m_pFirstCodeLabel = pCodeLabel;
566 CodeLabel* StubLinker::NewAbsoluteCodeLabel()
575 CodeLabel *pCodeLabel = NewCodeLabel();
576 pCodeLabel->m_fAbsolute = TRUE;
581 //---------------------------------------------------------------
582 // Sets the label to point to the current "instruction pointer".
583 // It is invalid to call EmitLabel() twice on
585 //---------------------------------------------------------------
586 VOID StubLinker::EmitLabel(CodeLabel* pCodeLabel)
596 _ASSERTE(!(pCodeLabel->m_fExternal)); //can't emit an external label
597 _ASSERTE(pCodeLabel->i.m_pCodeRun == NULL); //must only emit label once
598 CodeRun *pLastCodeRun = GetLastCodeRunIfAny();
600 pLastCodeRun = AppendNewEmptyCodeRun();
602 pCodeLabel->i.m_pCodeRun = pLastCodeRun;
603 pCodeLabel->i.m_localOffset = pLastCodeRun->m_numcodebytes;
607 //---------------------------------------------------------------
608 // Combines NewCodeLabel() and EmitLabel() for convenience.
609 // Throws COM+ exception on failure.
610 //---------------------------------------------------------------
611 CodeLabel* StubLinker::EmitNewCodeLabel()
621 CodeLabel* label = NewCodeLabel();
627 //---------------------------------------------------------------
628 // Creates & emits the patch offset label for the stub
629 //---------------------------------------------------------------
630 VOID StubLinker::EmitPatchLabel()
641 // Note that it's OK to have re-emit the patch label,
642 // just use the later one.
645 m_pPatchLabel = EmitNewCodeLabel();
648 //---------------------------------------------------------------
649 // Returns final location of label as an offset from the start
650 // of the stub. Can only be called after linkage.
651 //---------------------------------------------------------------
652 UINT32 StubLinker::GetLabelOffset(CodeLabel *pLabel)
662 _ASSERTE(!(pLabel->m_fExternal));
663 return pLabel->i.m_localOffset + pLabel->i.m_pCodeRun->m_globaloffset;
667 //---------------------------------------------------------------
668 // Create a new label to an external address.
669 // Throws COM+ exception on failure.
670 //---------------------------------------------------------------
671 CodeLabel* StubLinker::NewExternalCodeLabel(LPVOID pExternalAddress)
679 PRECONDITION(CheckPointer(pExternalAddress));
683 CodeLabel *pCodeLabel = (CodeLabel*)(m_quickHeap.Alloc(sizeof(CodeLabel)));
684 _ASSERTE(pCodeLabel); // QuickHeap throws exceptions rather than returning NULL
685 pCodeLabel->m_next = m_pFirstCodeLabel;
686 pCodeLabel->m_fExternal = TRUE;
687 pCodeLabel->m_fAbsolute = FALSE;
688 pCodeLabel->e.m_pExternalAddress = pExternalAddress;
689 m_pFirstCodeLabel = pCodeLabel;
696 //---------------------------------------------------------------
697 // Append an instruction containing a reference to a label.
699 // target - the label being referenced.
700 // instructionFormat - a platform-specific InstructionFormat object
701 // that gives properties about the reference.
702 // variationCode - uninterpreted data passed to the pInstructionFormat methods.
703 //---------------------------------------------------------------
704 VOID StubLinker::EmitLabelRef(CodeLabel* target, const InstructionFormat & instructionFormat, UINT variationCode)
714 LabelRef *pLabelRef = (LabelRef *)(m_quickHeap.Alloc(sizeof(LabelRef)));
715 _ASSERTE(pLabelRef); // m_quickHeap throws an exception rather than returning NULL
716 pLabelRef->m_type = LabelRef::kLabelRef;
717 pLabelRef->m_pInstructionFormat = (InstructionFormat*)&instructionFormat;
718 pLabelRef->m_variationCode = variationCode;
719 pLabelRef->m_target = target;
721 pLabelRef->m_nextLabelRef = m_pFirstLabelRef;
722 m_pFirstLabelRef = pLabelRef;
724 AppendCodeElement(pLabelRef);
733 //---------------------------------------------------------------
734 // Internal helper routine.
735 //---------------------------------------------------------------
736 CodeRun *StubLinker::GetLastCodeRunIfAny()
746 CodeElement *pLastCodeElem = GetLastCodeElement();
747 if (pLastCodeElem == NULL || pLastCodeElem->m_type != CodeElement::kCodeRun) {
750 return (CodeRun*)pLastCodeElem;
755 //---------------------------------------------------------------
756 // Internal helper routine.
757 //---------------------------------------------------------------
758 CodeRun *StubLinker::AppendNewEmptyCodeRun()
767 CodeRun *pNewCodeRun = (CodeRun*)(m_quickHeap.Alloc(sizeof(CodeRun)));
768 _ASSERTE(pNewCodeRun); // QuickHeap throws exceptions rather than returning NULL
769 pNewCodeRun->m_type = CodeElement::kCodeRun;
770 pNewCodeRun->m_numcodebytes = 0;
771 AppendCodeElement(pNewCodeRun);
776 //---------------------------------------------------------------
777 // Internal helper routine.
778 //---------------------------------------------------------------
779 VOID StubLinker::AppendCodeElement(CodeElement *pCodeElement)
789 pCodeElement->m_next = m_pCodeElements;
790 m_pCodeElements = pCodeElement;
795 //---------------------------------------------------------------
796 // Is the current LabelRef's size big enough to reach the target?
797 //---------------------------------------------------------------
798 static BOOL LabelCanReach(LabelRef *pLabelRef)
808 InstructionFormat *pIF = pLabelRef->m_pInstructionFormat;
810 if (pLabelRef->m_target->m_fExternal)
812 return pLabelRef->m_pInstructionFormat->CanReach(
813 pLabelRef->m_refsize, pLabelRef->m_variationCode, TRUE, (INT_PTR)pLabelRef->m_target->e.m_pExternalAddress);
817 UINT targetglobaloffset = pLabelRef->m_target->i.m_pCodeRun->m_globaloffset +
818 pLabelRef->m_target->i.m_localOffset;
819 UINT srcglobaloffset = pLabelRef->m_globaloffset +
820 pIF->GetHotSpotOffset(pLabelRef->m_refsize,
821 pLabelRef->m_variationCode);
822 INT offset = (INT)(targetglobaloffset - srcglobaloffset);
824 return pLabelRef->m_pInstructionFormat->CanReach(
825 pLabelRef->m_refsize, pLabelRef->m_variationCode, FALSE, offset);
829 //---------------------------------------------------------------
830 // Generate the actual stub. The returned stub has a refcount of 1.
831 // No other methods (other than the destructor) should be called
832 // after calling Link().
834 // Throws COM+ exception on failure.
835 //---------------------------------------------------------------
836 Stub *StubLinker::LinkInterceptor(LoaderHeap *pHeap, Stub* interceptee, void *pRealAddr)
838 STANDARD_VM_CONTRACT;
841 int size = CalculateSize(&globalsize);
843 _ASSERTE(!pHeap || pHeap->IsExecutable());
845 StubHolder<Stub> pStub;
847 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
848 StubUnwindInfoSegmentBoundaryReservationList ReservedStubs;
853 pStub = InterceptStub::NewInterceptedStub(pHeap, size, interceptee,
855 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
856 , UnwindInfoSize(globalsize)
859 bool fSuccess; fSuccess = EmitStub(pStub, globalsize, pHeap);
861 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
868 ReservedStubs.AddStub(pStub);
869 pStub.SuppressRelease();
872 CONSISTENCY_CHECK_MSG(fSuccess, ("EmitStub should always return true"));
876 return pStub.Extract();
879 //---------------------------------------------------------------
880 // Generate the actual stub. The returned stub has a refcount of 1.
881 // No other methods (other than the destructor) should be called
882 // after calling Link().
884 // Throws COM+ exception on failure.
885 //---------------------------------------------------------------
886 Stub *StubLinker::Link(LoaderHeap *pHeap, DWORD flags)
888 STANDARD_VM_CONTRACT;
891 int size = CalculateSize(&globalsize);
893 #ifndef CROSSGEN_COMPILE
894 _ASSERTE(!pHeap || pHeap->IsExecutable());
897 StubHolder<Stub> pStub;
899 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
900 StubUnwindInfoSegmentBoundaryReservationList ReservedStubs;
905 pStub = Stub::NewStub(
909 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
910 , UnwindInfoSize(globalsize)
913 ASSERT(pStub != NULL);
915 bool fSuccess; fSuccess = EmitStub(pStub, globalsize, pHeap);
917 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
924 ReservedStubs.AddStub(pStub);
925 pStub.SuppressRelease();
928 CONSISTENCY_CHECK_MSG(fSuccess, ("EmitStub should always return true"));
932 return pStub.Extract();
935 int StubLinker::CalculateSize(int* pGlobalSize)
945 _ASSERTE(pGlobalSize);
947 #if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) && !defined(CROSSGEN_COMPILE)
948 if (m_pUnwindInfoCheckLabel)
950 EmitLabel(m_pUnwindInfoCheckLabel);
951 EmitUnwindInfoCheckSubfunction();
952 m_pUnwindInfoCheckLabel = NULL;
957 // Don't want any undefined labels
958 for (CodeLabel *pCodeLabel = m_pFirstCodeLabel;
960 pCodeLabel = pCodeLabel->m_next) {
961 if ((!(pCodeLabel->m_fExternal)) && pCodeLabel->i.m_pCodeRun == NULL) {
962 _ASSERTE(!"Forgot to define a label before asking StubLinker to link.");
967 //-------------------------------------------------------------------
968 // Tentatively set all of the labelref sizes to their smallest possible
970 //-------------------------------------------------------------------
971 for (LabelRef *pLabelRef = m_pFirstLabelRef;
973 pLabelRef = pLabelRef->m_nextLabelRef) {
975 for (UINT bitmask = 1; bitmask <= InstructionFormat::kMax; bitmask = bitmask << 1) {
976 if (pLabelRef->m_pInstructionFormat->m_allowedSizes & bitmask) {
977 pLabelRef->m_refsize = bitmask;
986 BOOL fSomethingChanged;
988 fSomethingChanged = FALSE;
991 // Layout each code element.
994 CodeElement *pCodeElem;
995 for (pCodeElem = m_pCodeElements; pCodeElem; pCodeElem = pCodeElem->m_next) {
997 switch (pCodeElem->m_type) {
998 case CodeElement::kCodeRun:
999 globalsize += ((CodeRun*)pCodeElem)->m_numcodebytes;
1002 case CodeElement::kLabelRef: {
1003 LabelRef *pLabelRef = (LabelRef*)pCodeElem;
1004 globalsize += pLabelRef->m_pInstructionFormat->GetSizeOfInstruction( pLabelRef->m_refsize,
1005 pLabelRef->m_variationCode );
1006 datasize += pLabelRef->m_pInstructionFormat->GetSizeOfData( pLabelRef->m_refsize,
1007 pLabelRef->m_variationCode );
1015 // Record a temporary global offset; this is actually
1016 // wrong by a fixed value. We'll fix up after we know the
1017 // size of the entire stub.
1018 pCodeElem->m_globaloffset = 0 - globalsize;
1020 // also record the data offset. Note the link-list we walk is in
1021 // *reverse* order so we visit the last instruction first
1022 // so what we record now is in fact the offset from the *end* of
1023 // the data block. We fix it up later.
1024 pCodeElem->m_dataoffset = 0 - datasize;
1027 // Now fix up the global offsets.
1028 for (pCodeElem = m_pCodeElements; pCodeElem; pCodeElem = pCodeElem->m_next) {
1029 pCodeElem->m_globaloffset += globalsize;
1030 pCodeElem->m_dataoffset += datasize;
1034 // Now, iterate thru the LabelRef's and check if any of them
1035 // have to be resized.
1036 for (LabelRef *pLabelRef = m_pFirstLabelRef;
1038 pLabelRef = pLabelRef->m_nextLabelRef) {
1041 if (!LabelCanReach(pLabelRef)) {
1042 fSomethingChanged = TRUE;
1044 UINT bitmask = pLabelRef->m_refsize << 1;
1045 // Find the next largest size.
1046 // (we could be smarter about this and eliminate intermediate
1047 // sizes based on the tentative offset.)
1048 for (; bitmask <= InstructionFormat::kMax; bitmask = bitmask << 1) {
1049 if (pLabelRef->m_pInstructionFormat->m_allowedSizes & bitmask) {
1050 pLabelRef->m_refsize = bitmask;
1055 if (bitmask > InstructionFormat::kMax) {
1056 // CANNOT REACH target even with kMax
1057 _ASSERTE(!"Stub instruction cannot reach target: must choose a different instruction!");
1064 } while (fSomethingChanged); // Keep iterating until all LabelRef's can reach
1067 // We now have the correct layout write out the stub.
1069 // Compute stub code+data size after aligning data correctly
1070 if(globalsize % DATA_ALIGNMENT)
1071 globalsize += (DATA_ALIGNMENT - (globalsize % DATA_ALIGNMENT));
1073 *pGlobalSize = globalsize;
1074 return globalsize + datasize;
1077 bool StubLinker::EmitStub(Stub* pStub, int globalsize, LoaderHeap* pHeap)
1079 STANDARD_VM_CONTRACT;
1081 BYTE *pCode = (BYTE*)(pStub->GetBlob());
1082 BYTE *pData = pCode+globalsize; // start of data area
1084 int lastCodeOffset = 0;
1086 // Write out each code element.
1087 for (CodeElement* pCodeElem = m_pCodeElements; pCodeElem; pCodeElem = pCodeElem->m_next) {
1090 switch (pCodeElem->m_type) {
1091 case CodeElement::kCodeRun:
1092 CopyMemory(pCode + pCodeElem->m_globaloffset,
1093 ((CodeRun*)pCodeElem)->m_codebytes,
1094 ((CodeRun*)pCodeElem)->m_numcodebytes);
1095 currOffset = pCodeElem->m_globaloffset + ((CodeRun *)pCodeElem)->m_numcodebytes;
1098 case CodeElement::kLabelRef: {
1099 LabelRef *pLabelRef = (LabelRef*)pCodeElem;
1100 InstructionFormat *pIF = pLabelRef->m_pInstructionFormat;
1103 LPBYTE srcglobaladdr = pCode +
1104 pLabelRef->m_globaloffset +
1105 pIF->GetHotSpotOffset(pLabelRef->m_refsize,
1106 pLabelRef->m_variationCode);
1107 LPBYTE targetglobaladdr;
1108 if (!(pLabelRef->m_target->m_fExternal)) {
1109 targetglobaladdr = pCode +
1110 pLabelRef->m_target->i.m_pCodeRun->m_globaloffset +
1111 pLabelRef->m_target->i.m_localOffset;
1113 targetglobaladdr = (LPBYTE)(pLabelRef->m_target->e.m_pExternalAddress);
1115 if ((pLabelRef->m_target->m_fAbsolute)) {
1116 fixupval = (__int64)(size_t)targetglobaladdr;
1118 fixupval = (__int64)(targetglobaladdr - srcglobaladdr);
1120 pLabelRef->m_pInstructionFormat->EmitInstruction(
1121 pLabelRef->m_refsize,
1123 pCode + pCodeElem->m_globaloffset,
1124 pLabelRef->m_variationCode,
1125 pData + pCodeElem->m_dataoffset);
1128 pCodeElem->m_globaloffset +
1129 pLabelRef->m_pInstructionFormat->GetSizeOfInstruction( pLabelRef->m_refsize,
1130 pLabelRef->m_variationCode );
1137 lastCodeOffset = (currOffset > lastCodeOffset) ? currOffset : lastCodeOffset;
1140 // Fill in zeros at the end, if necessary
1141 if (lastCodeOffset < globalsize)
1142 ZeroMemory(pCode + lastCodeOffset, globalsize - lastCodeOffset);
1145 // Fill in patch offset, if we have one
1146 // Note that these offsets are relative to the start of the stub,
1147 // not the code, so you'll have to add sizeof(Stub) to get to the
1149 if (m_pPatchLabel != NULL)
1151 UINT32 uLabelOffset = GetLabelOffset(m_pPatchLabel);
1152 _ASSERTE(FitsIn<USHORT>(uLabelOffset));
1153 pStub->SetPatchOffset(static_cast<USHORT>(uLabelOffset));
1155 LOG((LF_CORDB, LL_INFO100, "SL::ES: patch offset:0x%x\n",
1156 pStub->GetPatchOffset()));
1159 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
1160 if (pStub->HasUnwindInfo())
1162 if (!EmitUnwindInfo(pStub, globalsize, pHeap))
1165 #endif // STUBLINKER_GENERATES_UNWIND_INFO
1169 FlushInstructionCache(GetCurrentProcess(), pCode, globalsize);
1172 _ASSERTE(m_fDataOnly || DbgIsExecutable(pCode, globalsize));
1178 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
1179 #if defined(_TARGET_AMD64_)
1181 // See RtlVirtualUnwind in base\ntos\rtl\amd64\exdsptch.c
1183 static_assert_no_msg(kRAX == (FIELD_OFFSET(CONTEXT, Rax) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1184 static_assert_no_msg(kRCX == (FIELD_OFFSET(CONTEXT, Rcx) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1185 static_assert_no_msg(kRDX == (FIELD_OFFSET(CONTEXT, Rdx) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1186 static_assert_no_msg(kRBX == (FIELD_OFFSET(CONTEXT, Rbx) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1187 static_assert_no_msg(kRBP == (FIELD_OFFSET(CONTEXT, Rbp) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1188 static_assert_no_msg(kRSI == (FIELD_OFFSET(CONTEXT, Rsi) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1189 static_assert_no_msg(kRDI == (FIELD_OFFSET(CONTEXT, Rdi) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1190 static_assert_no_msg(kR8 == (FIELD_OFFSET(CONTEXT, R8 ) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1191 static_assert_no_msg(kR9 == (FIELD_OFFSET(CONTEXT, R9 ) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1192 static_assert_no_msg(kR10 == (FIELD_OFFSET(CONTEXT, R10) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1193 static_assert_no_msg(kR11 == (FIELD_OFFSET(CONTEXT, R11) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1194 static_assert_no_msg(kR12 == (FIELD_OFFSET(CONTEXT, R12) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1195 static_assert_no_msg(kR13 == (FIELD_OFFSET(CONTEXT, R13) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1196 static_assert_no_msg(kR14 == (FIELD_OFFSET(CONTEXT, R14) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1197 static_assert_no_msg(kR15 == (FIELD_OFFSET(CONTEXT, R15) - FIELD_OFFSET(CONTEXT, Rax)) / sizeof(ULONG64));
1199 VOID StubLinker::UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset)
1201 USHORT FrameOffset = (USHORT)(SPRelativeOffset / 8);
1203 if ((ULONG)FrameOffset == SPRelativeOffset)
1205 UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_SAVE_NONVOL);
1206 pUnwindCode->OpInfo = reg;
1207 pUnwindCode[1].FrameOffset = FrameOffset;
1211 UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_SAVE_NONVOL_FAR);
1212 pUnwindCode->OpInfo = reg;
1213 pUnwindCode[1].FrameOffset = (USHORT)SPRelativeOffset;
1214 pUnwindCode[2].FrameOffset = (USHORT)(SPRelativeOffset >> 16);
1218 VOID StubLinker::UnwindPushedReg (UCHAR reg)
1220 m_stackSize += sizeof(void*);
1222 if (m_fHaveFramePointer)
1225 UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_PUSH_NONVOL);
1226 pUnwindCode->OpInfo = reg;
1229 VOID StubLinker::UnwindAllocStack (SHORT FrameSizeIncrement)
1238 if (! ClrSafeInt<SHORT>::addition(m_stackSize, FrameSizeIncrement, m_stackSize))
1239 COMPlusThrowArithmetic();
1241 if (m_fHaveFramePointer)
1244 UCHAR OpInfo = (UCHAR)((FrameSizeIncrement - 8) / 8);
1246 if (OpInfo*8 + 8 == FrameSizeIncrement)
1248 UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_ALLOC_SMALL);
1249 pUnwindCode->OpInfo = OpInfo;
1253 USHORT FrameOffset = (USHORT)FrameSizeIncrement;
1254 BOOL fNeedExtraSlot = ((ULONG)FrameOffset != (ULONG)FrameSizeIncrement);
1256 UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_ALLOC_LARGE, fNeedExtraSlot);
1258 pUnwindCode->OpInfo = fNeedExtraSlot;
1260 pUnwindCode[1].FrameOffset = FrameOffset;
1263 pUnwindCode[2].FrameOffset = (USHORT)(FrameSizeIncrement >> 16);
1267 VOID StubLinker::UnwindSetFramePointer (UCHAR reg)
1269 _ASSERTE(!m_fHaveFramePointer);
1271 UNWIND_CODE *pUnwindCode = AllocUnwindInfo(UWOP_SET_FPREG);
1272 pUnwindCode->OpInfo = reg;
1274 m_fHaveFramePointer = TRUE;
1277 UNWIND_CODE *StubLinker::AllocUnwindInfo (UCHAR Op, UCHAR nExtraSlots /*= 0*/)
1286 _ASSERTE(Op < sizeof(UnwindOpExtraSlotTable));
1288 UCHAR nSlotsAlloc = UnwindOpExtraSlotTable[Op] + nExtraSlots;
1290 IntermediateUnwindInfo *pUnwindInfo = (IntermediateUnwindInfo*)m_quickHeap.Alloc( sizeof(IntermediateUnwindInfo)
1291 + nSlotsAlloc * sizeof(UNWIND_CODE));
1292 m_nUnwindSlots += 1 + nSlotsAlloc;
1294 pUnwindInfo->pNext = m_pUnwindInfoList;
1295 m_pUnwindInfoList = pUnwindInfo;
1297 UNWIND_CODE *pUnwindCode = &pUnwindInfo->rgUnwindCode[0];
1299 pUnwindCode->UnwindOp = Op;
1301 CodeRun *pCodeRun = GetLastCodeRunIfAny();
1302 _ASSERTE(pCodeRun != NULL);
1304 pUnwindInfo->pCodeRun = pCodeRun;
1305 pUnwindInfo->LocalOffset = pCodeRun->m_numcodebytes;
1307 EmitUnwindInfoCheck();
1311 #endif // defined(_TARGET_AMD64_)
1313 struct FindBlockArgs
1320 bool FindBlockCallback (PTR_VOID pvArgs, PTR_VOID pvAllocationBase, SIZE_T cbReserved)
1329 FindBlockArgs* pArgs = (FindBlockArgs*)pvArgs;
1330 if (pArgs->pCode >= pvAllocationBase && (pArgs->pCode < ((BYTE *)pvAllocationBase + cbReserved)))
1332 pArgs->pBlockBase = (BYTE*)pvAllocationBase;
1333 pArgs->cbBlockSize = cbReserved;
1340 bool StubLinker::EmitUnwindInfo(Stub* pStub, int globalsize, LoaderHeap* pHeap)
1342 STANDARD_VM_CONTRACT;
1344 BYTE *pCode = (BYTE*)(pStub->GetEntryPoint());
1347 // Determine the lower bound of the address space containing the stub.
1350 FindBlockArgs findBlockArgs;
1351 findBlockArgs.pCode = pCode;
1352 findBlockArgs.pBlockBase = NULL;
1354 pHeap->EnumPageRegions(&FindBlockCallback, &findBlockArgs);
1356 if (findBlockArgs.pBlockBase == NULL)
1358 // REVISIT_TODO better exception
1362 BYTE *pbRegionBaseAddress = findBlockArgs.pBlockBase;
1365 static SIZE_T MaxSegmentSize = -1;
1366 if (MaxSegmentSize == (SIZE_T)-1)
1367 MaxSegmentSize = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_MaxStubUnwindInfoSegmentSize, DYNAMIC_FUNCTION_TABLE_MAX_RANGE);
1369 const SIZE_T MaxSegmentSize = DYNAMIC_FUNCTION_TABLE_MAX_RANGE;
1373 // The RUNTIME_FUNCTION offsets are ULONGs. If the region size is >
1374 // ULONG_MAX, then we'll shift the base address to the next 4gb and
1375 // register a separate function table.
1377 // But...RtlInstallFunctionTableCallback has a 2gb restriction...so
1378 // make that LONG_MAX.
1381 StubUnwindInfoHeader *pHeader = pStub->GetUnwindInfoHeader();
1382 _ASSERTE(IS_ALIGNED(pHeader, sizeof(void*)));
1384 BYTE *pbBaseAddress = pbRegionBaseAddress;
1386 while ((size_t)((BYTE*)pHeader - pbBaseAddress) > MaxSegmentSize)
1388 pbBaseAddress += MaxSegmentSize;
1392 // If the unwind info/code straddle a 2gb boundary, then we're stuck.
1393 // Rather than add a lot more bit twiddling code to deal with this
1394 // exceptionally rare case, we'll signal the caller to keep this allocation
1395 // temporarily and allocate another. This repeats until we eventually get
1396 // an allocation that doesn't straddle a 2gb boundary. Afterwards the old
1397 // allocations are freed.
1400 if ((size_t)(pCode + globalsize - pbBaseAddress) > MaxSegmentSize)
1405 // Ensure that the first RUNTIME_FUNCTION struct ends up pointer aligned,
1406 // so that the StubUnwindInfoHeader struct is aligned. UNWIND_INFO
1407 // includes one UNWIND_CODE.
1408 _ASSERTE(IS_ALIGNED(pStub, sizeof(void*)));
1409 _ASSERTE(0 == (FIELD_OFFSET(StubUnwindInfoHeader, FunctionEntry) % sizeof(void*)));
1411 StubUnwindInfoHeader * pUnwindInfoHeader = pStub->GetUnwindInfoHeader();
1413 #ifdef _TARGET_AMD64_
1415 UNWIND_CODE *pDestUnwindCode = &pUnwindInfoHeader->UnwindInfo.UnwindCode[0];
1417 UNWIND_CODE *pDestUnwindCodeLimit = (UNWIND_CODE*)pStub->GetUnwindInfoHeaderSuffix();
1420 UINT FrameRegister = 0;
1423 // Resolve the unwind operation offsets, and fill in the UNWIND_INFO and
1424 // RUNTIME_FUNCTION structs preceeding the stub. The unwind codes are recorded
1425 // in decreasing address order.
1428 for (IntermediateUnwindInfo *pUnwindInfoList = m_pUnwindInfoList; pUnwindInfoList != NULL; pUnwindInfoList = pUnwindInfoList->pNext)
1430 UNWIND_CODE *pUnwindCode = &pUnwindInfoList->rgUnwindCode[0];
1431 UCHAR op = pUnwindCode[0].UnwindOp;
1433 if (UWOP_SET_FPREG == op)
1435 FrameRegister = pUnwindCode[0].OpInfo;
1439 // Compute number of slots used by this encoding.
1444 if (UWOP_ALLOC_LARGE == op)
1446 nSlots = 2 + pUnwindCode[0].OpInfo;
1450 _ASSERTE(UnwindOpExtraSlotTable[op] != (UCHAR)-1);
1451 nSlots = 1 + UnwindOpExtraSlotTable[op];
1455 // Compute offset and ensure that it will fit in the encoding.
1458 SIZE_T CodeOffset = pUnwindInfoList->pCodeRun->m_globaloffset
1459 + pUnwindInfoList->LocalOffset;
1461 if (CodeOffset != (SIZE_T)(UCHAR)CodeOffset)
1463 // REVISIT_TODO better exception
1468 // Copy the encoding data, overwrite the new offset, and advance
1469 // to the next encoding.
1472 _ASSERTE(pDestUnwindCode + nSlots <= pDestUnwindCodeLimit);
1474 CopyMemory(pDestUnwindCode, pUnwindCode, nSlots * sizeof(UNWIND_CODE));
1476 pDestUnwindCode->CodeOffset = (UCHAR)CodeOffset;
1478 pDestUnwindCode += nSlots;
1482 // Fill in the UNWIND_INFO struct
1484 UNWIND_INFO *pUnwindInfo = &pUnwindInfoHeader->UnwindInfo;
1485 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
1487 // PrologueSize may be 0 if all unwind directives at offset 0.
1488 SIZE_T PrologueSize = m_pUnwindInfoList->pCodeRun->m_globaloffset
1489 + m_pUnwindInfoList->LocalOffset;
1491 UINT nEntryPointSlots = m_nUnwindSlots;
1493 if ( PrologueSize != (SIZE_T)(UCHAR)PrologueSize
1494 || nEntryPointSlots > UCHAR_MAX)
1496 // REVISIT_TODO better exception
1500 _ASSERTE(nEntryPointSlots);
1502 pUnwindInfo->Version = 1;
1503 pUnwindInfo->Flags = 0;
1504 pUnwindInfo->SizeOfProlog = (UCHAR)PrologueSize;
1505 pUnwindInfo->CountOfUnwindCodes = (UCHAR)nEntryPointSlots;
1506 pUnwindInfo->FrameRegister = FrameRegister;
1507 pUnwindInfo->FrameOffset = 0;
1510 // Fill in the RUNTIME_FUNCTION struct for this prologue.
1512 PT_RUNTIME_FUNCTION pCurFunction = &pUnwindInfoHeader->FunctionEntry;
1513 _ASSERTE(IS_ALIGNED(pCurFunction, sizeof(ULONG)));
1515 S_UINT32 sBeginAddress = S_BYTEPTR(pCode) - S_BYTEPTR(pbBaseAddress);
1516 if (sBeginAddress.IsOverflow())
1517 COMPlusThrowArithmetic();
1518 pCurFunction->BeginAddress = sBeginAddress.Value();
1520 S_UINT32 sEndAddress = S_BYTEPTR(pCode) + S_BYTEPTR(globalsize) - S_BYTEPTR(pbBaseAddress);
1521 if (sEndAddress.IsOverflow())
1522 COMPlusThrowArithmetic();
1523 pCurFunction->EndAddress = sEndAddress.Value();
1525 S_UINT32 sTemp = S_BYTEPTR(pUnwindInfo) - S_BYTEPTR(pbBaseAddress);
1526 if (sTemp.IsOverflow())
1527 COMPlusThrowArithmetic();
1528 RUNTIME_FUNCTION__SetUnwindInfoAddress(pCurFunction, sTemp.Value());
1529 #elif defined(_TARGET_ARM_)
1531 // Fill in the RUNTIME_FUNCTION struct for this prologue.
1533 UNWIND_INFO *pUnwindInfo = &pUnwindInfoHeader->UnwindInfo;
1535 PT_RUNTIME_FUNCTION pCurFunction = &pUnwindInfoHeader->FunctionEntry;
1536 _ASSERTE(IS_ALIGNED(pCurFunction, sizeof(ULONG)));
1538 S_UINT32 sBeginAddress = S_BYTEPTR(pCode) - S_BYTEPTR(pbBaseAddress);
1539 if (sBeginAddress.IsOverflow())
1540 COMPlusThrowArithmetic();
1541 RUNTIME_FUNCTION__SetBeginAddress(pCurFunction, sBeginAddress.Value());
1543 S_UINT32 sTemp = S_BYTEPTR(pUnwindInfo) - S_BYTEPTR(pbBaseAddress);
1544 if (sTemp.IsOverflow())
1545 COMPlusThrowArithmetic();
1546 RUNTIME_FUNCTION__SetUnwindInfoAddress(pCurFunction, sTemp.Value());
1548 //Get the exact function Length. Cannot use globalsize as it is explicitly made to be
1550 CodeRun *pLastCodeElem = GetLastCodeRunIfAny();
1551 _ASSERTE(pLastCodeElem != NULL);
1553 int functionLength = pLastCodeElem->m_numcodebytes + pLastCodeElem->m_globaloffset;
1555 // cannot encode functionLength greater than (2 * 0xFFFFF)
1556 if (functionLength > 2 * 0xFFFFF)
1557 COMPlusThrowArithmetic();
1559 _ASSERTE(functionLength <= globalsize);
1561 BYTE * pUnwindCodes = (BYTE *)pUnwindInfo + sizeof(DWORD);
1563 // Not emitting compact unwind info as there are very few (4) dynamic stubs with unwind info.
1564 // Benefit of the optimization does not outweigh the cost of adding the code for it.
1566 //UnwindInfo for prolog
1567 if (m_cbStackFrame != 0)
1569 if(m_cbStackFrame < 512)
1571 *pUnwindCodes++ = (BYTE)0xF8; // 16-bit sub/add sp,#x
1572 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 18);
1573 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 10);
1574 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 2);
1578 *pUnwindCodes++ = (BYTE)0xFA; // 32-bit sub/add sp,#x
1579 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 18);
1580 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 10);
1581 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 2);
1584 if(m_cbStackFrame >= 4096)
1586 // r4 register is used as param to checkStack function and must have been saved in prolog
1587 _ASSERTE(m_cCalleeSavedRegs > 0);
1588 *pUnwindCodes++ = (BYTE)0xFB; // nop 16 bit for bl r12
1589 *pUnwindCodes++ = (BYTE)0xFC; // nop 32 bit for movt r12, checkStack
1590 *pUnwindCodes++ = (BYTE)0xFC; // nop 32 bit for movw r12, checkStack
1592 // Ensure that mov r4, m_cbStackFrame fits in a 32-bit instruction
1593 if(m_cbStackFrame > 65535)
1594 COMPlusThrow(kNotSupportedException);
1595 *pUnwindCodes++ = (BYTE)0xFC; // nop 32 bit for mov r4, m_cbStackFrame
1599 // Unwind info generated will be incorrect when m_cCalleeSavedRegs = 0.
1600 // The unwind code will say that the size of push/pop instruction
1601 // size is 16bits when actually the opcode generated by
1602 // ThumbEmitPop & ThumbEMitPush will be 32bits.
1603 // Currently no stubs has m_cCalleeSavedRegs as 0
1604 // therfore just adding the assert.
1605 _ASSERTE(m_cCalleeSavedRegs > 0);
1607 if (m_cCalleeSavedRegs <= 4)
1609 *pUnwindCodes++ = (BYTE)(0xD4 + (m_cCalleeSavedRegs - 1)); // push/pop {r4-rX}
1613 _ASSERTE(m_cCalleeSavedRegs <= 8);
1614 *pUnwindCodes++ = (BYTE)(0xDC + (m_cCalleeSavedRegs - 5)); // push/pop {r4-rX}
1619 *pUnwindCodes++ = (BYTE)0x04; // push {r0-r3} / add sp,#16
1620 *pUnwindCodes++ = (BYTE)0xFD; // bx lr
1624 *pUnwindCodes++ = (BYTE)0xFF; // end
1627 ptrdiff_t epilogUnwindCodeIndex = 0;
1629 //epilog differs from prolog
1630 if(m_cbStackFrame >= 4096)
1632 //Index of the first unwind code of the epilog
1633 epilogUnwindCodeIndex = pUnwindCodes - (BYTE *)pUnwindInfo - sizeof(DWORD);
1635 *pUnwindCodes++ = (BYTE)0xF8; // sub/add sp,#x
1636 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 18);
1637 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 10);
1638 *pUnwindCodes++ = (BYTE)(m_cbStackFrame >> 2);
1640 if (m_cCalleeSavedRegs <= 4)
1642 *pUnwindCodes++ = (BYTE)(0xD4 + (m_cCalleeSavedRegs - 1)); // push/pop {r4-rX}
1646 *pUnwindCodes++ = (BYTE)(0xDC + (m_cCalleeSavedRegs - 5)); // push/pop {r4-rX}
1651 *pUnwindCodes++ = (BYTE)0x04; // push {r0-r3} / add sp,#16
1652 *pUnwindCodes++ = (BYTE)0xFD; // bx lr
1656 *pUnwindCodes++ = (BYTE)0xFF; // end
1661 // Number of 32-bit unwind codes
1662 size_t codeWordsCount = (ALIGN_UP((size_t)pUnwindCodes, sizeof(void*)) - (size_t)pUnwindInfo - sizeof(DWORD))/4;
1664 _ASSERTE(epilogUnwindCodeIndex < 32);
1666 //Check that MAX_UNWIND_CODE_WORDS is sufficient to store all unwind Codes
1667 _ASSERTE(codeWordsCount <= MAX_UNWIND_CODE_WORDS);
1669 *(DWORD *)pUnwindInfo =
1670 ((functionLength) / 2) |
1672 ((int)epilogUnwindCodeIndex << 23)|
1673 ((int)codeWordsCount << 28);
1675 #elif defined(_TARGET_ARM64_)
1678 // If EmitProlog isn't called. This is a leaf function which doesn't need any unwindInfo
1679 T_RUNTIME_FUNCTION *pCurFunction = NULL;
1685 // Fill in the RUNTIME_FUNCTION struct for this prologue.
1687 UNWIND_INFO *pUnwindInfo = &(pUnwindInfoHeader->UnwindInfo);
1689 T_RUNTIME_FUNCTION *pCurFunction = &(pUnwindInfoHeader->FunctionEntry);
1691 _ASSERTE(IS_ALIGNED(pCurFunction, sizeof(void*)));
1693 S_UINT32 sBeginAddress = S_BYTEPTR(pCode) - S_BYTEPTR(pbBaseAddress);
1694 if (sBeginAddress.IsOverflow())
1695 COMPlusThrowArithmetic();
1697 S_UINT32 sTemp = S_BYTEPTR(pUnwindInfo) - S_BYTEPTR(pbBaseAddress);
1698 if (sTemp.IsOverflow())
1699 COMPlusThrowArithmetic();
1701 RUNTIME_FUNCTION__SetBeginAddress(pCurFunction, sBeginAddress.Value());
1702 RUNTIME_FUNCTION__SetUnwindInfoAddress(pCurFunction, sTemp.Value());
1704 CodeRun *pLastCodeElem = GetLastCodeRunIfAny();
1705 _ASSERTE(pLastCodeElem != NULL);
1707 int functionLength = pLastCodeElem->m_numcodebytes + pLastCodeElem->m_globaloffset;
1709 // .xdata has 18 bits for function length and it is to store the total length of the function in bytes, divided by 4
1710 // If the function is larger than 1M, then multiple pdata and xdata records must be used, which we don't support right now.
1711 if (functionLength > 4 * 0x3FFFF)
1712 COMPlusThrowArithmetic();
1714 _ASSERTE(functionLength <= globalsize);
1716 // No support for extended code words and/or extended epilog.
1717 // ASSERTION: first 10 bits of the pUnwindInfo, which holds the #codewords and #epilogcount, cannot be 0
1718 // And no space for exception scope data also means that no support for exceptions for the stubs
1719 // generated with this stublinker.
1720 BYTE * pUnwindCodes = (BYTE *)pUnwindInfo + sizeof(DWORD);
1723 // Emitting the unwind codes:
1724 // The unwind codes are emited in Epilog order.
1726 // 6. Integer argument registers
1727 // Although we might be saving the argument registers in the prolog we don't need
1728 // to report them to the OS. (they are not expressible anyways)
1730 // 5. Floating point argument registers:
1731 // Similar to Integer argumetn registers, no reporting
1734 // 4. Set the frame pointer
1735 // ASSUMPTION: none of the Stubs generated with this stublinker change SP value outside of epilog and prolog
1736 // when that is the case we can skip reporting setting up the frame pointer
1738 // With skiping Step #4, #5 and #6 Prolog and Epilog becomes reversible. so they can share the unwind codes
1739 int epilogUnwindCodeIndex = 0;
1741 unsigned cStackFrameSizeInQWORDs = GetStackFrameSize()/16;
1744 *pUnwindCodes++ = (BYTE)(0x40 | (m_cbStackSpace>>3));
1746 // 2. Callee-saved registers
1748 if (m_cCalleeSavedRegs > 0)
1750 unsigned offset = 2 + m_cbStackSpace/8; // 2 is for fp,lr
1751 if ((m_cCalleeSavedRegs %2) ==1)
1754 *pUnwindCodes++ = (BYTE) (0xD0 | ((m_cCalleeSavedRegs-1)>>2));
1755 *pUnwindCodes++ = (BYTE) ((BYTE)((m_cCalleeSavedRegs-1) << 6) | ((offset + m_cCalleeSavedRegs - 1) & 0x3F));
1757 for (int i=(m_cCalleeSavedRegs/2)*2-2; i>=0; i-=2)
1762 *pUnwindCodes++ = 0xE6;
1767 *pUnwindCodes++ = 0xC8;
1768 *pUnwindCodes++ = (BYTE)(offset & 0x3F);
1775 // EmitProlog is supposed to reject frames larger than 504 bytes.
1776 // Assert that here.
1777 _ASSERTE(cStackFrameSizeInQWORDs <= 0x3F);
1778 if (cStackFrameSizeInQWORDs <= 0x1F)
1781 *pUnwindCodes++ = (BYTE)(cStackFrameSizeInQWORDs);
1786 *pUnwindCodes++ = (BYTE)(0xC0 | (cStackFrameSizeInQWORDs >> 8));
1787 *pUnwindCodes++ = (BYTE)(cStackFrameSizeInQWORDs);
1791 *pUnwindCodes++ = 0xE4;
1793 // Number of 32-bit unwind codes
1794 int codeWordsCount = (int)(ALIGN_UP((size_t)pUnwindCodes, sizeof(DWORD)) - (size_t)pUnwindInfo - sizeof(DWORD))/4;
1796 //Check that MAX_UNWIND_CODE_WORDS is sufficient to store all unwind Codes
1797 _ASSERTE(codeWordsCount <= MAX_UNWIND_CODE_WORDS);
1799 *(DWORD *)pUnwindInfo =
1800 ((functionLength) / 4) |
1801 (1 << 21) | // E bit
1802 (epilogUnwindCodeIndex << 22)|
1803 (codeWordsCount << 27);
1804 } // end else (!m_fProlog)
1806 PORTABILITY_ASSERT("StubLinker::EmitUnwindInfo");
1807 T_RUNTIME_FUNCTION *pCurFunction = NULL;
1811 // Get a StubUnwindInfoHeapSegment for this base address
1814 CrstHolder crst(&g_StubUnwindInfoHeapSegmentsCrst);
1816 StubUnwindInfoHeapSegment *pStubHeapSegment;
1817 StubUnwindInfoHeapSegment **ppPrevStubHeapSegment;
1818 for (ppPrevStubHeapSegment = &g_StubHeapSegments;
1819 (pStubHeapSegment = *ppPrevStubHeapSegment);
1820 (ppPrevStubHeapSegment = &pStubHeapSegment->pNext))
1822 if (pbBaseAddress < pStubHeapSegment->pbBaseAddress)
1824 // The list is ordered, so address is between segments
1825 pStubHeapSegment = NULL;
1829 if (pbBaseAddress == pStubHeapSegment->pbBaseAddress)
1831 // Found an existing segment
1836 if (!pStubHeapSegment)
1839 // RtlInstallFunctionTableCallback will only accept a ULONG for the
1840 // region size. We've already checked above that the RUNTIME_FUNCTION
1841 // offsets will work relative to pbBaseAddress.
1844 SIZE_T cbSegment = findBlockArgs.cbBlockSize;
1846 if (cbSegment > MaxSegmentSize)
1847 cbSegment = MaxSegmentSize;
1849 NewHolder<StubUnwindInfoHeapSegment> pNewStubHeapSegment = new StubUnwindInfoHeapSegment();
1852 pNewStubHeapSegment->pbBaseAddress = pbBaseAddress;
1853 pNewStubHeapSegment->cbSegment = cbSegment;
1854 pNewStubHeapSegment->pUnwindHeaderList = NULL;
1855 #ifdef _TARGET_AMD64_
1856 pNewStubHeapSegment->pUnwindInfoTable = NULL;
1859 // Insert the new stub into list
1860 pNewStubHeapSegment->pNext = *ppPrevStubHeapSegment;
1861 *ppPrevStubHeapSegment = pNewStubHeapSegment;
1862 pNewStubHeapSegment.SuppressRelease();
1864 // Use new segment for the stub
1865 pStubHeapSegment = pNewStubHeapSegment;
1867 InstallEEFunctionTable(
1868 pNewStubHeapSegment,
1871 &FindStubFunctionEntry,
1872 pNewStubHeapSegment,
1877 // Link the new stub into the segment.
1880 pHeader->pNext = pStubHeapSegment->pUnwindHeaderList;
1881 pStubHeapSegment->pUnwindHeaderList = pHeader;
1883 #ifdef _TARGET_AMD64_
1884 // Publish Unwind info to ETW stack crawler
1885 UnwindInfoTable::AddToUnwindInfoTable(
1886 &pStubHeapSegment->pUnwindInfoTable, pCurFunction,
1887 (TADDR) pStubHeapSegment->pbBaseAddress,
1888 (TADDR) pStubHeapSegment->pbBaseAddress + pStubHeapSegment->cbSegment);
1892 _ASSERTE(pHeader->IsRegistered());
1893 _ASSERTE( &pHeader->FunctionEntry
1894 == FindStubFunctionEntry((ULONG64)pCode, EncodeDynamicFunctionTableContext(pStubHeapSegment, DYNFNTABLE_STUB)));
1899 #endif // STUBLINKER_GENERATES_UNWIND_INFO
1902 void StubLinker::DescribeProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs)
1905 m_cCalleeSavedRegs = cCalleeSavedRegs;
1906 m_cbStackFrame = cbStackFrame;
1907 m_fPushArgRegs = fPushArgRegs;
1909 #elif defined(_TARGET_ARM64_)
1910 void StubLinker::DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cCalleeSavedRegs, UINT cbStackSpace)
1913 m_cIntRegArgs = cIntRegArgs;
1914 m_cVecRegArgs = cVecRegArgs;
1915 m_cCalleeSavedRegs = cCalleeSavedRegs;
1916 m_cbStackSpace = cbStackSpace;
1919 UINT StubLinker::GetSavedRegArgsOffset()
1921 _ASSERTE(m_fProlog);
1922 // This is the offset from SP
1923 // We're assuming that the stublinker will push the arg registers to the bottom of the stack frame
1924 return m_cbStackSpace + (2+ m_cCalleeSavedRegs)*sizeof(void*); // 2 is for FP and LR
1927 UINT StubLinker::GetStackFrameSize()
1929 _ASSERTE(m_fProlog);
1930 return m_cbStackSpace + (2 + m_cCalleeSavedRegs + m_cIntRegArgs + m_cVecRegArgs)*sizeof(void*);
1934 #endif // ifdef _TARGET_ARM_, elif defined(_TARGET_ARM64_)
1936 #endif // #ifndef DACCESS_COMPILE
1938 #ifndef DACCESS_COMPILE
1940 //-------------------------------------------------------------------
1941 // Inc the refcount.
1942 //-------------------------------------------------------------------
1952 _ASSERTE(m_signature == kUsedStub);
1953 FastInterlockIncrement((LONG*)&m_refcount);
1956 //-------------------------------------------------------------------
1957 // Dec the refcount.
1958 //-------------------------------------------------------------------
1968 _ASSERTE(m_signature == kUsedStub);
1969 int count = FastInterlockDecrement((LONG*)&m_refcount);
1971 if(m_patchOffset & INTERCEPT_BIT)
1973 ((InterceptStub*)this)->ReleaseInterceptedStub();
1982 VOID Stub::DeleteStub()
1991 COUNTER_ONLY(GetPerfCounters().m_Interop.cStubs--);
1993 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
1994 if (HasUnwindInfo())
1996 StubUnwindInfoHeader *pHeader = GetUnwindInfoHeader();
1999 // Check if the stub has been linked into a StubUnwindInfoHeapSegment.
2001 if (pHeader->IsRegistered())
2003 CrstHolder crst(&g_StubUnwindInfoHeapSegmentsCrst);
2006 // Find the segment containing the stub.
2008 StubUnwindInfoHeapSegment **ppPrevSegment = &g_StubHeapSegments;
2009 StubUnwindInfoHeapSegment *pSegment = *ppPrevSegment;
2013 PBYTE pbCode = (PBYTE)GetEntryPointInternal();
2014 #ifdef _TARGET_AMD64_
2015 UnwindInfoTable::RemoveFromUnwindInfoTable(&pSegment->pUnwindInfoTable,
2016 (TADDR) pSegment->pbBaseAddress, (TADDR) pbCode);
2018 for (StubUnwindInfoHeapSegment *pNextSegment = pSegment->pNext;
2020 ppPrevSegment = &pSegment->pNext, pSegment = pNextSegment, pNextSegment = pSegment->pNext)
2022 // The segments are sorted by pbBaseAddress.
2023 if (pbCode < pNextSegment->pbBaseAddress)
2028 // The stub was marked as registered, so a segment should exist.
2035 // Find this stub's location in the segment's list.
2037 StubUnwindInfoHeader *pCurHeader;
2038 StubUnwindInfoHeader **ppPrevHeaderList;
2039 for (ppPrevHeaderList = &pSegment->pUnwindHeaderList;
2040 (pCurHeader = *ppPrevHeaderList);
2041 (ppPrevHeaderList = &pCurHeader->pNext))
2043 if (pHeader == pCurHeader)
2047 // The stub was marked as registered, so we should find it in the segment's list.
2048 _ASSERTE(pCurHeader);
2053 // Remove the stub from the segment's list.
2055 *ppPrevHeaderList = pHeader->pNext;
2058 // If the segment's list is now empty, delete the segment.
2060 if (!pSegment->pUnwindHeaderList)
2062 DeleteEEFunctionTable(pSegment);
2063 #ifdef _TARGET_AMD64_
2064 if (pSegment->pUnwindInfoTable != 0)
2065 delete pSegment->pUnwindInfoTable;
2067 *ppPrevSegment = pSegment->pNext;
2076 // a size of 0 is a signal to Nirvana to flush the entire cache
2077 //FlushInstructionCache(GetCurrentProcess(),0,0);
2079 if ((m_patchOffset & LOADER_HEAP_BIT) == 0)
2082 m_signature = kFreedStub;
2083 FillMemory(this+1, m_numCodeBytes, 0xcc);
2087 DeleteExecutable((BYTE*)GetAllocationBase());
2089 delete [] (BYTE*)GetAllocationBase();
2094 TADDR Stub::GetAllocationBase()
2104 TADDR info = dac_cast<TADDR>(this);
2105 SIZE_T cbPrefix = 0;
2109 cbPrefix += 2 * sizeof(TADDR);
2112 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2113 if (HasUnwindInfo())
2115 StubUnwindInfoHeaderSuffix *pSuffix =
2116 PTR_StubUnwindInfoHeaderSuffix(info - cbPrefix -
2119 cbPrefix += StubUnwindInfoHeader::ComputeSize(pSuffix->nUnwindInfoSize);
2121 #endif // STUBLINKER_GENERATES_UNWIND_INFO
2123 if (!HasExternalEntryPoint())
2125 cbPrefix = ALIGN_UP(cbPrefix + sizeof(Stub), CODE_SIZE_ALIGN) - sizeof(Stub);
2128 return info - cbPrefix;
2131 Stub* Stub::NewStub(PTR_VOID pCode, DWORD flags)
2140 Stub* pStub = NewStub(NULL, 0, flags | NEWSTUB_FL_EXTERNAL);
2141 _ASSERTE(pStub->HasExternalEntryPoint());
2143 *(PTR_VOID *)(pStub + 1) = pCode;
2148 //-------------------------------------------------------------------
2149 // Stub allocation done here.
2150 //-------------------------------------------------------------------
2151 /*static*/ Stub* Stub::NewStub(
2155 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2156 , UINT nUnwindInfoSize
2167 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2168 _ASSERTE(!nUnwindInfoSize || !pHeap || pHeap->m_fPermitStubsWithUnwindInfo);
2169 #endif // STUBLINKER_GENERATES_UNWIND_INFO
2171 COUNTER_ONLY(GetPerfCounters().m_Interop.cStubs++);
2173 S_SIZE_T size = S_SIZE_T(sizeof(Stub));
2175 if (flags & NEWSTUB_FL_INTERCEPT)
2177 size += sizeof(Stub *) + sizeof(void*);
2180 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2181 if (nUnwindInfoSize != 0)
2183 size += StubUnwindInfoHeader::ComputeSize(nUnwindInfoSize);
2187 if (flags & NEWSTUB_FL_EXTERNAL)
2189 _ASSERTE(numCodeBytes == 0);
2190 size += sizeof(PTR_PCODE);
2194 size.AlignUp(CODE_SIZE_ALIGN);
2195 size += numCodeBytes;
2198 if (size.IsOverflow())
2199 COMPlusThrowArithmetic();
2201 size_t totalSize = size.Value();
2207 pBlock = new (executable) BYTE[totalSize];
2209 pBlock = new BYTE[totalSize];
2214 pBlock = (BYTE*)(void*) pHeap->AllocAlignedMem(totalSize, CODE_SIZE_ALIGN);
2215 flags |= NEWSTUB_FL_LOADERHEAP;
2218 // Make sure that the payload of the stub is aligned
2219 Stub* pStub = (Stub*)((pBlock + totalSize) -
2220 (sizeof(Stub) + ((flags & NEWSTUB_FL_EXTERNAL) ? sizeof(PTR_PCODE) : numCodeBytes)));
2225 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2230 _ASSERTE((BYTE *)pStub->GetAllocationBase() == pBlock);
2235 void Stub::SetupStub(int numCodeBytes, DWORD flags
2236 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2237 , UINT nUnwindInfoSize
2249 m_signature = kUsedStub;
2252 m_pad_code_bytes = 0;
2256 m_numCodeBytes = numCodeBytes;
2261 if((flags & NEWSTUB_FL_INTERCEPT) != 0)
2262 m_patchOffset |= INTERCEPT_BIT;
2263 if((flags & NEWSTUB_FL_LOADERHEAP) != 0)
2264 m_patchOffset |= LOADER_HEAP_BIT;
2265 if((flags & NEWSTUB_FL_MULTICAST) != 0)
2266 m_patchOffset |= MULTICAST_DELEGATE_BIT;
2267 if ((flags & NEWSTUB_FL_EXTERNAL) != 0)
2268 m_patchOffset |= EXTERNAL_ENTRY_BIT;
2270 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2271 if (nUnwindInfoSize)
2273 m_patchOffset |= UNWIND_INFO_BIT;
2275 StubUnwindInfoHeaderSuffix * pSuffix = GetUnwindInfoHeaderSuffix();
2276 pSuffix->nUnwindInfoSize = (BYTE)nUnwindInfoSize;
2278 StubUnwindInfoHeader * pHeader = GetUnwindInfoHeader();
2284 //-------------------------------------------------------------------
2286 //-------------------------------------------------------------------
2287 /*static*/ void Stub::Init()
2296 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2297 g_StubUnwindInfoHeapSegmentsCrst.Init(CrstStubUnwindInfoHeapSegments);
2301 /*static*/ Stub* InterceptStub::NewInterceptedStub(void* pCode,
2312 InterceptStub *pStub = (InterceptStub *) NewStub(pCode, NEWSTUB_FL_INTERCEPT);
2314 *pStub->GetInterceptedStub() = interceptee;
2315 *pStub->GetRealAddr() = (TADDR)pRealAddr;
2317 LOG((LF_CORDB, LL_INFO10000, "For Stub 0x%x, set intercepted stub to 0x%x\n",
2318 pStub, interceptee));
2323 //-------------------------------------------------------------------
2324 // Stub allocation done here.
2325 //-------------------------------------------------------------------
2326 /*static*/ Stub* InterceptStub::NewInterceptedStub(LoaderHeap *pHeap,
2330 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2331 , UINT nUnwindInfoSize
2342 InterceptStub *pStub = (InterceptStub *) NewStub(
2345 NEWSTUB_FL_INTERCEPT
2346 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
2351 *pStub->GetInterceptedStub() = interceptee;
2352 *pStub->GetRealAddr() = (TADDR)pRealAddr;
2354 LOG((LF_CORDB, LL_INFO10000, "For Stub 0x%x, set intercepted stub to 0x%x\n",
2355 pStub, interceptee));
2360 //-------------------------------------------------------------------
2361 // Release the stub that is owned by this stub
2362 //-------------------------------------------------------------------
2363 void InterceptStub::ReleaseInterceptedStub()
2372 Stub** intercepted = GetInterceptedStub();
2373 // If we own the stub then decrement it. It can be null if the
2374 // linked stub is actually a jitted stub.
2376 (*intercepted)->DecRef();
2379 //-------------------------------------------------------------------
2381 //-------------------------------------------------------------------
2382 ArgBasedStubCache::ArgBasedStubCache(UINT fixedSlots)
2383 : m_numFixedSlots(fixedSlots),
2384 m_crst(CrstArgBasedStubCache)
2386 WRAPPER_NO_CONTRACT;
2388 m_aStub = new Stub * [m_numFixedSlots];
2389 _ASSERTE(m_aStub != NULL);
2391 for (unsigned __int32 i = 0; i < m_numFixedSlots; i++) {
2394 m_pSlotEntries = NULL;
2398 //-------------------------------------------------------------------
2400 //-------------------------------------------------------------------
2401 ArgBasedStubCache::~ArgBasedStubCache()
2410 for (unsigned __int32 i = 0; i < m_numFixedSlots; i++) {
2411 Stub *pStub = m_aStub[i];
2416 // a size of 0 is a signal to Nirvana to flush the entire cache
2417 // not sure if this is needed, but should have no CLR perf impact since size is 0.
2418 FlushInstructionCache(GetCurrentProcess(),0,0);
2420 SlotEntry **ppSlotEntry = &m_pSlotEntries;
2422 while (NULL != (pCur = *ppSlotEntry)) {
2423 Stub *pStub = pCur->m_pStub;
2425 *ppSlotEntry = pCur->m_pNext;
2433 //-------------------------------------------------------------------
2434 // Queries/retrieves a previously cached stub.
2436 // If there is no stub corresponding to the given index,
2437 // this function returns NULL.
2439 // Otherwise, this function returns the stub after
2440 // incrementing its refcount.
2441 //-------------------------------------------------------------------
2442 Stub *ArgBasedStubCache::GetStub(UINT_PTR key)
2454 CrstHolder ch(&m_crst);
2456 if (key < m_numFixedSlots) {
2457 pStub = m_aStub[key];
2460 for (SlotEntry *pSlotEntry = m_pSlotEntries;
2462 pSlotEntry = pSlotEntry->m_pNext) {
2464 if (pSlotEntry->m_key == key) {
2465 pStub = pSlotEntry->m_pStub;
2477 //-------------------------------------------------------------------
2478 // Tries to associate a stub with a given index. This association
2479 // may fail because some other thread may have beaten you to it
2480 // just before you make the call.
2482 // If the association succeeds, "pStub" is installed, and it is
2483 // returned back to the caller. The stub's refcount is incremented
2484 // twice (one to reflect the cache's ownership, and one to reflect
2485 // the caller's ownership.)
2487 // If the association fails because another stub is already installed,
2488 // then the incumbent stub is returned to the caller and its refcount
2489 // is incremented once (to reflect the caller's ownership.)
2491 // If the association fails due to lack of memory, NULL is returned
2492 // and no one's refcount changes.
2494 // This routine is intended to be called like this:
2496 // Stub *pCandidate = MakeStub(); // after this, pCandidate's rc is 1
2497 // Stub *pWinner = cache->SetStub(idx, pCandidate);
2498 // pCandidate->DecRef();
2499 // pCandidate = 0xcccccccc; // must not use pCandidate again.
2501 // OutOfMemoryError;
2503 // // If the association succeeded, pWinner's refcount is 2 and so
2504 // // is pCandidate's (because it *is* pWinner);.
2505 // // If the association failed, pWinner's refcount is still 2
2506 // // and pCandidate got destroyed by the last DecRef().
2507 // // Either way, pWinner is now the official index holder. It
2508 // // has a refcount of 2 (one for the cache's ownership, and
2509 // // one belonging to this code.)
2510 //-------------------------------------------------------------------
2511 Stub* ArgBasedStubCache::AttemptToSetStub(UINT_PTR key, Stub *pStub)
2521 CrstHolder ch(&m_crst);
2523 if (key < m_numFixedSlots) {
2525 pStub = m_aStub[key];
2527 m_aStub[key] = pStub;
2528 pStub->IncRef(); // IncRef on cache's behalf
2531 SlotEntry *pSlotEntry;
2532 for (pSlotEntry = m_pSlotEntries;
2534 pSlotEntry = pSlotEntry->m_pNext) {
2536 if (pSlotEntry->m_key == key) {
2537 pStub = pSlotEntry->m_pStub;
2542 pSlotEntry = new SlotEntry;
2543 pSlotEntry->m_pStub = pStub;
2544 pStub->IncRef(); // IncRef on cache's behalf
2545 pSlotEntry->m_key = key;
2546 pSlotEntry->m_pNext = m_pSlotEntries;
2547 m_pSlotEntries = pSlotEntry;
2551 pStub->IncRef(); // IncRef because we're returning it to caller
2560 VOID ArgBasedStubCache::Dump()
2570 printf("--------------------------------------------------------------\n");
2571 printf("ArgBasedStubCache dump (%lu fixed entries):\n", m_numFixedSlots);
2572 for (UINT32 i = 0; i < m_numFixedSlots; i++) {
2574 printf(" Fixed slot %lu: ", (ULONG)i);
2575 Stub *pStub = m_aStub[i];
2579 printf("%lxh - refcount is %lu\n",
2580 (size_t)(pStub->GetEntryPoint()),
2581 (ULONG)( *( ( ((ULONG*)(pStub->GetEntryPoint())) - 1))));
2585 for (SlotEntry *pSlotEntry = m_pSlotEntries;
2587 pSlotEntry = pSlotEntry->m_pNext) {
2589 printf(" Dyna. slot %lu: ", (ULONG)(pSlotEntry->m_key));
2590 Stub *pStub = pSlotEntry->m_pStub;
2591 printf("%lxh - refcount is %lu\n",
2592 (size_t)(pStub->GetEntryPoint()),
2593 (ULONG)( *( ( ((ULONG*)(pStub->GetEntryPoint())) - 1))));
2598 printf("--------------------------------------------------------------\n");
2602 #endif // #ifndef DACCESS_COMPILE