Bagaimana cara melihat rakitan di belakang kode menggunakan Visual C ++?

117

Saya membaca pertanyaan lain mengenai efisiensi dua baris kode, dan OP mengatakan bahwa dia melihat perakitan di belakang kode dan kedua baris identik dalam perakitan. Digresi samping, bagaimana saya bisa melihat kode assembly yang dibuat ketika sebuah program dikompilasi.

Saya menggunakan Microsoft Visual C ++, tetapi saya juga ingin tahu apakah mungkin untuk melihat perakitan di belakang kode yang ditulis dalam Visual Basic.

Jadi, bagaimana cara melihat kode assembly di belakang program yang ditulis dalam bahasa tingkat tinggi seperti C ++ dan Visual Basic?

Bart
sumber
Ini disebut daftar perakitan di D3D seperti yang telah disebutkan orang lain. Saya membuat plugin sederhana yang menambahkan entri ke menu konteks editor untuk mengotomatiskan langkah-langkah membosankan itu: marketplace.visualstudio.com/items?itemName=Trass3r.DevUtils
Trass3r

Jawaban:

149

Ada beberapa pendekatan:

  1. Anda biasanya dapat melihat kode assembly saat men-debug C ++ di studio visual (dan juga eclipse). Untuk ini di Visual Studio, letakkan breakpoint pada kode yang dimaksud dan ketika debugger memukulnya, klik tepat dan temukan "Go To Assembly" (atau tekan CTRL + ALT + D)

  2. Pendekatan kedua adalah menghasilkan daftar perakitan saat menyusun. Untuk ini, masuk ke pengaturan proyek -> C / C ++ -> Output Files -> ASM List Location dan isi nama file. Pilih juga "Assembly Output" ke "Assembly With Source Code".

  3. Kompilasi program dan gunakan debugger pihak ketiga. Anda dapat menggunakan OllyDbg atau WinDbg untuk ini. Anda juga dapat menggunakan IDA (disassembler interaktif). Tapi ini cara hardcore untuk melakukannya.

inazaruk
sumber
5
Perhatikan bahwa pendekatan # 2 tidak berfungsi saat menyusun pustaka statis dengan pengoptimalan seluruh program diaktifkan (setidaknya di VS2010). Yang masuk akal - kompiler belum menghasilkan kode akhir.
dhaffey
3
Ini disebut "Goto Disassembly" dalam Visual Studio 2017
Matthias
Dengan pendekatan # 2, bagaimana saya bisa melihat majelis?
pengguna1507435
Harus melihat file .asm di dir debug jika Anda menggunakan lokasi default.
pengguna3015682
28

Catatan tambahan: ada perbedaan besar antara keluaran assembler Debug dan keluaran satu. Yang pertama bagus untuk mempelajari bagaimana compiler menghasilkan kode assembler dari C ++. Yang kedua adalah baik untuk mempelajari bagaimana compiler mengoptimalkan berbagai konstruksi C ++. Dalam hal ini beberapa transformasi C ++ - ke-asm tidak jelas.

Vladimir Obrizan
sumber
Saya perhatikan bahwa ketika membongkar Debug yang dapat dieksekusi, sepertinya kode membongkar saat sedang berjalan, ini tidak terjadi pada versi Rilis. Juga saat membuka keduanya dengan PEiD hanya versi Debug yang menampilkan "Microsoft Visual C ++ 8.0 [Debug]".
jyz
9
Ini memang benar. Tapi itu tidak menjawab pertanyaan itu sama sekali.
imallett
25

Tentukan sakelar / FA untuk kompilator cl. Bergantung pada nilai sakelar, baik hanya kode perakitan atau kode tingkat tinggi dan kode perakitan yang terintegrasi. Nama file mendapat ekstensi file .asm. Berikut adalah nilai yang didukung:


  • / Kode Perakitan FA; .asm
  • / FAc Mesin dan kode perakitan; .ikan kod
  • / FAs Source dan kode perakitan; .asm
  • / FAcs Mesin, sumber, dan kode perakitan; .ikan kod
steve
sumber
10

Cara termudah adalah dengan mengaktifkan debugger dan memeriksa jendela pembongkaran .

diapir
sumber
8

Versi sebelumnya dari jawaban ini ("retasan" untuk rextester.com) sebagian besar mubazir sekarang karena http://gcc.godbolt.org/ menyediakan CL 19 RC untuk ARM, x86, dan x86-64 (menargetkan konvensi pemanggilan Windows , tidak seperti gcc, clang, dan icc di situs itu).

Penjelajah kompilator Godbolt dirancang untuk memformat keluaran asm kompilator dengan baik, menghilangkan "noise" dari direktif, jadi saya sangat merekomendasikan menggunakannya untuk melihat asm untuk fungsi sederhana yang mengambil argumen dan mengembalikan nilai (jadi mereka tidak akan dioptimalkan).

