Jak wyświetlić zestaw za kodem przy użyciu Visual C ++?


117

Czytałem kolejne pytanie dotyczące wydajności dwóch linii kodu, a OP powiedział, że spojrzał na assembler za kodem i obie linie były identyczne w asemblerze. Pomijając dygresję, jak mógłbym zobaczyć kod asemblera utworzony podczas kompilacji programu.

Używam Visual C ++ firmy Microsoft, ale chciałbym również wiedzieć, czy jest możliwe wyświetlenie zestawu za kodem napisanym w Visual Basic.

Jak więc wyświetlić kod asemblera za programem napisanym w językach wyższego poziomu, takich jak C ++ i Visual Basic?


Nazywa się to listą zespołu w msvc, jak wspominali już inni. Stworzyłem prostą wtyczkę
dodającą

Odpowiedzi:


149

Istnieje kilka podejść:

  1. Zwykle można zobaczyć kod asemblera podczas debugowania C ++ w Visual Studio (i zaćmienie). W tym celu w programie Visual Studio umieść punkt przerwania w kodzie, o którym mowa, a gdy debugger go osiągnie, kliknij i znajdź „Przejdź do zestawu” (lub naciśnij CTRL + ALT + D)

  2. Drugie podejście polega na generowaniu list asemblerów podczas kompilacji. W tym celu przejdź do ustawień projektu -> C / C ++ -> Pliki wyjściowe -> Lokalizacja listy ASM i wpisz nazwę pliku. Wybierz także „Wyjście zespołu” na „Zespół z kodem źródłowym”.

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


5
Zauważ, ż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 nie wygenerował jeszcze ostatecznego kodu.
dhaffey

3
Nazywa się „Idź do demontażu” w programie Visual Studio 2017
Matthias

Przy podejściu nr 2, jak mogę zobaczyć zespół?
user1507435

Powinien pojawić się plik .asm w katalogu debugowania, jeśli użyto domyślnej lokalizacji.
user3015682

28

Dodatkowa uwaga: istnieje duża różnica między wyjściem debugowania asemblera a wydaniem. Pierwszym z nich jest nauczenie się, jak kompilator tworzy kod asemblera z C ++. Drugi to dobry sposób, aby dowiedzieć się, jak kompilator optymalizuje różne konstrukcje C ++. W tym przypadku niektóre przekształcenia C ++ na asm nie są oczywiste.


Zauważyłem, że podczas deasemblacji pliku wykonywalnego Debug wydaje się, że rozpakowuje kod, gdy jest uruchomiony, nie dzieje się tak w wersji Release. Również podczas otwierania obu za pomocą PEiD tylko wersja Debug pokazuje „Microsoft Visual C ++ 8.0 [Debugowanie]”.
jyz

9
To jest absolutnie prawdziwe. Ale to wcale nie odpowiada na pytanie.
imallett

25

Określ przełącznik / FA dla kompilatora cl. W zależności od wartości przełącznika zintegrowany jest albo tylko kod montażowy, albo kod wysokiego poziomu i kod montażowy. Nazwa pliku otrzymuje rozszerzenie .asm. Oto obsługiwane wartości:


  • / FA Kod montażowy; .jako M
  • / FAc Kod maszyny i zespołu; .dorsz
  • / FAs Kod źródłowy i asemblerowy; .jako M
  • / FAcs Kod maszyny, źródła i asemblera; .dorsz

10

Najłatwiej jest odpalić debugger i sprawdzić okno dezasemblacji .


8

Wcześniejsza wersja tej odpowiedzi ("hack" dla rextester.com) jest teraz w większości zbędna, ponieważ http://gcc.godbolt.org/ udostępnia CL 19 RC dla ARM, x86 i x86-64 (celując w konwencję wywoływania systemu Windows , w przeciwieństwie do gcc, clang i icc na tej stronie).

Eksplorator kompilatora Godbolt jest przeznaczony do ładnego formatowania danych wyjściowych kompilatora asm, usuwania „szumu” dyrektyw, więc bardzo polecam używanie go do szukania prostych funkcji, które pobierają argumenty i zwracają wartość (więc nie będą zoptymalizowany z dala).

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


Aby uzyskać dane wyjściowe MSVC asm z http://rextester.com/l/cpp_online_compiler_visual kompilatora online: Dodaj /FAsdo opcji wiersza poleceń. Niech twój program znajdzie własną ścieżkę, opracuje ścieżkę do .asmpliku i zrzuci go. Lub uruchom dezasembler na .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 ...

