Что именно происходит во время переходного процесса?

18

Я понимаю, что в некоторых случаях CLR нужно делать маршалинг, но, допустим, у меня есть:

using System.Runtime.InteropServices;
using System.Security;

[SuppressUnmanagedCodeSecurity]
static class Program
{
    [DllImport("kernel32.dll", SetLastError = false)]
    static extern int GetVersion();

    static void Main()
    {
        for (; ; )
            GetVersion();
    }
}

Когда я ворвался в эту программу с помощью отладчика, я всегда вижу:

Учитывая, что не требуется маршалинг, который нужно сделать (правильно?), может кто-нибудь объяснить, что на самом деле происходит происходит в этом «переход от перехода к родному» и почему это необходимо?     

задан Mehrdad 08.02.2012 в 22:08
источник
  • Возможно, эта строка в стеке вызовов просто информативна, чтобы вы узнали, когда вы перешли –  David Heffernan 08.02.2012 в 22:11
  • @DavidHeffernan: О, я думаю, это тоже работает ... но у меня есть чувство, что происходит что-то еще (хотя я бы хотел, чтобы меня доказали неправильно!). –  Mehrdad 08.02.2012 в 22:15
  • @DavidHeffernan: Интересно, что он не говорит то же самое при переходе с kernel32.dll на mscoree.dll, хотя ... поэтому он заставляет меня подозревать, что что-то действительно происходит. –  Mehrdad 08.02.2012 в 22:21
  • Существует маршалинг, потому что CLR автоматически обрабатывает возвращаемое значение, как если бы это нормальный аргумент, используя OutAttribute. –  Paolo Moretti 08.02.2012 в 22:23
  • Я не уверен, что вы имеете в виду. Вы говорите о обратных вызовах? –  David Heffernan 08.02.2012 в 22:23
Показать остальные комментарии

5 ответов

10

Сначала необходимо настроить стек вызовов, чтобы STDCALL мог произойти. Это вызов для Win32.

Далее среда выполнения вытолкнет так называемый кадр выполнения. Существует множество различных типов фреймов: безопасности, защищенных GC областей, собственных кодовых вызовов, ...

Среда выполнения использует такой фрейм для отслеживания текущего исполняемого кода. Это может повлиять на потенциально одновременную сборку мусора и, возможно, на другие вещи. Это также помогает отладчику.

Так что на самом деле здесь не так много. Это довольно тонкий путь кода.

    
ответ дан usr 08.02.2012 в 22:45
  • +1 это замечательный ответ. –  Mehrdad 08.02.2012 в 22:46
2

Помимо слоя маршалинга, который отвечает за преобразование параметров для вас и вычисляет соглашения о вызовах, среда выполнения должна выполнять несколько других действий, чтобы поддерживать внутреннее состояние.

Необходимо проверить контекст безопасности, чтобы убедиться, что вызывающему коду разрешен доступ к собственным методам. Текущий управляемый стек стека должен быть сохранен, так что среда выполнения может выполнять переход в стеке для таких вещей, как отладка и обработка исключений (не говоря уже о собственном коде, который вызывает управляемый обратный вызов). Внутренние биты состояния должны быть установлены, чтобы указать, что мы в настоящее время выполняем собственный код.

Кроме того, регистры могут нуждаться в сохранении, в зависимости от того, что нужно отслеживать и которые, как гарантируется, будут восстановлены с помощью соглашения о вызовах. Корни GC, которые находятся в регистрах (locals), возможно, должны быть отмечены каким-то образом, чтобы они не собирали мусор во время собственного метода.

Так что в основном это обработка стека и маршалинг типов, причем некоторые элементы безопасности вставляются. Хотя это не огромное количество вещей, он будет представляет собой значительный барьер против вызова небольших собственных методов. Например, попытка P / Invoke в оптимизированной математической библиотеке редко приводит к выигрышу в производительности, поскольку накладных расходов достаточно, чтобы отрицать любые потенциальные выгоды. Некоторые результаты профилирования производительности обсуждаются здесь .

    
ответ дан MikeP 08.02.2012 в 23:06
2

Я понимаю, что на это был дан ответ, но я удивлен, что никто не предложил вам показать внешний код в окне отладки. Если вы щелкните правой кнопкой мыши по строке [Native to Managed Transition] и отметьте опцию Show External Code , вы увидите, какие именно методы .NET вызывают в процессе перехода. Это может дать вам лучшую идею. Вот пример:

    
ответ дан Sheridan 27.03.2013 в 15:55
1

Я не вижу многого, что нужно сделать. Я подозреваю, что в основном информативный, указать вам, что часть вашего стека вызовов показывает собственные функции, а также указывает, что среда IDE и отладчик могут вести себя по-разному в течение этого перехода (поскольку управляемый код обрабатывается совсем по-разному в отладчике и некоторые функции, которые вы ожидаете, могут не работать)

Но я думаю, вы должны быть в состоянии узнать, просто осмотрев разборку вокруг перехода. Посмотрите, не делает ли что-нибудь необычное.

    
ответ дан jalf 08.02.2012 в 22:36
  • Трудно проверить разборку: VS говорит мне, что инструкция в моем коде C # вызывает 0xFFEFBFAC, но ничего нет на этом адресе - когда я вхожу в эту функцию, она автоматически переходит в _GetVersionStub @ 0, что на 75834437. Таким образом, очевидно, что пропускается какой-то код. Может быть, я мог бы сделать это с помощью WinDbg? Не уверен, я мог бы попробовать и посмотреть. –  Mehrdad 08.02.2012 в 22:38
0

Поскольку вы вызываете dll. он должен выйти из управляемой среды. Он входит в ядро ​​Windows. Вы нарушаете барьер .net и переходите в код Windows, который не работает так же, как .NET.

    
ответ дан iefpw 08.02.2012 в 22:15
  • Не шутите !! ... –  Mehrdad 08.02.2012 в 22:18
  • Не очень информативный. Вы просто перефразируете вопрос. :) –  jalf 08.02.2012 в 22:23
  • @jalf, но «нарушение барьера .NET» - хорошая перефразировка. –  phoog 08.02.2012 в 22:29
  • Я не уверен, что он спрашивал. Что именно происходит во время перехода к естественному переходу. Он вызывает DLL-окна, которые находятся вне рамок .NET, и именно поэтому он информирует пользователя о том, что существует «переход к естественному переходу». Не пытался быть умным. Когда произошел переход на native, ресурсы должны быть освобождены и очищены пользователем. Как только он станет родным, доступной информации отладки недостаточно. –  iefpw 08.02.2012 в 23:01
  • @iefpw Если вы не знаете, что кто-то спрашивает, не отвечайте на вопрос. У вас достаточно репутации, чтобы оставить комментарий, требуя разъяснений. Ваш «ответ», по сути, не имеет смысла, а тем более полезно. –  Andrew Barber 08.02.2012 в 23:47