Hai bisogno di aiuto per decifrare una riga di codice assembler, dal codice .NET JITted
-
13-09-2019 - |
Domanda
In un C # costruttore, che finisce con una chiamata a this(...)
, la chiamata effettiva viene tradotto a questo:
0000003d call dword ptr ds:[199B88E8h]
Qual è il registro DS contenuti qui? So che è il segmento di dati, ma è questa chiamata attraverso un VMT-tavolo o simili? Ne dubito, però, dal momento che this(...)
non sarebbe una chiamata a un metodo virtuale, solo un altro costruttore.
Lo chiedo perché il valore in quella posizione sembra essere un male in qualche modo, se ho colpito F11, traccia in (Visual Studio 2008), in quel call-istruzione, il programma si blocca con una violazione di accesso.
Il codice è profondo all'interno di una libreria di controllo 3rd party, dove, anche se ho il codice sorgente, non ho gli assembly compilati con le informazioni di debug sufficiente che posso rintracciarlo tramite codice C #, solo attraverso la disassembler, e allora devo corrispondere a quello nuovo al codice vero e proprio.
Il codice C # in questione è questo:
public AxisRangeData(AxisRange range) : this(range, range.Axis) {
}
Reflector mi mostra questo codice 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
E 'che lì ultima chiamata, l'altro costruttore della stessa classe, che non riesce. Il debugger mai superfici dentro l'altro metodo, appena si blocca.
Lo smontaggio per il metodo dopo JITting è questo:
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
In pratica quello che sto chiedendo è questo:
- Quale lo scopo del indirezione
ds:[ADDR]
qui? VMT-tabella è solo per virtuale non è vero? e questo è il costruttore - Può il costruttore devono ancora essere JITted, che potrebbe significare che la chiamata sarebbe in realtà chiamata attraverso uno spessore JIT? Ho paura che sono in acque profonde qui, quindi tutto potrebbe e potrebbe aiutare.
Modifica :. Beh, il problema solo peggiorata, o meglio, o qualsiasi altra cosa
Stiamo sviluppando la funzionalità .NET in un progetto C # in uno Studio 2008 soluzione di Visual, e il debug e lo sviluppo tramite Visual Studio.
Tuttavia, alla fine, questo codice verrà caricato in un runtime .NET ospitato da un'applicazione di Win32 Delphi.
Al fine di facilitare la sperimentazione di tali caratteristiche, possiamo anche configurare il progetto di Visual Studio / soluzione / debugger per copiare i prodotti dll alla directory di Delphi applicazione, e quindi eseguire l'applicazione Delphi, attraverso il debugger di Visual Studio.
Si scopre che il problema va via se corro il programma all'esterno del debugger, ma durante il debug, si pota in su, ogni volta.
Non è sicuro che aiuta, ma dal momento che il codice non è previsto per il rilascio in produzione per altri 6 mesi o giù di lì, quindi ci vuole un po 'la pressione di esso per il rilascio di test che abbiamo presto.
mi tuffo nelle parti della memoria in seguito, ma probabilmente non fino a quando durante il fine settimana, e posta un follow-up.
Soluzione
segmento dati è dove i compilatori di solito mettere le variabili globali e in cui risiede l'Import Address Table.
00000029 cmp dword ptr [ecx],ecx
0000002b call dword ptr ds:[1889D0DCh]
La prima riga è in realtà un null-controllo, che alla fine solleva un NullReferenceException
se il puntatore si trova nel registro ECX è valido.
L'istruzione MSIL callvirt
deve fare il null controllo prima di richiamare il metodo effettivo. Detto questo, possiamo tranquillamente assumere che queste due righe di codice assembly hanno la seguente rappresentazione codice MSIL:
class DevExpress.XtraCharts.AxisBase DevExpress.XtraCharts.AxisRange::get_Axis()
E il codice assembly commentato:
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
Non è chiaro per me perché è crash, hai provato guardando il contenuto della locazione di memoria (DS:[199B88E8h]
)?