Нужна помощь в расшифровке строки кода на ассемблере из кода .NET JITted - PullRequest
4 голосов
/ 23 апреля 2009

В конструкторе C #, который заканчивается вызовом this(...), фактический вызов переводится в это:

0000003d  call        dword ptr ds:[199B88E8h]

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

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

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

Код C #, о котором идет речь, таков:

public AxisRangeData(AxisRange range) : this(range, range.Axis) {
}

Отражатель показывает мне этот код IL:

.maxstack 8
L_0000: ldarg.0 
L_0001: ldarg.1 
L_0002: ldarg.1 
L_0003: callvirt instance class DevExpress.XtraCharts.AxisBase DevExpress.XtraCharts.AxisRange::get_Axis()
L_0008: call instance void DevExpress.XtraCharts.Native.AxisRangeData::.ctor(class DevExpress.XtraCharts.ChartElement, class DevExpress.XtraCharts.AxisBase)
L_000d: ret 

Это последний вызов этого другого конструктора того же класса, который завершается неудачей. Отладчик никогда не всплывает внутри другого метода, он просто падает.

Разборка для метода после JITting такова:

00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  sub         esp,14h 
00000006  mov         dword ptr [ebp-4],ecx 
00000009  mov         dword ptr [ebp-8],edx 
0000000c  cmp         dword ptr ds:[18890E24h],0 
00000013  je          0000001A 
00000015  call        61843511 
0000001a  mov         eax,dword ptr [ebp-4] 
0000001d  mov         dword ptr [ebp-0Ch],eax 
00000020  mov         eax,dword ptr [ebp-8] 
00000023  mov         dword ptr [ebp-10h],eax 
00000026  mov         ecx,dword ptr [ebp-8] 
00000029  cmp         dword ptr [ecx],ecx 
0000002b  call        dword ptr ds:[1889D0DCh]   // range.Axis
00000031  mov         dword ptr [ebp-14h],eax 
00000034  push        dword ptr [ebp-14h] 
00000037  mov         edx,dword ptr [ebp-10h] 
0000003a  mov         ecx,dword ptr [ebp-0Ch] 
0000003d  call        dword ptr ds:[199B88E8h]   // this(range, range.Axis)?
00000043  nop              
00000044  mov         esp,ebp 
00000046  pop         ebp  
00000047  ret              

В основном я спрашиваю:

  • Какова цель перенаправления ds:[ADDR] здесь? VMT-таблица только для виртуальных, не так ли? и это конструктор
  • Может ли конструктор еще быть JITted, что может означать, что вызов действительно будет вызываться через прокладку JIT? Боюсь, что я в глубокой воде, поэтому все может и может помочь.

Редактировать : Ну, проблема только усугубилась, или улучшилась, или как там.

Мы разрабатываем функцию .NET в проекте C # в решении Visual Studio 2008, а также отлаживаем и разрабатываем с помощью Visual Studio.

Однако, в конце концов, этот код будет загружен в среду выполнения .NET, размещенную приложением Win32 Delphi.

Чтобы упростить экспериментирование с такими функциями, мы также можем настроить проект / решение / отладчик Visual Studio для копирования созданных библиотек DLL в каталог приложения Delphi, а затем запустить приложение Delphi через отладчик Visual Studio.

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

Не уверен, что это помогает, но, поскольку код не планируется к выпуску в течение еще 6 месяцев или около того, он снимает с него некоторое давление для тестового выпуска, который у нас скоро.

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

1 Ответ

3 голосов
/ 23 апреля 2009

Сегмент данных - это место, где компиляторы обычно помещают глобальные переменные и где находится таблица адресов импорта.

00000029  cmp         dword ptr [ecx],ecx 
0000002b  call        dword ptr ds:[1889D0DCh]

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

Инструкция callvirt MSIL должна выполнить нулевую проверку перед вызовом фактического метода. При этом можно смело предположить, что эти две строки кода сборки имеют следующее представление кода MSIL:

class DevExpress.XtraCharts.AxisBase DevExpress.XtraCharts.AxisRange::get_Axis()

И прокомментированный код сборки:

00000026  mov         ecx,dword ptr [ebp-8]      // store the pointer to the 'range' in ECX
00000029  cmp         dword ptr [ecx],ecx        // null-check
0000002b  call        dword ptr ds:[1889D0DCh]   // range.get_Axis()
00000031  mov         dword ptr [ebp-14h],eax    // store the result in a local variable
00000034  push        dword ptr [ebp-14h]        // push the result onto a stack
00000037  mov         edx,dword ptr [ebp-10h]    // this variable was previously loaded with the 'range' pointer
0000003a  mov         ecx,dword ptr [ebp-0Ch]    // here seems to be stored the actual 'this' pointer
0000003d  call        dword ptr ds:[199B88E8h]   // call the this(...) ctor

Мне непонятно, почему происходит сбой, вы пытались найти содержимое ячейки памяти (DS:[199B88E8h])?

...