typejest wersją DOS cat. Nie chciałem dołączać więcej kodu, który utrudniałby znalezienie funkcji, dla których chciałem zobaczyć asm. (Chociaż za pomocą std :: string i są sprzeczne impuls do tych celów! Niektóre C-styl manipulacji ciąg, który sprawia, że kolejne założenia o struny to przetwórstwo (i ignoruje max długości bezpieczeństwa / alokację przy użyciu duży bufor) na skutek GetModuleFileNameABĘDZIE być znacznie mniej całkowitym kodem maszynowym.)

IDK dlaczego, ale cout << p.string() << endlpokazuje tylko podstawową nazwę (tj. Nazwę pliku bez katalogów), mimo że wypisanie jej długości pokazuje, że nie jest to tylko sama nazwa. (Chromium48 na Ubuntu 15.10). Prawdopodobnie w pewnym momencie coutlub między standardowym wyjściem programu a przeglądarką internetową występuje pewne przetwarzanie ucieczki odwrotnym ukośnikiem .


@MichaelPetch: och, okazuje się, że właśnie tego próbowałem. .c_str()drukuje coś, co wygląda jak wskaźnik. Jeśli podążasz za linkiem, zobaczysz kod zrzutu szesnastkowego std::string(wyłączony za pomocą #if 0). Okazuje się, że ciąg jest w porządku, ale coutnie przekazuje go do przeglądarki internetowej. Nie ma też żadnych znaków spoza zestawu ASCII, tylko ukośniki odwrotne.
Peter Cordes,

Może coś mi umknęło, ale subdir--; p /= *subdir;czy nie zredukowałeś p do samej nazwy pliku? A może źle rozumiem, co próbujesz wydrukować.
Michael Petch

Wydaje mi się, że nie do końca rozumiem, co subdir--nastąpiło po tym, p /= *subdirkiedy subdirpierwotnie byłop.end()
Michael Petch,

@MichaelPetch: zaktualizowane komentarze. Musiałem uzyskać ostatni składnik katalogu ścieżki, który ma być używany jako nazwa pliku. To działa, ale zajęło mi dużo czasu, ponieważ myślałem, że GetModuleFileNameAwłaśnie wracam a.exe. Dopiero gdy go przekręciłem i wydrukowałem długość, wiedziałem, że działa, i mogłem pozwolić programowi manipulować ścieżką, po prostu nie mogłem wydrukować ścieżki
Peter Cordes,

1
Tak, wydaje się, że jest to \\r(dobrze, \rkiedy kompilator ją wypisuje) część nazwy pliku, którą źle przetłumaczył podczas renderowania w przeglądarce internetowej. Używanie p.generic_string()działa, ale ukośniki odwrotne są ukośnikami w przód.
Michael Petch,

5

W języku Visual C ++ opcje projektu w obszarze Output Files, jak sądzę, mają opcję wyświetlania listy ASM z kodem źródłowym. Więc zobaczysz kod źródłowy C / C ++ i wynikowy ASM w tym samym pliku.


5

W przypadku MSVC możesz użyć konsolidatora.

link.exe / dump / Linnumbers / disasm /out:foo.dis foo.dll

Aby można było pobrać symbole, musi być dostępny plik foo.pdb


1

Odbłyśnik .NET firmy Red Gate to całkiem niesamowite narzędzie, które pomogło mi więcej niż kilka razy. Zaletą tego narzędzia poza łatwym wyświetlaniem MSIL jest to, że możesz przeanalizować wiele bibliotek DLL innych firm i zlecić Reflectorowi zajęcie się konwersją MSIL na C # i VB.

Nie obiecuję, że kod będzie tak czytelny jak źródło, ale nie powinieneś mieć większych problemów z jego śledzeniem.


2
Uwaga: ma zastosowanie tylko do zarządzanych zespołów, a nie do demontażu, jak w asemblerze, asm.
sean e

Słuszna uwaga, przeczytałem to jako „czy dwie linie kodu są takie same w asemblerze” zamiast „czy te dwie linie kodu są takie same w asemblerze”
Dave L

Będzie działać tylko w aplikacjach dotnet, a nie w konsolidatorze lub kompilatorze Visual C ++.
Muhammad Ali

1

Jeśli mówisz o debugowaniu, aby zobaczyć kod asemblera, najłatwiejszym sposobem jest Debug-> Windows-> Disassembly (lub Alt-8). Pozwoli ci to wejść do wywoływanej funkcji i pozostać w demontażu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.