2015-12-29 25 views
5

So che altre persone hanno scritto domande simili, ma penso che il mio sia un caso diverso, poiché non sono riuscito a trovare alcuna soluzione.La chiamata misteriosa viene aggiunta quando viene assegnato un riferimento in C#

Ho un incarico oggetto, qualcosa di molto semplice come questo:

_buffer3 = buffer; //they are just simple reference types 

il codice assembly generato è il seguente

mov   edx,dword ptr [ebp-3Ch] 
mov   eax,dword ptr [ebp-40h] 
lea   edx,[edx+4] 
call  69C322F0 

ora, solo per capire cosa sta succedendo, ho voluto passo all'interno della chiamata (perché una chiamata dovrebbe essere utilizzata in un incarico?). Tuttavia il codice a quell'indirizzo non esiste e non può fare un passo in se digito l'indirizzo nel campo indirizzo, questo è ciò che viene mostrato:.

69C322F0 ??? 

Qualsiasi aiuto cercando di risolvere questo mistero? :)

Modifica..apparentemente la chiamata misteriosa viene aggiunta quando un riferimento viene assegnato all'interno di un metodo di una classe.

Se ho questa classe:

 private class Test 
     { 
      int _X; 
      int _Y; 
      Test _t; 

      public void SetValues(int x, int y, Test t) 
      { 
       _X = x; 
       _Y = y; 
      } 
     } 

dell'assieme generato per i SetValues ​​metodo è:

   _X = x; 
00000028 mov   eax,dword ptr [ebp-3Ch] 
0000002b mov   edx,dword ptr [ebp-40h] 
0000002e mov   dword ptr [eax+8],edx 
       _Y = y; 
00000031 mov   eax,dword ptr [ebp-3Ch] 
00000034 mov   edx,dword ptr [ebp+0Ch] 
00000037 mov   dword ptr [eax+0Ch],edx 

che ha senso

se sto scrivendo questo

 private class Test 
     { 
      int _X; 
      int _Y; 
      Test _t; 

      public void SetValues(int x, int y, Test t) 
      { 
       _X = x; 
       _Y = y; 
       _t = t; 
      } 
     } 

il chiamata misteriosa appare

   _X = x; 
00000028 mov   eax,dword ptr [ebp-3Ch] 
0000002b mov   edx,dword ptr [ebp-40h] 
0000002e mov   dword ptr [eax+8],edx 
       _Y = y; 
00000031 mov   eax,dword ptr [ebp-3Ch] 
00000034 mov   edx,dword ptr [ebp+0Ch] 
00000037 mov   dword ptr [eax+0Ch],edx 
       _t = t; 
0000003a mov   edx,dword ptr [ebp-3Ch] 
0000003d mov   eax,dword ptr [ebp+8] 
00000040 lea   edx,[edx+4] 
00000043 call  515E2E48 

IMHO è qualcosa legato alla raccolta dei rifiuti, ma non riesco a capire di cosa si tratta e mi piacerebbe capirlo. So che qualcuno di voi deve sapere :)

Addendum alla risposta, questo è un estratto ho preso da Google Libri del libro CLR via C#:

This is an extract I took from Google Books of the book: CLR via C#

+0

hmm no, l'ho effettivamente disabilitato di proposito. Lo proverò! – sebas

+0

@AlexD, hai selezionato "Abilita debug del codice non gestito" nelle proprietà del progetto (scheda Debug)? –

+0

Potrebbe essere un duplicato di [questa domanda] (http://stackoverflow.com/questions/57840/how-to-attach-debugger-to-step-into-native-c-code-from-a-managed-c -wrappe) –

risposta

4

te lo Noodle su questo un un po ', una risposta completa riempie un libro che mette tutti a dormire. Si sta ottenendo una visione molto imprecisa del codice macchina, il disassemblatore a 32 bit fa un lavoro molto scarso traducendo gli indirizzi CALL. Questo è migliorato parecchio nelle recenti versioni di VS, se si guarda il codice a 64 bit, che per uno non falsifica più gli indirizzi delle istruzioni del codice macchina. Arrivare con:

  • Progetto> Proprietà> scheda Corporatura: Piattaforma target = AnyCPU, deselezionare "Preferisco a 32 bit"
  • Progetto> scheda Proprietà> Debug: tick "attivare il debug di codice nativo"
  • Strumenti > Opzioni> Debug> Simboli: abilita Microsoft Symbol Server
  • Strumenti> Opzioni> Debug> Generale: deseleziona "Elimina ottimizzazione JIT".

L'ultima modifica impostazione è necessaria solo se si vuole guardare il codice macchina vera, il tipo che gira sulla macchina dell'utente. Fai attenzione che stai guardando il codice di debug non ottimizzato in questo momento. Non altrimenti pertinente a questa domanda.

Che illumina abbastanza bene il disassemblatore, sebbene sia ancora lontano dall'ideale. La coda dei tuoi Test.SetValues ​​() metodo appare come segue:

   _t = t; 
00007FFA1ECB0C58 mov   rdx,qword ptr [rbp+50h] 
00007FFA1ECB0C5C lea   rcx,[rdx+8] 
00007FFA1ECB0C60 mov   rdx,qword ptr [rbp+68h] 
00007FFA1ECB0C64 call  JIT_WriteBarrier (07FFA7E3312B0h) 

l'indirizzo visualizzato è ora precisa, 0x07FFA7E3312B0. Guardare quel codice richiede un passo in più, devi forzare il debugger in modalità nativa. Debug> Windows> Chiama pila e fai doppio clic su una funzione nativa nella parte inferiore della traccia, come RtlUserThreadStart. Ora è possibile copiare/incollare "07FFA7E3312B0" nella casella Indirizzo del disassemblatore, digitare prima "0x". Non lo mostrerò qui, questo è un codice assembly scritto a mano che fa una cosa piuttosto misteriosa che non puoi mai decodificare dal codice.

Il posto migliore per cercare queste funzioni di jitter helper è il codice sorgente, anche se non è una corrispondenza esatta, lo github CoreCLR project è la soluzione migliore. Ti porta a here.

In generale, il jitter emette questo tipo di chiamate di funzione CLR diretta secondo necessità e il loro nome di solito inizia con "JIT". Questo sembra essere scritto in assemblea, che tuttavia non è molto comune; la maggior parte sono scritti in C++.

+0

grazie, risposta molto utile. Per me era sufficiente sapere su WriteBarrier, ma la spiegazione del debug è la ciliegina sulla torta. – sebas

+1

Sempre una gioia leggere le tue risposte, impara qualcosa di nuovo ogni volta :) –

Problemi correlati