2009-06-19 15 views
80

Czytałem inne pytanie dotyczące wydajności dwóch linii kodu, a OP powiedział, że spojrzał na zespół za kodem i obie linie były identyczne w montażu. Odsuwając na bok, jak mogłem zobaczyć kod złożenia utworzony podczas kompilacji programu.Jak wyświetlić zestaw za kodem za pomocą programu Visual C++?

Używam Visual C++ Microsoftu, ale chciałbym również wiedzieć, czy możliwe jest zobaczenie zestawu za kodem napisanym w Visual Basic.

Jak zatem wyświetlić kod zespołu za programem napisanym w językach wyższego poziomu, takich jak C++ i Visual Basic?

Odpowiedz

114

Istnieją różne podejścia:

  1. Można normalnie patrz kod montażu podczas debugowania C++ w visual studio (zbyt) i Eclipse. W tym celu w Visual Studio ustaw punkt przełomowy na kodzie, a kiedy debugger trafi, kliknij i znajdź "Przejdź do zespołu" (lub naciśnij CTRL + ALT + D).

  2. Drugie podejście polega na generowaniu zestawień zestawów podczas kompilacji. W tym celu przejdź do ustawień projektu -> C/C++ -> Pliki wyjściowe -> ASM Lista Lokalizacja i wypełnij nazwę pliku. Wybierz także "Output Output" na "Assembly With Source Code".

  3. Skompiluj program i użyj dowolnego debuggera innej firmy. Możesz użyć OllyDbg lub WinDbg do tego. Możesz także użyć IDA (disassembler interaktywny). Ale to jest hardcorowy sposób robienia tego.

+5

Należy zauważyć, że podejście nr 2 nie działa podczas kompilowania biblioteki statycznej z włączoną optymalizacją całego programu (przynajmniej w VS2010). Co ma sens - kompilator jeszcze nie wygenerował ostatecznego kodu. – dhaffey

+2

Nazywa się "Goto Disassembly" w Visual Studio 2017 – Matthias

4

W Visual C++ opcje projektu poniżej, Pliki wyjściowe Wierzę, że ma opcję wyprowadzania listy ASM z kodem źródłowym. Więc zobaczysz kod źródłowy C/C++ i wynikowe ASM wszystkie w tym samym pliku.

9

Najprostszym sposobem jest uruchomienie debuggera i sprawdzenie okna demontażu .

1

Red Gate's .NET Reflector to całkiem niesamowite narzędzie, które pomogło mi ponad kilka razy. Dodatkową stroną tego narzędzia poza łatwym pokazaniem MSIL jest to, że możesz analizować wiele bibliotek DLL innych firm i mieć Reflectora, który zajmuje się konwersją MSIL do C# i VB.

Nie obiecuję, że kod będzie równie czytelny jak źródło, ale nie powinieneś mieć problemu z jego podążaniem.

+2

Uwaga: dotyczy tylko zarządzanych zestawów, aby nie dezasemblować jak w asembler, asm. –

+0

Dobra rada, przeczytałem to jako "są dwie linie kodu identyczne w zestawie" zamiast "są dwie linie kodu identyczne w zestawie" –

17

Należy określić przełącznik/FA dla kompilatora cl. W zależności od wartości przełącznika jest zintegrowany tylko kod zespołu lub kod wysokopoziomowy i kod zespołu. Nazwa pliku otrzymuje rozszerzenie .asm. Oto obsługiwane wartości: Kod


  • /FA Zgromadzenie; .asm
  • /FAC Kod maszyny i zespołu; .cod
  • /FAs Kod źródłowy i montażowy; .asm
  • /FAcs Kod maszyny, źródła i zespołu; .cod
24

Dodatkowa uwaga: istnieje duża różnica między danymi wyjściowymi asemblera a wersją Release. Pierwszą z nich jest dobra nauka, jak kompilator tworzy kod assemblera z C++. Drugi jest dobry, aby dowiedzieć się, w jaki sposób kompilator optymalizuje różne konstrukty C++. W tym przypadku niektóre transformacje C++ do asa nie są oczywiste.

+0

Zauważyłem, że podczas demontażu pliku wykonywalnego Debug wydaje się rozpakować kod podczas to działa, tak się nie dzieje w wersji Release. Również przy otwieraniu zarówno z PEiD, wersja Debug pokazuje "Microsoft Visual C++ 8.0 [Debug]". – jyz

+5

