2015-12-29 8 views
5

Wiem, że inni ludzie napisali podobne pytania, ale myślę, że mój jest inny przypadek, ponieważ nie mogłem znaleźć żadnego rozwiązania.Tajemnicze wywołanie jest dodawane, gdy odwołanie jest przypisane w C#

mam zadanie obiektu, coś bardzo prosty tak:

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

kod montaż generowany jest następujący

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

teraz, tylko zrozumieć, co się dzieje, chciałem wejdź do środka połączenia (dlaczego połączenie powinno być używane w zadaniu?). Jednak kod pod tym adresem nie istnieje i nie mogę wkroczyć jeśli wpisz adres w polu kod adresu, to co jest pokazane.

69C322F0 ??? 

Każda pomoc stara się rozwiązać ten Mistery? :)

Edycja. Najwyraźniej tajemnicze wywołanie jest dodawane, gdy odwołanie jest przypisane wewnątrz metody klasy.

Jeśli mam tej klasy:

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

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

zespół wygenerowany dla SetValues ​​metoda jest:

   _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 

co ma sens

jednak jeśli piszę ten

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

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

the tajemnicze wezwanie pojawia

   _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 jest to coś związane z Garbage Collection, ale nie mogę zrozumieć, co to jest, a ja naprawdę chciałbym zrozumieć. Wiem, że ktoś z was musi wiedzieć :)

aneks do odpowiedzi, to jest wyciąg Wziąłem od Google Books CLR książki poprzez C#:

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

+0

hmm nie, faktycznie to wyłączyłem celowo. Spróbuję tego! – sebas

+0

@AlexD, czy zaznaczyłeś opcję "Włącz debugowanie kodu niezarządzanego" we właściwościach projektu (karta Debugowanie)? –

+0

Może być duplikatem [tego pytania] (http://stackoverflow.com/questions/57840/how-to-attach-debugger-to-step-into-native-c-code-from-a-managed-c -wrappe) –

Odpowiedz

4

będę noodle o tym A trochę, pełna odpowiedź wypełnia książkę, która każe wszystkim spać. Otrzymujesz bardzo niedokładny widok kodu maszynowego, 32-bitowy dezasembler wykonuje bardzo słabą pracę tłumacząc adresy wywołania. To znacznie poprawiło się w ostatnich wersjach VS, jeśli spojrzeć na 64-bitowy kod, to dla jednego już nie fałszuje adresów instrukcji maszynowych. Dostać się tam z:

  • Project> Właściwości> kartę Budowa: Platforma docelowa = AnyCPU, odznacz "Wolę 32-bitowego"
  • Projekt> Właściwości kartę> Debug: zaznaczyć "Włącz kodu natywnego debugowanie"
  • Narzędzia > Opcje> Debugowanie> Symbole: włącz serwer Microsoft Symbol
  • Narzędzia> Opcje> Usuwanie błędów> Ogólne: usuń zaznaczenie "Pomiń optymalizację JIT".

Ostatnia zmiana ustawienia jest konieczne tylko wtedy, jeśli chcesz spojrzeć na prawdziwy kodu maszynowego, rodzaju, który działa na komputerze Twojego użytkownika. Zważajcie teraz, że patrzycie na niezoptymalizowany kod debugowania. W innym przypadku nie dotyczy to pytanie.

To całkiem dobrze oświetla dezasembler, chociaż nadal jest dalekie od ideału. Koniec ogona swoimi Test.SetValues ​​() metoda teraz wygląda tak:

   _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) 

Wyświetlany adres jest teraz dokładne, 0x07FFA7E3312B0. Patrząc na ten kod, wykonuje jeden dodatkowy krok, musisz wymusić debugger w trybie macierzystym. Debuguj> Windows> Call Stack i kliknij dwukrotnie natywną funkcję na dole śledzenia, np. RtlUserThreadStart. Teraz możesz skopiować/wkleić "07FFA7E3312B0" do pola Adresu dezasemblera, najpierw wpisz "0x". Nie pokażę tego tutaj, jest to odręcznie napisany kod assemblera, który robi raczej tajemniczą rzecz, której nigdy nie można cofnąć inżynierii kodu.

Lepszym miejscem, w którym można znaleźć te funkcje pomocnika jittera, jest kod źródłowy, chociaż nie jest to dokładny odpowiednik, najlepiej jest wybrać numer github CoreCLR project. Zajmie Ci here.

Ogólnie jitter emituje tego rodzaju bezpośrednie wywołania funkcji CLR w razie potrzeby, a ich nazwa zwykle zaczyna się od "JIT". Ten jest napisany na zgromadzeniu, ale nie jest to zbyt częste; większość z nich napisana jest w C++.

+0

dzięki, bardzo przydatna odpowiedź. Dla mnie wystarczyło wiedzieć o WriteBarrier, ale wyjaśnienie debugowania jest najlepsze. – sebas

+1

Zawsze radość z czytania odpowiedzi, ucz się czegoś nowego za każdym razem :) –

Powiązane problemy