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.
4
5// STUBLINK.H
6//
7
8//
9// A StubLinker object provides a way to link several location-independent
10// code sources into one executable stub, resolving references,
11// and choosing the shortest possible instruction size. The StubLinker
12// abstracts out the notion of a "reference" so it is completely CPU
13// independent. This StubLinker is intended not only to create method
14// stubs but to create the PCode-marshaling stubs for Native/Direct.
15//
16// A StubLinker's typical life-cycle is:
17//
18// 1. Create a new StubLinker (it accumulates state for the stub being
19// generated.)
20// 2. Emit code bytes and references (requiring fixups) into the StubLinker.
21// 3. Call the Link() method to produce the final stub.
22// 4. Destroy the StubLinker.
23//
24// StubLinkers are not multithread-aware: they're intended to be
25// used entirely on a single thread. Also, StubLinker's report errors
26// using COMPlusThrow. StubLinker's do have a destructor: to prevent
27// C++ object unwinding from clashing with COMPlusThrow,
28// you must use COMPLUSCATCH to ensure the StubLinker's cleanup in the
29// event of an exception: the following code would do it:
30//
31// StubLinker stublink;
32// Inner();
33//
34//
35// // Have to separate into inner function because VC++ forbids
36// // mixing __try & local objects in the same function.
37// void Inner() {
38// COMPLUSTRY {
39// ... do stuff ...
40// pLinker->Link();
41// } COMPLUSCATCH {
42// }
43// }
44//
45
46
47// This file should only be included via the platform-specific cgencpu.h.
48
49#include "cgensys.h"
50
51#ifndef __stublink_h__
52#define __stublink_h__
53
54#include "crst.h"
55#include "util.hpp"
56#include "eecontract.h"
57
58//-------------------------------------------------------------------------
59// Forward refs
60//-------------------------------------------------------------------------
61class InstructionFormat;
62class Stub;
63class InterceptStub;
64class CheckDuplicatedStructLayouts;
65class CodeBasedStubCache;
66struct CodeLabel;
67
68struct CodeRun;
69struct LabelRef;
70struct CodeElement;
71struct IntermediateUnwindInfo;
72
73#if !defined(_TARGET_X86_) && !defined(FEATURE_PAL)
74#define STUBLINKER_GENERATES_UNWIND_INFO
75#endif // !_TARGET_X86_ && !FEATURE_PAL
76
77
78#ifdef STUBLINKER_GENERATES_UNWIND_INFO
79
80typedef DPTR(struct StubUnwindInfoHeaderSuffix) PTR_StubUnwindInfoHeaderSuffix;
81struct StubUnwindInfoHeaderSuffix
82{
83 UCHAR nUnwindInfoSize; // Size of unwind info in bytes
84};
85
86// Variable-sized struct that preceeds a Stub when the stub requires unwind
87// information. Followed by a StubUnwindInfoHeaderSuffix.
88typedef DPTR(struct StubUnwindInfoHeader) PTR_StubUnwindInfoHeader;
89struct StubUnwindInfoHeader
90{
91 PTR_StubUnwindInfoHeader pNext;
92 T_RUNTIME_FUNCTION FunctionEntry;
93 UNWIND_INFO UnwindInfo; // variable length
94
95 // Computes the size needed for this variable-sized struct.
96 static SIZE_T ComputeSize(UINT nUnwindInfoSize);
97
98 void Init ();
99
100 bool IsRegistered ();
101};
102
103// List of stub address ranges, in increasing address order.
104struct StubUnwindInfoHeapSegment
105{
106 PBYTE pbBaseAddress;
107 SIZE_T cbSegment;
108 StubUnwindInfoHeader *pUnwindHeaderList;
109 StubUnwindInfoHeapSegment *pNext;
110
111#ifdef _WIN64
112 class UnwindInfoTable* pUnwindInfoTable; // Used to publish unwind info to ETW stack crawler
113#endif
114};
115
116VOID UnregisterUnwindInfoInLoaderHeap (UnlockedLoaderHeap *pHeap);
117
118#endif // STUBLINKER_GENERATES_UNWIND_INFO
119
120
121//-------------------------------------------------------------------------
122// A non-multithreaded object that fixes up and emits one executable stub.
123//-------------------------------------------------------------------------
124class StubLinker
125{
126 public:
127 //---------------------------------------------------------------
128 // Construction
129 //---------------------------------------------------------------
130 StubLinker();
131
132
133 //---------------------------------------------------------------
134 // Create a new undefined label. Label must be assigned to a code
135 // location using EmitLabel() prior to final linking.
136 // Throws exception on failure.
137 //---------------------------------------------------------------
138 CodeLabel* NewCodeLabel();
139
140 //---------------------------------------------------------------
141 // Create a new undefined label for which we want the absolute
142 // address, not offset. Label must be assigned to a code
143 // location using EmitLabel() prior to final linking.
144 // Throws exception on failure.
145 //---------------------------------------------------------------
146 CodeLabel* NewAbsoluteCodeLabel();
147
148 //---------------------------------------------------------------
149 // Combines NewCodeLabel() and EmitLabel() for convenience.
150 // Throws exception on failure.
151 //---------------------------------------------------------------
152 CodeLabel* EmitNewCodeLabel();
153
154
155 //---------------------------------------------------------------
156 // Returns final location of label as an offset from the start
157 // of the stub. Can only be called after linkage.
158 //---------------------------------------------------------------
159 UINT32 GetLabelOffset(CodeLabel *pLabel);
160
161 //---------------------------------------------------------------
162 // Append code bytes.
163 //---------------------------------------------------------------
164 VOID EmitBytes(const BYTE *pBytes, UINT numBytes);
165 VOID Emit8 (unsigned __int8 u8);
166 VOID Emit16(unsigned __int16 u16);
167 VOID Emit32(unsigned __int32 u32);
168 VOID Emit64(unsigned __int64 u64);
169 VOID EmitPtr(const VOID *pval);
170
171 //---------------------------------------------------------------
172 // Emit a UTF8 string
173 //---------------------------------------------------------------
174 VOID EmitUtf8(LPCUTF8 pUTF8)
175 {
176 WRAPPER_NO_CONTRACT;
177
178 LPCUTF8 p = pUTF8;
179 while (*(p++)) {
180 //nothing
181 }
182 EmitBytes((const BYTE *)pUTF8, (unsigned int)(p-pUTF8-1));
183 }
184
185 //---------------------------------------------------------------
186 // Append an instruction containing a reference to a label.
187 //
188 // target - the label being referenced.
189 // instructionFormat - a platform-specific InstructionFormat object
190 // that gives properties about the reference.
191 // variationCode - uninterpreted data passed to the pInstructionFormat methods.
192 //---------------------------------------------------------------
193 VOID EmitLabelRef(CodeLabel* target, const InstructionFormat & instructionFormat, UINT variationCode);
194
195
196 //---------------------------------------------------------------
197 // Sets the label to point to the current "instruction pointer"
198 // It is invalid to call EmitLabel() twice on
199 // the same label.
200 //---------------------------------------------------------------
201 VOID EmitLabel(CodeLabel* pCodeLabel);
202
203 //---------------------------------------------------------------
204 // Emits the patch label for the stub.
205 // Throws exception on failure.
206 //---------------------------------------------------------------
207 void EmitPatchLabel();
208
209 //---------------------------------------------------------------
210 // Create a new label to an external address.
211 // Throws exception on failure.
212 //---------------------------------------------------------------
213 CodeLabel* NewExternalCodeLabel(LPVOID pExternalAddress);
214 CodeLabel* NewExternalCodeLabel(PCODE pExternalAddress)
215 {
216 return NewExternalCodeLabel((LPVOID)pExternalAddress);
217 }
218
219 //---------------------------------------------------------------
220 // Push and Pop can be used to keep track of stack growth.
221 // These should be adjusted by opcodes written to the stream.
222 //
223 // Note that popping & pushing stack size as opcodes are emitted
224 // is naive & may not be accurate in many cases,
225 // so complex stubs may have to manually adjust the stack size.
226 // However it should work for the vast majority of cases we care
227 // about.
228 //---------------------------------------------------------------
229 void Push(UINT size);
230 void Pop(UINT size);
231
232 INT GetStackSize() { LIMITED_METHOD_CONTRACT; return m_stackSize; }
233 void SetStackSize(SHORT size) { LIMITED_METHOD_CONTRACT; m_stackSize = size; }
234
235 void SetDataOnly(BOOL fDataOnly = TRUE) { LIMITED_METHOD_CONTRACT; m_fDataOnly = fDataOnly; }
236
237#ifdef _TARGET_ARM_
238 void DescribeProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs);
239#elif defined(_TARGET_ARM64_)
240 void DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cCalleeSavedRegs, UINT cbStackFrame);
241 UINT GetSavedRegArgsOffset();
242 UINT GetStackFrameSize();
243#endif
244
245 //===========================================================================
246 // Unwind information
247
248 // Records location of preserved or parameter register
249 VOID UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset);
250 VOID UnwindPushedReg (UCHAR reg);
251
252 // Records "sub rsp, xxx"
253 VOID UnwindAllocStack (SHORT FrameSizeIncrement);
254
255 // Records frame pointer register
256 VOID UnwindSetFramePointer (UCHAR reg);
257
258 // In DEBUG, emits a call to m_pUnwindInfoCheckLabel (via
259 // EmitUnwindInfoCheckWorker). Code at that label will call to a
260 // helper that will attempt to RtlVirtualUnwind through the stub. The
261 // helper will preserve ALL registers.
262 VOID EmitUnwindInfoCheck();
263
264#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO) && !defined(CROSSGEN_COMPILE)
265protected:
266
267 // Injects a call to the given label.
268 virtual VOID EmitUnwindInfoCheckWorker (CodeLabel *pCheckLabel) { _ASSERTE(!"override me"); }
269
270 // Emits a call to a helper that will attempt to RtlVirtualUnwind
271 // through the stub. The helper will preserve ALL registers.
272 virtual VOID EmitUnwindInfoCheckSubfunction() { _ASSERTE(!"override me"); }
273#endif
274
275public:
276
277 //---------------------------------------------------------------
278 // Generate the actual stub. The returned stub has a refcount of 1.
279 // No other methods (other than the destructor) should be called
280 // after calling Link().
281 //
282 // Throws exception on failure.
283 //---------------------------------------------------------------
284 Stub *Link(LoaderHeap *heap, DWORD flags = 0);
285
286 //---------------------------------------------------------------
287 // Generate the actual stub. The returned stub has a refcount of 1.
288 // No other methods (other than the destructor) should be called
289 // after calling Link(). The linked stub must have its increment
290 // increased by one prior to calling this method. This method
291 // does not increment the reference count of the interceptee.
292 //
293 // Throws exception on failure.
294 //---------------------------------------------------------------
295 Stub *LinkInterceptor(Stub* interceptee, void *pRealAddr)
296 { WRAPPER_NO_CONTRACT; return LinkInterceptor(NULL,interceptee, pRealAddr); }
297 Stub *LinkInterceptor(LoaderHeap *heap, Stub* interceptee, void *pRealAddr);
298
299 private:
300 CodeElement *m_pCodeElements; // stored in *reverse* order
301 CodeLabel *m_pFirstCodeLabel; // linked list of CodeLabels
302 LabelRef *m_pFirstLabelRef; // linked list of references
303 CodeLabel *m_pPatchLabel; // label of stub patch offset
304 // currently just for multicast
305 // frames.
306 SHORT m_stackSize; // count of pushes/pops
307 CQuickHeap m_quickHeap; // throwaway heap for
308 // labels, and
309 // internals.
310 BOOL m_fDataOnly; // the stub contains only data - does not need FlushInstructionCache
311
312#ifdef _TARGET_ARM_
313protected:
314 BOOL m_fProlog; // True if DescribeProlog has been called
315 UINT m_cCalleeSavedRegs; // Count of callee saved registers (0 == none, 1 == r4, 2 ==
316 // r4-r5 etc. up to 8 == r4-r11)
317 UINT m_cbStackFrame; // Count of bytes in the stack frame (excl of saved regs)
318 BOOL m_fPushArgRegs; // If true, r0-r3 are saved before callee saved regs
319#endif // _TARGET_ARM_
320
321#ifdef _TARGET_ARM64_
322protected:
323 BOOL m_fProlog; // True if DescribeProlog has been called
324 UINT m_cIntRegArgs; // Count of int register arguments (x0 - x7)
325 UINT m_cVecRegArgs; // Count of FP register arguments (v0 - v7)
326 UINT m_cCalleeSavedRegs; // Count of callee saved registers (x19 - x28)
327 UINT m_cbStackSpace; // Additional stack space for return buffer and stack alignment
328#endif // _TARGET_ARM64_
329
330#ifdef STUBLINKER_GENERATES_UNWIND_INFO
331
332#ifdef _DEBUG
333 CodeLabel *m_pUnwindInfoCheckLabel; // subfunction to call to unwind info check helper.
334 // On AMD64, the prologue is restricted to 256
335 // bytes, so this reduces the size of the injected
336 // code from 14 to 5 bytes.
337#endif
338
339#ifdef _TARGET_AMD64_
340 IntermediateUnwindInfo *m_pUnwindInfoList;
341 UINT m_nUnwindSlots; // number of slots to allocate at end, == UNWIND_INFO::CountOfCodes
342 BOOL m_fHaveFramePointer; // indicates stack operations no longer need to be recorded
343
344 //
345 // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
346 //
347 UINT UnwindInfoSize(UINT codeSize)
348 {
349 if (m_nUnwindSlots == 0) return 0;
350
351 return sizeof(T_RUNTIME_FUNCTION) + offsetof(UNWIND_INFO, UnwindCode) + m_nUnwindSlots * sizeof(UNWIND_CODE);
352 }
353#endif // _TARGET_AMD64_
354
355#ifdef _TARGET_ARM_
356#define MAX_UNWIND_CODE_WORDS 5 /* maximum number of 32-bit words to store unwind codes */
357 // Cache information about the stack frame set up in the prolog and use it in the generation of the
358 // epilog.
359private:
360 // Reserve fixed size block that's big enough to fit any unwind info we can have
361 static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
362
363 //
364 // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
365 //
366 UINT UnwindInfoSize(UINT codeSize)
367 {
368 if (!m_fProlog) return 0;
369
370 return c_nUnwindInfoSize;
371 }
372#endif // _TARGET_ARM_
373
374#ifdef _TARGET_ARM64_
375#define MAX_UNWIND_CODE_WORDS 5 /* maximum number of 32-bit words to store unwind codes */
376
377private:
378 // Reserve fixed size block that's big enough to fit any unwind info we can have
379 static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
380 UINT UnwindInfoSize(UINT codeSize)
381 {
382 if (!m_fProlog) return 0;
383
384 return c_nUnwindInfoSize;
385 }
386
387#endif // _TARGET_ARM64_
388
389#endif // STUBLINKER_GENERATES_UNWIND_INFO
390
391 CodeRun *AppendNewEmptyCodeRun();
392
393
394 // Returns pointer to last CodeElement or NULL.
395 CodeElement *GetLastCodeElement()
396 {
397 LIMITED_METHOD_CONTRACT;
398 return m_pCodeElements;
399 }
400
401 // Appends a new CodeElement.
402 VOID AppendCodeElement(CodeElement *pCodeElement);
403
404
405 // Calculates the size of the stub code that is allocate
406 // immediately after the stub object. Returns the
407 // total size. GlobalSize contains the size without
408 // that data part.
409 virtual int CalculateSize(int* globalsize);
410
411 // Writes out the code element into memory following the
412 // stub object.
413 bool EmitStub(Stub* pStub, int globalsize, LoaderHeap* pHeap);
414
415 CodeRun *GetLastCodeRunIfAny();
416
417 bool EmitUnwindInfo(Stub* pStub, int globalsize, LoaderHeap* pHeap);
418
419#if defined(_TARGET_AMD64_) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
420 UNWIND_CODE *AllocUnwindInfo (UCHAR Op, UCHAR nExtraSlots = 0);
421#endif // defined(_TARGET_AMD64_) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
422};
423
424//************************************************************************
425// CodeLabel
426//************************************************************************
427struct CodeLabel
428{
429 // Link pointer for StubLink's list of labels
430 CodeLabel *m_next;
431
432 // if FALSE, label refers to some code within the same stub
433 // if TRUE, label refers to some externally supplied address.
434 BOOL m_fExternal;
435
436 // if TRUE, means we want the actual address of the label and
437 // not an offset to it
438 BOOL m_fAbsolute;
439
440 union {
441
442 // Internal
443 struct {
444 // Indicates the position of the label, expressed
445 // as an offset into a CodeRun.
446 CodeRun *m_pCodeRun;
447 UINT m_localOffset;
448
449 } i;
450
451
452 // External
453 struct {
454 LPVOID m_pExternalAddress;
455 } e;
456 };
457};
458
459enum NewStubFlags
460{
461 NEWSTUB_FL_INTERCEPT = 0x00000001,
462 NEWSTUB_FL_MULTICAST = 0x00000002,
463 NEWSTUB_FL_EXTERNAL = 0x00000004,
464 NEWSTUB_FL_LOADERHEAP = 0x00000008
465};
466
467
468//-------------------------------------------------------------------------
469// An executable stub. These can only be created by the StubLinker().
470// Each stub has a reference count (which is maintained in a thread-safe
471// manner.) When the ref-count goes to zero, the stub automatically
472// cleans itself up.
473//-------------------------------------------------------------------------
474typedef DPTR(class Stub) PTR_Stub;
475typedef DPTR(PTR_Stub) PTR_PTR_Stub;
476class Stub
477{
478 friend class CheckDuplicatedStructLayouts;
479 friend class CheckAsmOffsets;
480
481 protected:
482 enum
483 {
484 MULTICAST_DELEGATE_BIT = 0x80000000,
485 EXTERNAL_ENTRY_BIT = 0x40000000,
486 LOADER_HEAP_BIT = 0x20000000,
487 INTERCEPT_BIT = 0x10000000,
488 UNWIND_INFO_BIT = 0x08000000,
489
490 PATCH_OFFSET_MASK = UNWIND_INFO_BIT - 1,
491 MAX_PATCH_OFFSET = PATCH_OFFSET_MASK + 1,
492 };
493
494 static_assert_no_msg(PATCH_OFFSET_MASK < UNWIND_INFO_BIT);
495
496 public:
497 //-------------------------------------------------------------------
498 // Inc the refcount.
499 //-------------------------------------------------------------------
500 VOID IncRef();
501
502
503 //-------------------------------------------------------------------
504 // Dec the refcount.
505 // Returns true if the count went to zero and the stub was deleted
506 //-------------------------------------------------------------------
507 BOOL DecRef();
508
509
510
511 //-------------------------------------------------------------------
512 // Used for throwing out unused stubs from stub caches. This
513 // method cannot be 100% accurate due to race conditions. This
514 // is ok because stub cache management is robust in the face
515 // of missed or premature cleanups.
516 //-------------------------------------------------------------------
517 BOOL HeuristicLooksOrphaned()
518 {
519 LIMITED_METHOD_CONTRACT;
520 _ASSERTE(m_signature == kUsedStub);
521 return (m_refcount == 1);
522 }
523
524 //-------------------------------------------------------------------
525 // Used by the debugger to help step through stubs
526 //-------------------------------------------------------------------
527 BOOL IsIntercept()
528 {
529 LIMITED_METHOD_CONTRACT;
530 return (m_patchOffset & INTERCEPT_BIT) != 0;
531 }
532
533 BOOL IsMulticastDelegate()
534 {
535 LIMITED_METHOD_CONTRACT;
536 return (m_patchOffset & MULTICAST_DELEGATE_BIT) != 0;
537 }
538
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 USHORT GetPatchOffset()
545 {
546 LIMITED_METHOD_CONTRACT;
547
548 return (USHORT)(m_patchOffset & PATCH_OFFSET_MASK);
549 }
550
551 void SetPatchOffset(USHORT offset)
552 {
553 LIMITED_METHOD_CONTRACT;
554 _ASSERTE(GetPatchOffset() == 0);
555 m_patchOffset |= offset;
556 _ASSERTE(GetPatchOffset() == offset);
557 }
558
559 TADDR GetPatchAddress()
560 {
561 WRAPPER_NO_CONTRACT;
562
563 return dac_cast<TADDR>(GetEntryPointInternal()) + GetPatchOffset();
564 }
565
566 //-------------------------------------------------------------------
567 // Unwind information.
568 //-------------------------------------------------------------------
569
570#ifdef STUBLINKER_GENERATES_UNWIND_INFO
571
572 BOOL HasUnwindInfo()
573 {
574 LIMITED_METHOD_CONTRACT;
575 return (m_patchOffset & UNWIND_INFO_BIT) != 0;
576 }
577
578 StubUnwindInfoHeaderSuffix *GetUnwindInfoHeaderSuffix()
579 {
580 CONTRACTL
581 {
582 NOTHROW;
583 GC_NOTRIGGER;
584 FORBID_FAULT;
585 SO_TOLERANT;
586 }
587 CONTRACTL_END
588
589 _ASSERTE(HasUnwindInfo());
590
591 TADDR info = dac_cast<TADDR>(this);
592
593 if (IsIntercept())
594 {
595 info -= 2 * sizeof(TADDR);
596 }
597
598 return PTR_StubUnwindInfoHeaderSuffix
599 (info - sizeof(StubUnwindInfoHeaderSuffix));
600 }
601
602 StubUnwindInfoHeader *GetUnwindInfoHeader()
603 {
604 CONTRACTL
605 {
606 NOTHROW;
607 GC_NOTRIGGER;
608 FORBID_FAULT;
609 }
610 CONTRACTL_END
611
612 StubUnwindInfoHeaderSuffix *pSuffix = GetUnwindInfoHeaderSuffix();
613
614 TADDR suffixEnd = dac_cast<TADDR>(pSuffix) + sizeof(*pSuffix);
615
616 return PTR_StubUnwindInfoHeader(suffixEnd -
617 StubUnwindInfoHeader::ComputeSize(pSuffix->nUnwindInfoSize));
618 }
619
620#endif // STUBLINKER_GENERATES_UNWIND_INFO
621
622 //-------------------------------------------------------------------
623 // Returns pointer to the start of the allocation containing this Stub.
624 //-------------------------------------------------------------------
625 TADDR GetAllocationBase();
626
627 //-------------------------------------------------------------------
628 // Return executable entrypoint after checking the ref count.
629 //-------------------------------------------------------------------
630 PCODE GetEntryPoint()
631 {
632 WRAPPER_NO_CONTRACT;
633 SUPPORTS_DAC;
634
635 _ASSERTE(m_signature == kUsedStub);
636 _ASSERTE(m_refcount > 0);
637
638 TADDR pEntryPoint = dac_cast<TADDR>(GetEntryPointInternal());
639
640#ifdef _TARGET_ARM_
641
642#ifndef THUMB_CODE
643#define THUMB_CODE 1
644#endif
645
646 pEntryPoint |= THUMB_CODE;
647#endif
648
649 return pEntryPoint;
650 }
651
652 UINT GetNumCodeBytes()
653 {
654 WRAPPER_NO_CONTRACT;
655 SUPPORTS_DAC;
656
657 return m_numCodeBytes;
658 }
659
660 //-------------------------------------------------------------------
661 // Return start of the stub blob
662 //-------------------------------------------------------------------
663 PTR_CBYTE GetBlob()
664 {
665 WRAPPER_NO_CONTRACT;
666 SUPPORTS_DAC;
667
668 _ASSERTE(m_signature == kUsedStub);
669 _ASSERTE(m_refcount > 0);
670
671 return GetEntryPointInternal();
672 }
673
674 //-------------------------------------------------------------------
675 // Return the Stub as in GetEntryPoint and size of the stub+code in bytes
676 // WARNING: Depending on the stub kind this may be just Stub size as
677 // not all stubs have the info about the code size.
678 // It's the caller responsibility to determine that
679 //-------------------------------------------------------------------
680 static Stub* RecoverStubAndSize(PCODE pEntryPoint, DWORD *pSize)
681 {
682 CONTRACT(Stub*)
683 {
684 NOTHROW;
685 GC_NOTRIGGER;
686 MODE_ANY;
687
688 PRECONDITION(pEntryPoint && pSize);
689 }
690 CONTRACT_END;
691
692 Stub *pStub = Stub::RecoverStub(pEntryPoint);
693 *pSize = sizeof(Stub) + pStub->m_numCodeBytes;
694 RETURN pStub;
695 }
696
697 HRESULT CloneStub(BYTE *pBuffer, DWORD dwBufferSize)
698 {
699 LIMITED_METHOD_CONTRACT;
700 if ((pBuffer == NULL) ||
701 (dwBufferSize < (sizeof(*this) + m_numCodeBytes)))
702 {
703 return E_INVALIDARG;
704 }
705
706 memcpyNoGCRefs(pBuffer, this, sizeof(*this) + m_numCodeBytes);
707 reinterpret_cast<Stub *>(pBuffer)->m_refcount = 1;
708
709 return S_OK;
710 }
711
712 //-------------------------------------------------------------------
713 // Reverse GetEntryPoint.
714 //-------------------------------------------------------------------
715 static Stub* RecoverStub(PCODE pEntryPoint)
716 {
717 STATIC_CONTRACT_NOTHROW;
718 STATIC_CONTRACT_GC_NOTRIGGER;
719
720 TADDR pStubData = PCODEToPINSTR(pEntryPoint);
721
722 Stub *pStub = PTR_Stub(pStubData - sizeof(*pStub));
723
724#if !defined(DACCESS_COMPILE)
725 _ASSERTE(pStub->m_signature == kUsedStub);
726 _ASSERTE(pStub->GetEntryPoint() == pEntryPoint);
727#elif defined(_DEBUG)
728 // If this isn't really a stub we don't want
729 // to continue with it.
730 // TODO: This should be removed once IsStub
731 // can adverstise whether it's safe to call
732 // further StubManager methods.
733 if (pStub->m_signature != kUsedStub ||
734 pStub->GetEntryPoint() != pEntryPoint)
735 {
736 DacError(E_INVALIDARG);
737 }
738#endif
739 return pStub;
740 }
741
742 //-------------------------------------------------------------------
743 // Returns TRUE if entry point is not inside the Stub allocation.
744 //-------------------------------------------------------------------
745 BOOL HasExternalEntryPoint() const
746 {
747 LIMITED_METHOD_CONTRACT;
748
749 return (m_patchOffset & EXTERNAL_ENTRY_BIT) != 0;
750 }
751
752 //-------------------------------------------------------------------
753 // This is the guy that creates stubs.
754 //-------------------------------------------------------------------
755 static Stub* NewStub(LoaderHeap *pLoaderHeap, UINT numCodeBytes,
756 DWORD flags = 0
757#ifdef STUBLINKER_GENERATES_UNWIND_INFO
758 , UINT nUnwindInfoSize = 0
759#endif
760 );
761
762 static Stub* NewStub(PTR_VOID pCode, DWORD flags = 0);
763 static Stub* NewStub(PCODE pCode, DWORD flags = 0)
764 {
765 return NewStub((PTR_VOID)pCode, flags);
766 }
767
768 //-------------------------------------------------------------------
769 // One-time init
770 //-------------------------------------------------------------------
771 static void Init();
772
773 protected:
774 // fMC: Set to true if the stub is a multicast delegate, false otherwise
775 void SetupStub(int numCodeBytes, DWORD flags
776#ifdef STUBLINKER_GENERATES_UNWIND_INFO
777 , UINT nUnwindInfoSlots
778#endif
779 );
780 void DeleteStub();
781
782 //-------------------------------------------------------------------
783 // Return executable entrypoint without checking the ref count.
784 //-------------------------------------------------------------------
785 inline PTR_CBYTE GetEntryPointInternal()
786 {
787 LIMITED_METHOD_CONTRACT;
788 SUPPORTS_DAC;
789
790 _ASSERTE(m_signature == kUsedStub);
791
792
793 if (HasExternalEntryPoint())
794 {
795 return dac_cast<PTR_BYTE>(*dac_cast<PTR_PCODE>(dac_cast<TADDR>(this) + sizeof(*this)));
796 }
797 else
798 {
799 // StubLink always puts the entrypoint first.
800 return dac_cast<PTR_CBYTE>(this) + sizeof(*this);
801 }
802 }
803
804 ULONG m_refcount;
805 ULONG m_patchOffset;
806
807 UINT m_numCodeBytes;
808
809#ifdef _DEBUG
810 enum {
811 kUsedStub = 0x42555453, // 'STUB'
812 kFreedStub = 0x46555453, // 'STUF'
813 };
814
815 UINT32 m_signature;
816#else
817#ifdef _WIN64
818 //README ALIGNEMENT: in retail mode UINT m_numCodeBytes does not align to 16byte for the code
819 // after the Stub struct. This is to pad properly
820 UINT m_pad_code_bytes;
821#endif // _WIN64
822#endif // _DEBUG
823
824#ifdef _DEBUG
825 Stub() // Stubs are created by NewStub(), not "new". Hide the
826 { LIMITED_METHOD_CONTRACT; } // constructor to enforce this.
827#endif
828
829};
830
831
832/*
833 * The InterceptStub hides a reference to the real stub at a negative offset.
834 * When this stub is deleted it decrements the real stub cleaning it up as
835 * well. The InterceptStub is created by the Stublinker.
836 *
837 * <TODO>@TODO: Intercepted stubs need have a routine that will find the
838 * last real stub in the chain.</TODO>
839 * The stubs are linked - GetInterceptedStub will return either
840 * a pointer to the next intercept stub (if there is one), or NULL,
841 * indicating end-of-chain. GetRealAddr will return the address of
842 * the "real" code, which may, in fact, be another thunk (for example),
843 * and thus should be traced as well.
844 */
845
846typedef DPTR(class InterceptStub) PTR_InterceptStub;
847class InterceptStub : public Stub
848{
849 friend class Stub;
850 public:
851 //-------------------------------------------------------------------
852 // This is the guy that creates stubs.
853 //-------------------------------------------------------------------
854 static Stub* NewInterceptedStub(LoaderHeap *pHeap,
855 UINT numCodeBytes,
856 Stub* interceptee,
857 void* pRealAddr
858#ifdef STUBLINKER_GENERATES_UNWIND_INFO
859 , UINT nUnwindInfoSize = 0
860#endif
861 );
862
863 //---------------------------------------------------------------
864 // Expose key offsets and values for stub generation.
865 //---------------------------------------------------------------
866 int GetNegativeOffset()
867 {
868 LIMITED_METHOD_CONTRACT;
869 return sizeof(TADDR) + GetNegativeOffsetRealAddr();
870 }
871
872 PTR_PTR_Stub GetInterceptedStub()
873 {
874 LIMITED_METHOD_CONTRACT;
875 return dac_cast<PTR_PTR_Stub>(
876 dac_cast<TADDR>(this) - GetNegativeOffset());
877 }
878
879 int GetNegativeOffsetRealAddr()
880 {
881 LIMITED_METHOD_CONTRACT;
882 return sizeof(TADDR);
883 }
884
885 PTR_TADDR GetRealAddr()
886 {
887 LIMITED_METHOD_CONTRACT;
888 return dac_cast<PTR_TADDR>(
889 dac_cast<TADDR>(this) - GetNegativeOffsetRealAddr());
890 }
891
892 static Stub* NewInterceptedStub(void* pCode,
893 Stub* interceptee,
894 void* pRealAddr);
895
896protected:
897 void ReleaseInterceptedStub();
898
899#ifdef _DEBUG
900 InterceptStub() // Intercept stubs are only created by NewInterceptedStub.
901 { LIMITED_METHOD_CONTRACT; }
902#endif
903};
904
905//-------------------------------------------------------------------------
906// Each platform encodes the "branch" instruction in a different
907// way. We use objects derived from InstructionFormat to abstract this
908// information away. InstructionFormats don't contain any variable data
909// so they should be allocated statically.
910//
911// Note that StubLinker does not create or define any InstructionFormats.
912// The client does.
913//
914// The following example shows how to define a InstructionFormat for the
915// X86 jump near instruction which takes on two forms:
916//
917// EB xx jmp rel8 ;; SHORT JMP (signed 8-bit offset)
918// E9 xxxxxxxx jmp rel32 ;; NEAR JMP (signed 32-bit offset)
919//
920// InstructionFormat's provide StubLinker the following information:
921//
922// RRT.m_allowedSizes
923//
924// What are the possible sizes that the reference can
925// take? The X86 jump can take either an 8-bit or 32-bit offset
926// so this value is set to (k8|k32). StubLinker will try to
927// use the smallest size possible.
928//
929//
930// RRT.m_fTreatSizesAsSigned
931// Sign-extend or zero-extend smallsizes offsets to the platform
932// code pointer size? For x86, this field is set to TRUE (rel8
933// is considered signed.)
934//
935//
936// UINT RRT.GetSizeOfInstruction(refsize, variationCode)
937// Returns the total size of the instruction in bytes for a given
938// refsize. For this example:
939//
940// if (refsize==k8) return 2;
941// if (refsize==k32) return 5;
942//
943//
944// UINT RRT.GetSizeOfData(refsize, variationCode)
945// Returns the total size of the seperate data area (if any) that the
946// instruction needs in bytes for a given refsize. For this example
947// on the SH3
948// if (refsize==k32) return 4; else return 0;
949//
950// The default implem of this returns 0, so CPUs that don't have need
951// for a seperate constant area don't have to worry about it.
952//
953//
954// BOOL CanReach(refsize, variationcode, fExternal, offset)
955// Returns whether the instruction with the given variationcode &
956// refsize can reach the given offset. In the case of External
957// calls, fExternal is set and offset is the target address. In this case an
958// implementation should return TRUE only if refsize is big enough to fit a
959// full machine-sized pointer to anywhere in the address space.
960//
961//
962// VOID RRT.EmitInstruction(UINT refsize,
963// __int64 fixedUpReference,
964// BYTE *pOutBuffer,
965// UINT variationCode,
966// BYTE *pDataBuffer)
967//
968// Given a chosen size (refsize) and the final offset value
969// computed by StubLink (fixedUpReference), write out the
970// instruction into the provided buffer (guaranteed to be
971// big enough provided you told the truth with GetSizeOfInstruction()).
972// If needed (e.g. on SH3) a data buffer is also passed in for
973// storage of constants.
974//
975// For x86 jmp near:
976//
977// if (refsize==k8) {
978// pOutBuffer[0] = 0xeb;
979// pOutBuffer[1] = (__int8)fixedUpReference;
980// } else if (refsize == k32) {
981// pOutBuffer[0] = 0xe9;
982// *((__int32*)(1+pOutBuffer)) = (__int32)fixedUpReference;
983// } else {
984// CRASH("Bad input.");
985// }
986//
987// VOID RRT.GetHotSpotOffset(UINT refsize, UINT variationCode)
988//
989// The reference offset is always relative to some IP: this
990// method tells StubLinker where that IP is relative to the
991// start of the instruction. For X86, the offset is always
992// relative to the start of the *following* instruction so
993// the correct implementation is:
994//
995// return GetSizeOfInstruction(refsize, variationCode);
996//
997// Actually, InstructionFormat() provides a default implementation of this
998// method that does exactly this so X86 need not override this at all.
999//
1000//
1001// The extra "variationCode" argument is an __int32 that StubLinker receives
1002// from EmitLabelRef() and passes uninterpreted to each RRT method.
1003// This allows one RRT to handle a family of related instructions,
1004// for example, the family of conditional jumps on the X86.
1005//
1006//-------------------------------------------------------------------------
1007class InstructionFormat
1008{
1009 private:
1010 enum
1011 {
1012 // if you want to add a size, insert it in-order (e.g. a 18-bit size would
1013 // go between k16 and k32) and shift all the higher values up. All values
1014 // must be a power of 2 since the get ORed together.
1015
1016 _k8,
1017#ifdef INSTRFMT_K9
1018 _k9,
1019#endif
1020#ifdef INSTRFMT_K13
1021 _k13,
1022#endif
1023 _k16,
1024#ifdef INSTRFMT_K24
1025 _k24,
1026#endif
1027#ifdef INSTRFMT_K26
1028 _k26,
1029#endif
1030 _k32,
1031#ifdef INSTRFMT_K64SMALL
1032 _k64Small,
1033#endif
1034#ifdef INSTRFMT_K64
1035 _k64,
1036#endif
1037 _kAllowAlways,
1038 };
1039
1040 public:
1041
1042 enum
1043 {
1044 k8 = (1 << _k8),
1045#ifdef INSTRFMT_K9
1046 k9 = (1 << _k9),
1047#endif
1048#ifdef INSTRFMT_K13
1049 k13 = (1 << _k13),
1050#endif
1051 k16 = (1 << _k16),
1052#ifdef INSTRFMT_K24
1053 k24 = (1 << _k24),
1054#endif
1055#ifdef INSTRFMT_K26
1056 k26 = (1 << _k26),
1057#endif
1058 k32 = (1 << _k32),
1059#ifdef INSTRFMT_K64SMALL
1060 k64Small = (1 << _k64Small),
1061#endif
1062#ifdef INSTRFMT_K64
1063 k64 = (1 << _k64),
1064#endif
1065 kAllowAlways= (1 << _kAllowAlways),
1066 kMax = kAllowAlways,
1067 };
1068
1069 const UINT m_allowedSizes; // OR mask using above "k" values
1070 InstructionFormat(UINT allowedSizes) : m_allowedSizes(allowedSizes)
1071 {
1072 LIMITED_METHOD_CONTRACT;
1073 }
1074
1075 virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) = 0;
1076 virtual VOID EmitInstruction(UINT refsize, __int64 fixedUpReference, BYTE *pCodeBuffer, UINT variationCode, BYTE *pDataBuffer) = 0;
1077 virtual UINT GetHotSpotOffset(UINT refsize, UINT variationCode)
1078 {
1079 WRAPPER_NO_CONTRACT;
1080 // Default implementation: the offset is added to the
1081 // start of the following instruction.
1082 return GetSizeOfInstruction(refsize, variationCode);
1083 }
1084
1085 virtual UINT GetSizeOfData(UINT refsize, UINT variationCode)
1086 {
1087 LIMITED_METHOD_CONTRACT;
1088 // Default implementation: 0 extra bytes needed (most CPUs)
1089 return 0;
1090 }
1091
1092 virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset)
1093 {
1094 LIMITED_METHOD_CONTRACT;
1095
1096 if (fExternal) {
1097 // For external, we don't have enough info to predict
1098 // the offset yet so we only accept if the offset size
1099 // is at least as large as the native pointer size.
1100 switch(refsize) {
1101 case InstructionFormat::k8: // intentional fallthru
1102 case InstructionFormat::k16: // intentional fallthru
1103#ifdef INSTRFMT_K24
1104 case InstructionFormat::k24: // intentional fallthru
1105#endif
1106#ifdef INSTRFMT_K26
1107 case InstructionFormat::k26: // intentional fallthru
1108#endif
1109 return FALSE; // no 8 or 16-bit platforms
1110
1111 case InstructionFormat::k32:
1112 return sizeof(LPVOID) <= 4;
1113#ifdef INSTRFMT_K64
1114 case InstructionFormat::k64:
1115 return sizeof(LPVOID) <= 8;
1116#endif
1117 case InstructionFormat::kAllowAlways:
1118 return TRUE;
1119
1120 default:
1121 _ASSERTE(0);
1122 return FALSE;
1123 }
1124 } else {
1125 switch(refsize)
1126 {
1127 case InstructionFormat::k8:
1128 return FitsInI1(offset);
1129
1130 case InstructionFormat::k16:
1131 return FitsInI2(offset);
1132
1133#ifdef INSTRFMT_K24
1134 case InstructionFormat::k24:
1135 return FitsInI2(offset>>8);
1136#endif
1137
1138#ifdef INSTRFMT_K26
1139 case InstructionFormat::k26:
1140 return FitsInI2(offset>>10);
1141#endif
1142 case InstructionFormat::k32:
1143 return FitsInI4(offset);
1144#ifdef INSTRFMT_K64
1145 case InstructionFormat::k64:
1146 // intentional fallthru
1147#endif
1148 case InstructionFormat::kAllowAlways:
1149 return TRUE;
1150 default:
1151 _ASSERTE(0);
1152 return FALSE;
1153
1154 }
1155 }
1156 }
1157};
1158
1159
1160
1161
1162
1163//-------------------------------------------------------------------------
1164// This stub cache associates stubs with an integer key. For some clients,
1165// this might represent the size of the argument stack in some cpu-specific
1166// units (for the x86, the size is expressed in DWORDS.) For other clients,
1167// this might take into account the style of stub (e.g. whether it returns
1168// an object reference or not).
1169//-------------------------------------------------------------------------
1170class ArgBasedStubCache
1171{
1172 public:
1173 ArgBasedStubCache(UINT fixedSize = NUMFIXEDSLOTS);
1174 ~ArgBasedStubCache();
1175
1176 //-----------------------------------------------------------------
1177 // Retrieves the stub associated with the given key.
1178 //-----------------------------------------------------------------
1179 Stub *GetStub(UINT_PTR key);
1180
1181 //-----------------------------------------------------------------
1182 // Tries to associate the stub with the given key.
1183 // It may fail because another thread might swoop in and
1184 // do the association before you do. Thus, you must use the
1185 // return value stub rather than the pStub.
1186 //-----------------------------------------------------------------
1187 Stub* AttemptToSetStub(UINT_PTR key, Stub *pStub);
1188
1189
1190 // Suggestions for number of slots
1191 enum {
1192 #ifdef _DEBUG
1193 NUMFIXEDSLOTS = 3,
1194 #else
1195 NUMFIXEDSLOTS = 16,
1196 #endif
1197 };
1198
1199#ifdef _DEBUG
1200 VOID Dump(); //Diagnostic dump
1201#endif
1202
1203 private:
1204
1205 // How many low-numbered keys have direct access?
1206 UINT m_numFixedSlots;
1207
1208 // For 'm_numFixedSlots' low-numbered keys, we store them in an array.
1209 Stub **m_aStub;
1210
1211
1212 struct SlotEntry
1213 {
1214 Stub *m_pStub;
1215 UINT_PTR m_key;
1216 SlotEntry *m_pNext;
1217 };
1218
1219 // High-numbered keys are stored in a sparse linked list.
1220 SlotEntry *m_pSlotEntries;
1221
1222
1223 Crst m_crst;
1224};
1225
1226
1227#define CPUSTUBLINKER StubLinkerCPU
1228
1229class NDirectStubLinker;
1230class CPUSTUBLINKER;
1231
1232#endif // __stublink_h__
1233