Jest to absolutnie prawdziwe. Ale w ogóle nie odpowiada na pytanie. – imallett

2

Dla MSVC można użyć linkera.

link.exe/zrzut/numery linii/disasm /out:foo.dis foo.dll

foo.pdb musi być dostępny, aby uzyskać symbole

6

Wcześniejsza wersja tej odpowiedzi (A „Hack "dla rextester.com) jest w większości zbędny teraz, gdy http://gcc.godbolt.org/ zapewnia CL 19 RC dla ARM, x86 i x86-64 (kierując się konwencją wywołującą Windows, w przeciwieństwie do gcc, clang i icc na tej stronie).

Eksplorator kompilatorów Godbolt został zaprojektowany do ładnego formatowania danych wyjściowych kompilatora ASM, usuwając "szum" dyrektyw, więc zdecydowanie polecam używanie go do sprawdzania asm dla prostych funkcji, które pobierają argumenty i zwracają wartość (więc nie zostaną zoptymalizowane).

Przez chwilę CL był dostępny na http://gcc.beta.godbolt.org/, ale nie na stronie głównej, ale teraz jest na obu.


Aby uzyskać wyjście asm MSVC z http://rextester.com/l/cpp_online_compiler_visual kompilatora internetowym: Dodaj /FAs do opcji wiersza poleceń. Niech twój program znajdzie swoją własną ścieżkę i wytyczy ścieżkę do .asm i zrzuci ją. Lub uruchom dezasembler na urządzeniu .exe.

np. http://rextester.com/OKI40941

#include <string> 
#include <boost/filesystem.hpp> 
#include <Windows.h> 

using namespace std; 

static string my_exe(void){ 
    char buf[MAX_PATH]; 
    DWORD tmp = GetModuleFileNameA(NULL, // self 
            buf, MAX_PATH); 
    return buf; 
} 

int main() { 
    string dircmd = "dir "; 
    boost::filesystem::path p(my_exe()); 
    //boost::filesystem::path dir = p.parent_path(); 

    // transform c:\foo\bar\1234\a.exe 
    // into  c:\foo\bar\1234\1234.asm 
    p.remove_filename(); 
    system ((dircmd + p.string()).c_str()); 

    auto subdir = p.end();  // pointing at one-past the end 
    subdir--;     // pointing at the last directory name 
    p /= *subdir;    // append the last dir name as a filename 
    p.replace_extension(".asm"); 
    system ((string("type ") + p.string()).c_str()); 
// std::cout << "Hello, world!\n"; 
} 

... code of functions you want to see the asm for goes here ... 

type jest wersja DOS cat. Nie chciałem dodawać więcej kodu, który utrudniłby znalezienie funkcji, które chciałem zobaczyć. (Chociaż używanie std :: string i boost działają przeciwnie do tych celów! Niektóre manipulacje łańcuchami w stylu C, które powodują więcej założeń dotyczących łańcucha, który przetwarza (i ignoruje maksymalne bezpieczeństwo/alokację przy użyciu dużego bufora) na wynik GetModuleFileNameA byłby o wiele mniejszy całkowity kod maszynowy.)

IDK dlaczego, ale cout << p.string() << endl pokazuje tylko nazwę baseame (tj. nazwę pliku, bez katalogów), mimo że wydrukowanie jej długości pokazuje, że to nie tylko nazwa bez nazwy. (Chromium48 na Ubuntu 15.10). Prawdopodobnie istnieje pewne przetwarzanie ułamków ukośników w pewnym momencie w cout lub między stdoutem programu i przeglądarką internetową.

+0

@MichaelPetch: oh, okazuje się, że * jest * tym, czego próbowałem. '.c_str()' wypisuje coś, co wygląda jak wskaźnik. Jeśli podążysz za odnośnikiem, zobaczysz kod do hexdump 'std :: string' (wyłączony przez' #if 0'). Okazuje się, że ciąg jest w porządku, ale 'cout' nie dostaje go do przeglądarki internetowej. Nie ma też żadnych znaków nie-ascii, tylko ukośniki odwrotne. –

+0

Być może czegoś mi brakuje, ale kiedy zrobiłeś 'subdir--; p/= * subdir; 'czy nie ograniczyłeś _p_ tylko do nazwy pliku?A może nie rozumiem, co próbujesz wydrukować. –

+0

Chyba nie całkiem rozumiem 'subdir -', po którym następuje 'p/= * subdir', gdy' subdir' był pierwotnie 'p.end()' –

Powiązane problemy