1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
8 // A StubLinker object provides a way to link several location-independent
9 // code sources into one executable stub, resolving references,
10 // and choosing the shortest possible instruction size. The StubLinker
11 // abstracts out the notion of a "reference" so it is completely CPU
12 // independent. This StubLinker is intended not only to create method
13 // stubs but to create the PCode-marshaling stubs for Native/Direct.
15 // A StubLinker's typical life-cycle is:
17 // 1. Create a new StubLinker (it accumulates state for the stub being
19 // 2. Emit code bytes and references (requiring fixups) into the StubLinker.
20 // 3. Call the Link() method to produce the final stub.
21 // 4. Destroy the StubLinker.
23 // StubLinkers are not multithread-aware: they're intended to be
24 // used entirely on a single thread. Also, StubLinker's report errors
25 // using COMPlusThrow. StubLinker's do have a destructor: to prevent
26 // C++ object unwinding from clashing with COMPlusThrow,
27 // you must use COMPLUSCATCH to ensure the StubLinker's cleanup in the
28 // event of an exception: the following code would do it:
30 // StubLinker stublink;
34 // // Have to separate into inner function because VC++ forbids
35 // // mixing __try & local objects in the same function.
46 // This file should only be included via the platform-specific cgencpu.h.
50 #ifndef __stublink_h__
51 #define __stublink_h__
55 #include "eecontract.h"
57 //-------------------------------------------------------------------------
59 //-------------------------------------------------------------------------
60 class InstructionFormat;
62 class CheckDuplicatedStructLayouts;
63 class CodeBasedStubCache;
69 struct IntermediateUnwindInfo;
71 #if !defined(TARGET_X86) && !defined(TARGET_UNIX)
72 #define STUBLINKER_GENERATES_UNWIND_INFO
73 #endif // !TARGET_X86 && !TARGET_UNIX
76 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
78 typedef DPTR(struct StubUnwindInfoHeaderSuffix) PTR_StubUnwindInfoHeaderSuffix;
79 struct StubUnwindInfoHeaderSuffix
81 UCHAR nUnwindInfoSize; // Size of unwind info in bytes
84 // Variable-sized struct that precedes a Stub when the stub requires unwind
85 // information. Followed by a StubUnwindInfoHeaderSuffix.
86 typedef DPTR(struct StubUnwindInfoHeader) PTR_StubUnwindInfoHeader;
87 struct StubUnwindInfoHeader
89 PTR_StubUnwindInfoHeader pNext;
90 T_RUNTIME_FUNCTION FunctionEntry;
91 UNWIND_INFO UnwindInfo; // variable length
93 // Computes the size needed for this variable-sized struct.
94 static SIZE_T ComputeAlignedSize(UINT nUnwindInfoSize);
101 // List of stub address ranges, in increasing address order.
102 struct StubUnwindInfoHeapSegment
106 StubUnwindInfoHeader *pUnwindHeaderList;
107 StubUnwindInfoHeapSegment *pNext;
110 class UnwindInfoTable* pUnwindInfoTable; // Used to publish unwind info to ETW stack crawler
114 VOID UnregisterUnwindInfoInLoaderHeap (UnlockedLoaderHeap *pHeap);
116 #endif // STUBLINKER_GENERATES_UNWIND_INFO
119 //-------------------------------------------------------------------------
120 // A non-multithreaded object that fixes up and emits one executable stub.
121 //-------------------------------------------------------------------------
125 //---------------------------------------------------------------
127 //---------------------------------------------------------------
131 //---------------------------------------------------------------
132 // Create a new undefined label. Label must be assigned to a code
133 // location using EmitLabel() prior to final linking.
134 // Throws exception on failure.
135 //---------------------------------------------------------------
136 CodeLabel* NewCodeLabel();
138 //---------------------------------------------------------------
139 // Create a new undefined label for which we want the absolute
140 // address, not offset. Label must be assigned to a code
141 // location using EmitLabel() prior to final linking.
142 // Throws exception on failure.
143 //---------------------------------------------------------------
144 CodeLabel* NewAbsoluteCodeLabel();
146 //---------------------------------------------------------------
147 // Combines NewCodeLabel() and EmitLabel() for convenience.
148 // Throws exception on failure.
149 //---------------------------------------------------------------
150 CodeLabel* EmitNewCodeLabel();
153 //---------------------------------------------------------------
154 // Returns final location of label as an offset from the start
155 // of the stub. Can only be called after linkage.
156 //---------------------------------------------------------------
157 UINT32 GetLabelOffset(CodeLabel *pLabel);
159 //---------------------------------------------------------------
160 // Append code bytes.
161 //---------------------------------------------------------------
162 VOID EmitBytes(const BYTE *pBytes, UINT numBytes);
163 VOID Emit8 (unsigned __int8 u8);
164 VOID Emit16(unsigned __int16 u16);
165 VOID Emit32(unsigned __int32 u32);
166 VOID Emit64(unsigned __int64 u64);
167 VOID EmitPtr(const VOID *pval);
169 //---------------------------------------------------------------
170 // Append an instruction containing a reference to a label.
172 // target - the label being referenced.
173 // instructionFormat - a platform-specific InstructionFormat object
174 // that gives properties about the reference.
175 // variationCode - uninterpreted data passed to the pInstructionFormat methods.
176 //---------------------------------------------------------------
177 VOID EmitLabelRef(CodeLabel* target, const InstructionFormat & instructionFormat, UINT variationCode);
180 //---------------------------------------------------------------
181 // Sets the label to point to the current "instruction pointer"
182 // It is invalid to call EmitLabel() twice on
184 //---------------------------------------------------------------
185 VOID EmitLabel(CodeLabel* pCodeLabel);
187 //---------------------------------------------------------------
188 // Emits the patch label for the stub.
189 // Throws exception on failure.
190 //---------------------------------------------------------------
191 void EmitPatchLabel();
193 //---------------------------------------------------------------
194 // Create a new label to an external address.
195 // Throws exception on failure.
196 //---------------------------------------------------------------
197 CodeLabel* NewExternalCodeLabel(LPVOID pExternalAddress);
198 CodeLabel* NewExternalCodeLabel(PCODE pExternalAddress)
200 return NewExternalCodeLabel((LPVOID)pExternalAddress);
203 //---------------------------------------------------------------
204 // Set the target method for Instantiating stubs.
205 //---------------------------------------------------------------
206 void SetTargetMethod(PTR_MethodDesc pMD);
208 //---------------------------------------------------------------
209 // Push and Pop can be used to keep track of stack growth.
210 // These should be adjusted by opcodes written to the stream.
212 // Note that popping & pushing stack size as opcodes are emitted
213 // is naive & may not be accurate in many cases,
214 // so complex stubs may have to manually adjust the stack size.
215 // However it should work for the vast majority of cases we care
217 //---------------------------------------------------------------
218 void Push(UINT size);
221 INT GetStackSize() { LIMITED_METHOD_CONTRACT; return m_stackSize; }
222 void SetStackSize(SHORT size) { LIMITED_METHOD_CONTRACT; m_stackSize = size; }
224 void SetDataOnly(BOOL fDataOnly = TRUE) { LIMITED_METHOD_CONTRACT; m_fDataOnly = fDataOnly; }
227 void DescribeProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs);
228 #elif defined(TARGET_ARM64)
229 void DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cCalleeSavedRegs, UINT cbStackFrame);
230 UINT GetSavedRegArgsOffset();
231 UINT GetStackFrameSize();
232 #elif defined(TARGET_RISCV64)
233 void DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cbStackFrame);
234 UINT GetSavedRegArgsOffset();
235 UINT GetStackFrameSize();
238 //===========================================================================
239 // Unwind information
241 // Records location of preserved or parameter register
242 VOID UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset);
243 VOID UnwindPushedReg (UCHAR reg);
245 // Records "sub rsp, xxx"
246 VOID UnwindAllocStack (SHORT FrameSizeIncrement);
248 // Records frame pointer register
249 VOID UnwindSetFramePointer (UCHAR reg);
251 // In DEBUG, emits a call to m_pUnwindInfoCheckLabel (via
252 // EmitUnwindInfoCheckWorker). Code at that label will call to a
253 // helper that will attempt to RtlVirtualUnwind through the stub. The
254 // helper will preserve ALL registers.
255 VOID EmitUnwindInfoCheck();
257 #if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
260 // Injects a call to the given label.
261 virtual VOID EmitUnwindInfoCheckWorker (CodeLabel *pCheckLabel) { _ASSERTE(!"override me"); }
263 // Emits a call to a helper that will attempt to RtlVirtualUnwind
264 // through the stub. The helper will preserve ALL registers.
265 virtual VOID EmitUnwindInfoCheckSubfunction() { _ASSERTE(!"override me"); }
270 //---------------------------------------------------------------
271 // Generate the actual stub. The returned stub has a refcount of 1.
272 // No other methods (other than the destructor) should be called
273 // after calling Link().
275 // Throws exception on failure.
276 //---------------------------------------------------------------
277 Stub *Link(LoaderHeap *heap, DWORD flags = 0);
280 CodeElement *m_pCodeElements; // stored in *reverse* order
281 CodeLabel *m_pFirstCodeLabel; // linked list of CodeLabels
282 LabelRef *m_pFirstLabelRef; // linked list of references
283 CodeLabel *m_pPatchLabel; // label of stub patch offset
284 // currently just for multicast
286 PTR_MethodDesc m_pTargetMethod; // Used for instantiating stubs.
287 SHORT m_stackSize; // count of pushes/pops
288 CQuickHeap m_quickHeap; // throwaway heap for
291 BOOL m_fDataOnly; // the stub contains only data - does not need FlushInstructionCache
295 BOOL m_fProlog; // True if DescribeProlog has been called
296 UINT m_cCalleeSavedRegs; // Count of callee saved registers (0 == none, 1 == r4, 2 ==
297 // r4-r5 etc. up to 8 == r4-r11)
298 UINT m_cbStackFrame; // Count of bytes in the stack frame (excl of saved regs)
299 BOOL m_fPushArgRegs; // If true, r0-r3 are saved before callee saved regs
304 BOOL m_fProlog; // True if DescribeProlog has been called
305 UINT m_cIntRegArgs; // Count of int register arguments (x0 - x7)
306 UINT m_cVecRegArgs; // Count of FP register arguments (v0 - v7)
307 UINT m_cCalleeSavedRegs; // Count of callee saved registers (x19 - x28)
308 UINT m_cbStackSpace; // Additional stack space for return buffer and stack alignment
309 #endif // TARGET_ARM64
311 #ifdef TARGET_RISCV64
313 BOOL m_fProlog; // True if DescribeProlog has been called
314 UINT m_cIntRegArgs; // Count of int register arguments (x10 - x17)
315 UINT m_cFpRegArgs; // Count of FP register arguments (f10 - f17)
316 UINT m_cbStackSpace; // Additional stack space for return buffer and stack alignment
317 #endif // TARGET_RISCV64
319 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
322 CodeLabel *m_pUnwindInfoCheckLabel; // subfunction to call to unwind info check helper.
323 // On AMD64, the prologue is restricted to 256
324 // bytes, so this reduces the size of the injected
325 // code from 14 to 5 bytes.
329 IntermediateUnwindInfo *m_pUnwindInfoList;
330 UINT m_nUnwindSlots; // number of slots to allocate at end, == UNWIND_INFO::CountOfCodes
331 BOOL m_fHaveFramePointer; // indicates stack operations no longer need to be recorded
334 // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
336 UINT UnwindInfoSize(UINT codeSize)
338 if (m_nUnwindSlots == 0) return 0;
340 return sizeof(T_RUNTIME_FUNCTION) + offsetof(UNWIND_INFO, UnwindCode) + m_nUnwindSlots * sizeof(UNWIND_CODE);
342 #endif // TARGET_AMD64
345 #define MAX_UNWIND_CODE_WORDS 5 /* maximum number of 32-bit words to store unwind codes */
346 // Cache information about the stack frame set up in the prolog and use it in the generation of the
349 // Reserve fixed size block that's big enough to fit any unwind info we can have
350 static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
353 // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
355 UINT UnwindInfoSize(UINT codeSize)
357 if (!m_fProlog) return 0;
359 return c_nUnwindInfoSize;
364 #define MAX_UNWIND_CODE_WORDS 5 /* maximum number of 32-bit words to store unwind codes */
367 // Reserve fixed size block that's big enough to fit any unwind info we can have
368 static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
369 UINT UnwindInfoSize(UINT codeSize)
371 if (!m_fProlog) return 0;
373 return c_nUnwindInfoSize;
376 #endif // TARGET_ARM64
378 #endif // STUBLINKER_GENERATES_UNWIND_INFO
380 CodeRun *AppendNewEmptyCodeRun();
383 // Returns pointer to last CodeElement or NULL.
384 CodeElement *GetLastCodeElement()
386 LIMITED_METHOD_CONTRACT;
387 return m_pCodeElements;
390 // Appends a new CodeElement.
391 VOID AppendCodeElement(CodeElement *pCodeElement);
394 // Calculates the size of the stub code that is allocate
395 // immediately after the stub object. Returns the
396 // total size. GlobalSize contains the size without
398 virtual int CalculateSize(int* globalsize);
400 // Writes out the code element into memory following the
402 bool EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap);
404 CodeRun *GetLastCodeRunIfAny();
406 bool EmitUnwindInfo(Stub* pStubRX, Stub* pStubRW, int globalsize, LoaderHeap* pHeap);
408 #if defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
409 UNWIND_CODE *AllocUnwindInfo (UCHAR Op, UCHAR nExtraSlots = 0);
410 #endif // defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
413 //************************************************************************
415 //************************************************************************
418 // Link pointer for StubLink's list of labels
421 // if FALSE, label refers to some code within the same stub
422 // if TRUE, label refers to some externally supplied address.
425 // if TRUE, means we want the actual address of the label and
426 // not an offset to it
433 // Indicates the position of the label, expressed
434 // as an offset into a CodeRun.
443 LPVOID m_pExternalAddress;
450 NEWSTUB_FL_NONE = 0x00000000,
451 NEWSTUB_FL_INSTANTIATING_METHOD = 0x00000001,
452 NEWSTUB_FL_MULTICAST = 0x00000002,
453 NEWSTUB_FL_EXTERNAL = 0x00000004,
454 NEWSTUB_FL_LOADERHEAP = 0x00000008,
455 NEWSTUB_FL_THUNK = 0x00000010
459 //-------------------------------------------------------------------------
460 // An executable stub. These can only be created by the StubLinker().
461 // Each stub has a reference count (which is maintained in a thread-safe
462 // manner.) When the ref-count goes to zero, the stub automatically
464 //-------------------------------------------------------------------------
465 typedef DPTR(class Stub) PTR_Stub;
466 typedef DPTR(PTR_Stub) PTR_PTR_Stub;
469 friend class CheckDuplicatedStructLayouts;
470 friend class CheckAsmOffsets;
475 MULTICAST_DELEGATE_BIT = 0x80000000,
476 EXTERNAL_ENTRY_BIT = 0x40000000,
477 LOADER_HEAP_BIT = 0x20000000,
478 INSTANTIATING_STUB_BIT = 0x10000000,
479 UNWIND_INFO_BIT = 0x08000000,
480 THUNK_BIT = 0x04000000,
482 CODEBYTES_MASK = THUNK_BIT - 1,
483 MAX_CODEBYTES = CODEBYTES_MASK + 1,
485 static_assert_no_msg(CODEBYTES_MASK < THUNK_BIT);
488 //-------------------------------------------------------------------
490 //-------------------------------------------------------------------
493 //-------------------------------------------------------------------
495 // Returns true if the count went to zero and the stub was deleted
496 //-------------------------------------------------------------------
499 //-------------------------------------------------------------------
500 // Used for throwing out unused stubs from stub caches. This
501 // method cannot be 100% accurate due to race conditions. This
502 // is ok because stub cache management is robust in the face
503 // of missed or premature cleanups.
504 //-------------------------------------------------------------------
505 BOOL HeuristicLooksOrphaned()
507 LIMITED_METHOD_CONTRACT;
508 _ASSERTE(m_signature == kUsedStub);
509 return (m_refcount == 1);
512 //-------------------------------------------------------------------
513 // Used by the debugger to help step through stubs
514 //-------------------------------------------------------------------
515 BOOL IsMulticastDelegate()
517 LIMITED_METHOD_CONTRACT;
518 return (m_numCodeBytesAndFlags & MULTICAST_DELEGATE_BIT) != 0;
521 //-------------------------------------------------------------------
522 // Used by the debugger to help step through stubs
523 //-------------------------------------------------------------------
524 BOOL IsInstantiatingStub()
526 LIMITED_METHOD_CONTRACT;
527 return (m_numCodeBytesAndFlags & INSTANTIATING_STUB_BIT) != 0;
530 //-------------------------------------------------------------------
531 // Used by the debugger to help step through stubs
532 //-------------------------------------------------------------------
533 BOOL IsManagedThunk()
535 LIMITED_METHOD_CONTRACT;
536 return (m_numCodeBytesAndFlags & THUNK_BIT) != 0;
539 //-------------------------------------------------------------------
540 // For stubs which execute user code, a patch offset needs to be set
541 // to tell the debugger how far into the stub code the debugger has
542 // to step until the frame is set up.
543 //-------------------------------------------------------------------
544 void SetPatchOffset(USHORT offset)
546 LIMITED_METHOD_CONTRACT;
547 _ASSERTE(!IsInstantiatingStub());
548 m_data.PatchOffset = offset;
551 //-------------------------------------------------------------------
552 // For stubs which execute user code, a patch offset needs to be set
553 // to tell the debugger how far into the stub code the debugger has
554 // to step until the frame is set up.
555 //-------------------------------------------------------------------
556 USHORT GetPatchOffset()
558 LIMITED_METHOD_CONTRACT;
559 _ASSERTE(!IsInstantiatingStub());
560 return m_data.PatchOffset;
563 //-------------------------------------------------------------------
564 // For stubs which execute user code, a patch offset needs to be set
565 // to tell the debugger how far into the stub code the debugger has
566 // to step until the frame is set up.
567 //-------------------------------------------------------------------
568 TADDR GetPatchAddress()
570 LIMITED_METHOD_CONTRACT;
571 _ASSERTE(!IsInstantiatingStub());
572 return dac_cast<TADDR>(GetEntryPointInternal()) + GetPatchOffset();
575 //-------------------------------------------------------------------
576 // For instantiating methods, the target MethodDesc needs to be set
577 // to tell the debugger where to step through the instantiating method
579 //-------------------------------------------------------------------
580 void SetInstantiatedMethodDesc(PTR_MethodDesc pMD)
582 LIMITED_METHOD_CONTRACT;
583 _ASSERTE(IsInstantiatingStub());
584 m_data.InstantiatedMethod = pMD;
587 //-------------------------------------------------------------------
588 // For instantiating methods, the target MethodDesc needs to be set
589 // to tell the debugger where to step through the instantiating method
591 //-------------------------------------------------------------------
592 PTR_MethodDesc GetInstantiatedMethodDesc()
594 LIMITED_METHOD_CONTRACT;
595 _ASSERTE(IsInstantiatingStub());
596 return m_data.InstantiatedMethod;
599 //-------------------------------------------------------------------
600 // Unwind information.
601 //-------------------------------------------------------------------
603 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
607 LIMITED_METHOD_CONTRACT;
608 return (m_numCodeBytesAndFlags & UNWIND_INFO_BIT) != 0;
611 StubUnwindInfoHeaderSuffix *GetUnwindInfoHeaderSuffix()
621 _ASSERTE(HasUnwindInfo());
623 TADDR info = dac_cast<TADDR>(this);
625 return PTR_StubUnwindInfoHeaderSuffix
626 (info - sizeof(StubUnwindInfoHeaderSuffix));
629 StubUnwindInfoHeader *GetUnwindInfoHeader()
639 _ASSERTE(HasUnwindInfo());
641 StubUnwindInfoHeaderSuffix *pSuffix = GetUnwindInfoHeaderSuffix();
643 TADDR suffixEnd = dac_cast<TADDR>(pSuffix) + sizeof(*pSuffix);
645 return PTR_StubUnwindInfoHeader(suffixEnd -
646 StubUnwindInfoHeader::ComputeAlignedSize(pSuffix->nUnwindInfoSize));
649 #endif // STUBLINKER_GENERATES_UNWIND_INFO
651 //-------------------------------------------------------------------
652 // Returns pointer to the start of the allocation containing this Stub.
653 //-------------------------------------------------------------------
654 TADDR GetAllocationBase();
656 //-------------------------------------------------------------------
657 // Return executable entrypoint after checking the ref count.
658 //-------------------------------------------------------------------
659 PCODE GetEntryPoint()
664 _ASSERTE(m_signature == kUsedStub);
665 _ASSERTE(m_refcount > 0);
667 TADDR pEntryPoint = dac_cast<TADDR>(GetEntryPointInternal());
675 pEntryPoint |= THUMB_CODE;
681 UINT GetNumCodeBytes()
686 return (m_numCodeBytesAndFlags & CODEBYTES_MASK);
689 //-------------------------------------------------------------------
690 // Return start of the stub blob
691 //-------------------------------------------------------------------
697 _ASSERTE(m_signature == kUsedStub);
698 _ASSERTE(m_refcount > 0);
700 return GetEntryPointInternal();
703 //-------------------------------------------------------------------
704 // Return the Stub as in GetEntryPoint and size of the stub+code in bytes
705 // WARNING: Depending on the stub kind this may be just Stub size as
706 // not all stubs have the info about the code size.
707 // It's the caller responsibility to determine that
708 //-------------------------------------------------------------------
709 static Stub* RecoverStubAndSize(PCODE pEntryPoint, DWORD *pSize)
717 PRECONDITION(pEntryPoint && pSize);
721 Stub *pStub = Stub::RecoverStub(pEntryPoint);
722 *pSize = sizeof(Stub) + pStub->GetNumCodeBytes();
726 HRESULT CloneStub(BYTE *pBuffer, DWORD dwBufferSize)
728 LIMITED_METHOD_CONTRACT;
729 if ((pBuffer == NULL) ||
730 (dwBufferSize < (sizeof(*this) + GetNumCodeBytes())))
735 memcpyNoGCRefs(pBuffer, this, sizeof(*this) + GetNumCodeBytes());
736 reinterpret_cast<Stub *>(pBuffer)->m_refcount = 1;
741 //-------------------------------------------------------------------
742 // Reverse GetEntryPoint.
743 //-------------------------------------------------------------------
744 static Stub* RecoverStub(PCODE pEntryPoint)
746 STATIC_CONTRACT_NOTHROW;
747 STATIC_CONTRACT_GC_NOTRIGGER;
749 TADDR pStubData = PCODEToPINSTR(pEntryPoint);
751 Stub *pStub = PTR_Stub(pStubData - sizeof(*pStub));
753 #if !defined(DACCESS_COMPILE)
754 _ASSERTE(pStub->m_signature == kUsedStub);
755 _ASSERTE(pStub->GetEntryPoint() == pEntryPoint);
756 #elif defined(_DEBUG)
757 // If this isn't really a stub we don't want
758 // to continue with it.
759 // TODO: This should be removed once IsStub
760 // can adverstise whether it's safe to call
761 // further StubManager methods.
762 if (pStub->m_signature != kUsedStub ||
763 pStub->GetEntryPoint() != pEntryPoint)
765 DacError(E_INVALIDARG);
771 //-------------------------------------------------------------------
772 // Returns TRUE if entry point is not inside the Stub allocation.
773 //-------------------------------------------------------------------
774 BOOL HasExternalEntryPoint() const
776 LIMITED_METHOD_CONTRACT;
778 return (m_numCodeBytesAndFlags & EXTERNAL_ENTRY_BIT) != 0;
781 //-------------------------------------------------------------------
782 // This creates stubs.
783 //-------------------------------------------------------------------
784 static Stub* NewStub(LoaderHeap *pLoaderHeap, UINT numCodeBytes,
785 DWORD flags = NEWSTUB_FL_NONE
786 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
787 , UINT nUnwindInfoSize = 0
791 static Stub* NewStub(PTR_VOID pCode, DWORD flags = NEWSTUB_FL_NONE);
792 static Stub* NewStub(PCODE pCode, DWORD flags = NEWSTUB_FL_NONE)
794 return NewStub((PTR_VOID)pCode, flags);
797 //-------------------------------------------------------------------
799 //-------------------------------------------------------------------
803 // fMC: Set to true if the stub is a multicast delegate, false otherwise
804 void SetupStub(int numCodeBytes, DWORD flags
805 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
806 , UINT nUnwindInfoSlots
811 //-------------------------------------------------------------------
812 // Return executable entrypoint without checking the ref count.
813 //-------------------------------------------------------------------
814 inline PTR_CBYTE GetEntryPointInternal()
816 LIMITED_METHOD_CONTRACT;
819 _ASSERTE(m_signature == kUsedStub);
822 if (HasExternalEntryPoint())
824 return dac_cast<PTR_BYTE>(*dac_cast<PTR_PCODE>(dac_cast<TADDR>(this) + sizeof(*this)));
828 // StubLink always puts the entrypoint first.
829 return dac_cast<PTR_CBYTE>(this) + sizeof(*this);
834 UINT32 m_numCodeBytesAndFlags;
838 PTR_MethodDesc InstantiatedMethod;
843 kUsedStub = 0x42555453, // 'STUB'
844 kFreedStub = 0x46555453, // 'STUF'
849 //README ALIGNMENT: Enusure code after the Stub struct align to 16-bytes.
850 UINT32 m_pad_code_bytes1;
851 UINT32 m_pad_code_bytes2;
852 UINT32 m_pad_code_bytes3;
856 Stub() = delete; // Stubs are created by NewStub(), not "new".
859 //-------------------------------------------------------------------------
860 // Each platform encodes the "branch" instruction in a different
861 // way. We use objects derived from InstructionFormat to abstract this
862 // information away. InstructionFormats don't contain any variable data
863 // so they should be allocated statically.
865 // Note that StubLinker does not create or define any InstructionFormats.
868 // The following example shows how to define a InstructionFormat for the
869 // X86 jump near instruction which takes on two forms:
871 // EB xx jmp rel8 ;; SHORT JMP (signed 8-bit offset)
872 // E9 xxxxxxxx jmp rel32 ;; NEAR JMP (signed 32-bit offset)
874 // InstructionFormat's provide StubLinker the following information:
876 // RRT.m_allowedSizes
878 // What are the possible sizes that the reference can
879 // take? The X86 jump can take either an 8-bit or 32-bit offset
880 // so this value is set to (k8|k32). StubLinker will try to
881 // use the smallest size possible.
884 // RRT.m_fTreatSizesAsSigned
885 // Sign-extend or zero-extend smallsizes offsets to the platform
886 // code pointer size? For x86, this field is set to TRUE (rel8
887 // is considered signed.)
890 // UINT RRT.GetSizeOfInstruction(refsize, variationCode)
891 // Returns the total size of the instruction in bytes for a given
892 // refsize. For this example:
894 // if (refsize==k8) return 2;
895 // if (refsize==k32) return 5;
898 // UINT RRT.GetSizeOfData(refsize, variationCode)
899 // Returns the total size of the separate data area (if any) that the
900 // instruction needs in bytes for a given refsize. For this example
902 // if (refsize==k32) return 4; else return 0;
904 // The default implem of this returns 0, so CPUs that don't have need
905 // for a separate constant area don't have to worry about it.
908 // BOOL CanReach(refsize, variationcode, fExternal, offset)
909 // Returns whether the instruction with the given variationcode &
910 // refsize can reach the given offset. In the case of External
911 // calls, fExternal is set and offset is the target address. In this case an
912 // implementation should return TRUE only if refsize is big enough to fit a
913 // full machine-sized pointer to anywhere in the address space.
916 // VOID RRT.EmitInstruction(UINT refsize,
917 // __int64 fixedUpReference,
919 // UINT variationCode,
920 // BYTE *pDataBuffer)
922 // Given a chosen size (refsize) and the final offset value
923 // computed by StubLink (fixedUpReference), write out the
924 // instruction into the provided buffer (guaranteed to be
925 // big enough provided you told the truth with GetSizeOfInstruction()).
926 // If needed (e.g. on SH3) a data buffer is also passed in for
927 // storage of constants.
931 // if (refsize==k8) {
932 // pOutBuffer[0] = 0xeb;
933 // pOutBuffer[1] = (__int8)fixedUpReference;
934 // } else if (refsize == k32) {
935 // pOutBuffer[0] = 0xe9;
936 // *((__int32*)(1+pOutBuffer)) = (__int32)fixedUpReference;
938 // CRASH("Bad input.");
941 // VOID RRT.GetHotSpotOffset(UINT refsize, UINT variationCode)
943 // The reference offset is always relative to some IP: this
944 // method tells StubLinker where that IP is relative to the
945 // start of the instruction. For X86, the offset is always
946 // relative to the start of the *following* instruction so
947 // the correct implementation is:
949 // return GetSizeOfInstruction(refsize, variationCode);
951 // Actually, InstructionFormat() provides a default implementation of this
952 // method that does exactly this so X86 need not override this at all.
955 // The extra "variationCode" argument is an __int32 that StubLinker receives
956 // from EmitLabelRef() and passes uninterpreted to each RRT method.
957 // This allows one RRT to handle a family of related instructions,
958 // for example, the family of conditional jumps on the X86.
960 //-------------------------------------------------------------------------
961 class InstructionFormat
966 // if you want to add a size, insert it in-order (e.g. a 18-bit size would
967 // go between k16 and k32) and shift all the higher values up. All values
968 // must be a power of 2 since the get ORed together.
985 #ifdef INSTRFMT_K64SMALL
1013 #ifdef INSTRFMT_K64SMALL
1014 k64Small = (1 << _k64Small),
1019 kAllowAlways= (1 << _kAllowAlways),
1020 kMax = kAllowAlways,
1023 const UINT m_allowedSizes; // OR mask using above "k" values
1024 InstructionFormat(UINT allowedSizes) : m_allowedSizes(allowedSizes)
1026 LIMITED_METHOD_CONTRACT;
1029 virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) = 0;
1030 virtual VOID EmitInstruction(UINT refsize, __int64 fixedUpReference, BYTE *pCodeBufferRX, BYTE *pCodeBufferRW, UINT variationCode, BYTE *pDataBuffer) = 0;
1031 virtual UINT GetHotSpotOffset(UINT refsize, UINT variationCode)
1033 WRAPPER_NO_CONTRACT;
1034 // Default implementation: the offset is added to the
1035 // start of the following instruction.
1036 return GetSizeOfInstruction(refsize, variationCode);
1039 virtual UINT GetSizeOfData(UINT refsize, UINT variationCode)
1041 LIMITED_METHOD_CONTRACT;
1042 // Default implementation: 0 extra bytes needed (most CPUs)
1046 virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset)
1048 LIMITED_METHOD_CONTRACT;
1051 // For external, we don't have enough info to predict
1052 // the offset yet so we only accept if the offset size
1053 // is at least as large as the native pointer size.
1055 case InstructionFormat::k8: // intentional fallthru
1056 case InstructionFormat::k16: // intentional fallthru
1058 case InstructionFormat::k24: // intentional fallthru
1061 case InstructionFormat::k26: // intentional fallthru
1063 return FALSE; // no 8 or 16-bit platforms
1065 case InstructionFormat::k32:
1066 return sizeof(LPVOID) <= 4;
1068 case InstructionFormat::k64:
1069 return sizeof(LPVOID) <= 8;
1071 case InstructionFormat::kAllowAlways:
1081 case InstructionFormat::k8:
1082 return FitsInI1(offset);
1084 case InstructionFormat::k16:
1085 return FitsInI2(offset);
1088 case InstructionFormat::k24:
1089 return FitsInI2(offset>>8);
1093 case InstructionFormat::k26:
1094 return FitsInI2(offset>>10);
1096 case InstructionFormat::k32:
1097 return FitsInI4(offset);
1099 case InstructionFormat::k64:
1100 // intentional fallthru
1102 case InstructionFormat::kAllowAlways:
1117 //-------------------------------------------------------------------------
1118 // This stub cache associates stubs with an integer key. For some clients,
1119 // this might represent the size of the argument stack in some cpu-specific
1120 // units (for the x86, the size is expressed in DWORDS.) For other clients,
1121 // this might take into account the style of stub (e.g. whether it returns
1122 // an object reference or not).
1123 //-------------------------------------------------------------------------
1124 class ArgBasedStubCache
1127 ArgBasedStubCache(UINT fixedSize = NUMFIXEDSLOTS);
1128 ~ArgBasedStubCache();
1130 //-----------------------------------------------------------------
1131 // Retrieves the stub associated with the given key.
1132 //-----------------------------------------------------------------
1133 Stub *GetStub(UINT_PTR key);
1135 //-----------------------------------------------------------------
1136 // Tries to associate the stub with the given key.
1137 // It may fail because another thread might swoop in and
1138 // do the association before you do. Thus, you must use the
1139 // return value stub rather than the pStub.
1140 //-----------------------------------------------------------------
1141 Stub* AttemptToSetStub(UINT_PTR key, Stub *pStub);
1144 // Suggestions for number of slots
1154 VOID Dump(); //Diagnostic dump
1159 // How many low-numbered keys have direct access?
1160 UINT m_numFixedSlots;
1162 // For 'm_numFixedSlots' low-numbered keys, we store them in an array.
1173 // High-numbered keys are stored in a sparse linked list.
1174 SlotEntry *m_pSlotEntries;
1181 #define CPUSTUBLINKER StubLinkerCPU
1183 class NDirectStubLinker;
1184 class CPUSTUBLINKER;
1186 #endif // __stublink_h__