Skip to content

Commit d5325b2

Browse files
committed
retaddr
1 parent 3f0d358 commit d5325b2

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

src/coreclr/nativeaot/Runtime/unix/UnixNativeCodeManager.cpp

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,104 @@ bool UnixNativeCodeManager::UnwindStackFrame(MethodInfo * pMethodInfo,
289289
return true;
290290
}
291291

292+
// Convert the return kind that was encoded by RyuJIT to the
293+
// enum used by the runtime.
294+
GCRefKind GetGcRefKind(ReturnKind returnKind)
295+
{
296+
static_assert((GCRefKind)ReturnKind::RT_Scalar == GCRK_Scalar, "ReturnKind::RT_Scalar does not match GCRK_Scalar");
297+
static_assert((GCRefKind)ReturnKind::RT_Object == GCRK_Object, "ReturnKind::RT_Object does not match GCRK_Object");
298+
static_assert((GCRefKind)ReturnKind::RT_ByRef == GCRK_Byref, "ReturnKind::RT_ByRef does not match GCRK_Byref");
299+
ASSERT((returnKind == RT_Scalar) || (returnKind == RT_Object) || (returnKind == RT_ByRef));
300+
301+
return (GCRefKind)returnKind;
302+
}
303+
292304
bool UnixNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodInfo,
293305
REGDISPLAY * pRegisterSet, // in
294306
PTR_PTR_VOID * ppvRetAddrLocation, // out
295307
GCRefKind * pRetValueKind) // out
296308
{
297-
// @TODO: GetReturnAddressHijackInfo
309+
UnixNativeMethodInfo* pNativeMethodInfo = (UnixNativeMethodInfo*)pMethodInfo;
310+
311+
PTR_UInt8 p = pNativeMethodInfo->pMainLSDA;
312+
313+
uint8_t unwindBlockFlags = *p++;
314+
315+
if ((unwindBlockFlags & UBF_FUNC_HAS_ASSOCIATED_DATA) != 0)
316+
p += sizeof(int32_t);
317+
318+
// Check whether this is a funclet
319+
if ((unwindBlockFlags & UBF_FUNC_KIND_MASK) != UBF_FUNC_KIND_ROOT)
320+
return false;
321+
322+
// Skip hijacking a reverse-pinvoke method - it doesn't get us much because we already synchronize
323+
// with the GC on the way back to native code.
324+
if ((unwindBlockFlags & UBF_FUNC_REVERSE_PINVOKE) != 0)
325+
return false;
326+
327+
if ((unwindBlockFlags & UBF_FUNC_HAS_EHINFO) != 0)
328+
p += sizeof(int32_t);
329+
330+
// Decode the GC info for the current method to determine its return type
331+
GcInfoDecoderFlags flags = DECODE_RETURN_KIND;
332+
#if defined(TARGET_ARM) || defined(TARGET_ARM64)
333+
flags = (GcInfoDecoderFlags)(flags | DECODE_HAS_TAILCALLS);
334+
#endif // TARGET_ARM || TARGET_ARM64
335+
GcInfoDecoder decoder(GCInfoToken(p), flags);
336+
337+
GCRefKind gcRefKind = GetGcRefKind(decoder.GetReturnKind());
338+
339+
// Unwind the current method context to the caller's context to get its stack pointer
340+
// and obtain the location of the return address on the stack
341+
#if defined(TARGET_AMD64)
342+
343+
if (!VirtualUnwind(pRegisterSet))
344+
{
345+
return false;
346+
}
347+
348+
*ppvRetAddrLocation = (PTR_PTR_VOID)(pRegisterSet->GetSP() - sizeof(TADDR));
349+
*pRetValueKind = gcRefKind;
350+
return true;
351+
352+
#elif defined(TARGET_ARM64)
353+
354+
if (decoder.HasTailCalls())
355+
{
356+
// Do not hijack functions that have tail calls, since there are two problems:
357+
// 1. When a function that tail calls another one is hijacked, the LR may be
358+
// stored at a different location in the stack frame of the tail call target.
359+
// So just by performing tail call, the hijacked location becomes invalid and
360+
// unhijacking would corrupt stack by writing to that location.
361+
// 2. There is a small window after the caller pops LR from the stack in its
362+
// epilog and before the tail called function pushes LR in its prolog when
363+
// the hijacked return address would not be not on the stack and so we would
364+
// not be able to unhijack.
365+
return false;
366+
}
367+
368+
PTR_UIntNative pLR = pRegisterSet->pLR;
369+
if (!VirtualUnwind(pRegisterSet))
370+
{
371+
return false;
372+
}
373+
374+
if (pRegisterSet->pLR == pLR)
375+
{
376+
// This is the case when we are either:
377+
//
378+
// 1) In a leaf method that does not push LR on stack, OR
379+
// 2) In the prolog/epilog of a non-leaf method that has not yet pushed LR on stack
380+
// or has LR already popped off.
381+
return false;
382+
}
383+
384+
*ppvRetAddrLocation = (PTR_PTR_VOID)pRegisterSet->pLR;
385+
*pRetValueKind = gcRefKind;
386+
return true;
387+
#else
298388
return false;
389+
#endif // defined(TARGET_AMD64)
299390
}
300391

301392
PTR_VOID UnixNativeCodeManager::RemapHardwareFaultToGCSafePoint(MethodInfo * pMethodInfo, PTR_VOID controlPC)

src/coreclr/nativeaot/Runtime/windows/CoffNativeCodeManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ GCRefKind GetGcRefKind(ReturnKind returnKind)
683683
static_assert((GCRefKind)ReturnKind::RT_Scalar == GCRK_Scalar, "ReturnKind::RT_Scalar does not match GCRK_Scalar");
684684
static_assert((GCRefKind)ReturnKind::RT_Object == GCRK_Object, "ReturnKind::RT_Object does not match GCRK_Object");
685685
static_assert((GCRefKind)ReturnKind::RT_ByRef == GCRK_Byref, "ReturnKind::RT_ByRef does not match GCRK_Byref");
686-
ASSERT((returnKind == RT_Scalar) || (returnKind == GCRK_Object) || (returnKind == GCRK_Byref));
686+
ASSERT((returnKind == RT_Scalar) || (returnKind == RT_Object) || (returnKind == RT_ByRef));
687687

688688
return (GCRefKind)returnKind;
689689
}

0 commit comments

Comments
 (0)