Untuk sementara, CL tersedia di http://gcc.beta.godbolt.org/ tetapi bukan situs utama, tetapi sekarang tersedia di keduanya.


Untuk mendapatkan keluaran MSVC asm dari http://rextester.com/l/cpp_online_compiler_visual kompilator online: Tambahkan /FAske opsi baris perintah. Mintalah program Anda menemukan jalurnya sendiri dan mengerjakan jalur ke .asmdan membuangnya. Atau jalankan disassembler di .exe.

mis. 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 ...

typeadalah versi DOS dari cat. Saya tidak ingin memasukkan lebih banyak kode yang akan membuat lebih sulit untuk menemukan fungsi yang ingin saya lihat asmnya. (Meskipun menggunakan std :: string dan boost run counter untuk tujuan tersebut! Beberapa manipulasi string gaya C yang membuat lebih banyak asumsi tentang string yang diprosesnya (dan mengabaikan keamanan / alokasi panjang-maksimal dengan menggunakan buffer besar) pada hasil GetModuleFileNameAwould menjadi lebih sedikit total kode mesin.)

IDK mengapa, tetapi cout << p.string() << endlhanya menunjukkan nama dasar (yaitu nama file, tanpa direktori), meskipun pencetakan panjangnya menunjukkan itu bukan hanya nama kosong. (Chromium48 di Ubuntu 15.10). Mungkin ada beberapa pemrosesan backslash-escape di beberapa titik cout, atau antara stdout program dan browser web.

Peter Cordes
sumber
@MichaelPetch: oh, ternyata bahwa adalah apa yang saya telah mencoba. .c_str()mencetak apa yang tampak seperti penunjuk. Jika Anda mengikuti tautan tersebut, Anda akan melihat kode ke hexdump a std::string(dinonaktifkan dengan #if 0). Ternyata string itu baik-baik saja, tetapi couttidak membawanya ke browser web. Tidak ada karakter non-ascii juga, hanya garis miring terbalik.
Peter Cordes
Saya mungkin melewatkan sesuatu tetapi ketika Anda subdir--; p /= *subdir;melakukannya bukankah Anda mengurangi p menjadi hanya nama file? Atau mungkin saya salah paham tentang apa yang Anda coba cetak.
Michael Petch
Saya kira saya tidak begitu mengerti subdir--diikuti oleh p /= *subdirkapan subdiraslinyap.end()
Michael Petch
@MichaelPetch: komentar diperbarui. Saya perlu mendapatkan komponen direktori terakhir dari jalur untuk digunakan sebagai nama file. Memang berhasil, tapi butuh waktu lama untuk berolahraga karena saya pikir GetModuleFileNameAbaru saja kembali a.exe. Tidak sampai saya melakukan hexdump dan mencetak panjang yang saya tahu itu berfungsi, dan saya dapat meminta program memanipulasi jalur, saya tidak bisa mencetak jalur
Peter Cordes
1
Ya, tampaknya menjadi bagian \\r(baik \rketika kompilator mengeluarkannya) dari nama file yang diterjemahkan dengan buruk saat rendering untuk browser web. Menggunakan p.generic_string()bekerja tetapi garis miring terbalik adalah garis miring ke depan.
Michael Petch
5

Dalam Visual C ++ opsi proyek di bawah, File Keluaran Saya percaya memiliki opsi untuk mengeluarkan daftar ASM dengan kode sumber. Jadi, Anda akan melihat kode sumber C / C ++ dan ASM yang dihasilkan semuanya dalam file yang sama.

jcopenha.dll
sumber
5

Untuk MSVC Anda dapat menggunakan linker.

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

foo.pdb harus tersedia untuk mendapatkan simbol

Steve Steiner
sumber
1

.NET Reflector dari Red Gate adalah alat yang cukup mengagumkan yang telah membantu saya lebih dari beberapa kali. Sisi positif dari utilitas ini selain menampilkan MSIL dengan mudah adalah bahwa Anda dapat menganalisis banyak DLL pihak ketiga dan meminta Reflector menangani pengubahan MSIL ke C # dan VB.

Saya tidak menjanjikan kode akan sejelas sumber tetapi Anda seharusnya tidak mengalami banyak kesulitan mengikutinya.

Dave L
sumber
2
Catatan: hanya berlaku untuk rakitan terkelola, bukan untuk pembongkaran seperti di assembler, asm.
sean e
Poin bagus, saya membacanya sebagai "adalah dua baris kode yang sama dalam perakitan" bukan "adalah dua baris kode yang sama dalam perakitan"
Dave L
Ini hanya akan bekerja pada aplikasi dotnet, Bukan linker atau kompiler Visual C ++.
Muhammad Ali
1

Jika Anda berbicara tentang debugging untuk melihat kode assembly, cara termudah adalah Debug-> Windows-> Disassembly (atau Alt-8). Ini akan memungkinkan Anda masuk ke fungsi yang dipanggil dan tetap dalam Pembongkaran.

Aabbee
sumber