Làm cách nào để xem phần lắp ráp phía sau mã bằng Visual C ++?


116

Tôi đang đọc một câu hỏi khác liên quan đến hiệu quả của hai dòng mã, và OP nói rằng ông đã xem xét phần lắp ráp phía sau mã và cả hai dòng đều giống hệt nhau. Bỏ qua một bên, làm thế nào tôi có thể xem mã lắp ráp được tạo khi chương trình được biên dịch.

Tôi đang sử dụng Visual C ++ của Microsoft, nhưng tôi cũng muốn biết liệu có thể xem tập hợp đằng sau mã được viết bằng Visual Basic hay không.

Vậy, làm cách nào để tôi xem mã lắp ráp đằng sau một chương trình được viết bằng các ngôn ngữ cấp cao hơn như C ++ và Visual Basic?


Nó được gọi là một danh sách lắp ráp trong msvc như những người khác đã đề cập. Tôi đã tạo một plugin đơn giản thêm các mục vào menu ngữ cảnh của trình soạn thảo để tự động hóa các bước tẻ nhạt đó: marketplace.visualstudio.com/items?itemName=Trass3r.DevUtils
Trass3r

Câu trả lời:


149

Có một số cách tiếp cận:

  1. Bạn thường có thể thấy mã lắp ráp trong khi gỡ lỗi C ++ trong studio hình ảnh (và nhật thực cũng vậy). Đối với điều này trong Visual Studio, hãy đặt một điểm dừng về mã trong câu hỏi và khi trình gỡ lỗi chạm vào nó, hãy nhấp và tìm "Đi đến hội" (hoặc nhấn CTRL + ALT + D)

  2. Cách tiếp cận thứ hai là tạo danh sách lắp ráp trong khi biên dịch. Đối với điều này, đi đến cài đặt dự án -> C / C ++ -> Tệp xuất -> Vị trí danh sách ASM và điền tên tệp. Đồng thời chọn "Kết quả đầu ra" để "Lắp ráp với mã nguồn".

  3. Biên dịch chương trình và sử dụng bất kỳ trình gỡ lỗi của bên thứ ba. Bạn có thể sử dụng OllyDbg hoặc WinDbg cho việc này. Ngoài ra, bạn có thể sử dụng IDA (trình phân tách tương tác). Nhưng đây là cách làm khó.


5
Lưu ý rằng cách tiếp cận # 2 không hoạt động khi biên dịch thư viện tĩnh với tối ưu hóa toàn bộ chương trình được bật (ít nhất là trong VS2010). Điều này có nghĩa - trình biên dịch chưa tạo mã cuối cùng.
dhaffey 26/03/13

3
Nó được gọi là "Tháo gỡ Goto" trong Visual Studio 2017
Matthias

Với cách tiếp cận # 2, làm thế nào tôi có thể thấy lắp ráp?
user1507435

Sẽ thấy tệp .asm trong thư mục gỡ lỗi nếu bạn đã sử dụng vị trí mặc định.
user3015682

28

Lưu ý thêm: có sự khác biệt lớn giữa đầu ra của trình biên dịch chương trình gỡ lỗi và Bản phát hành. Cách đầu tiên là tốt để tìm hiểu cách trình biên dịch tạo mã trình biên dịch mã từ C ++. Cách thứ hai là tốt để tìm hiểu cách trình biên dịch tối ưu hóa các cấu trúc C ++ khác nhau. Trong trường hợp này, một số phép biến đổi C ++ - to-asm không rõ ràng.


Tôi nhận thấy rằng khi tháo gỡ Debug thực thi, nó dường như giải nén mã trong khi nó đang chạy, điều này không xảy ra trên phiên bản Phát hành. Ngoài ra, khi mở cả hai bằng PEiD, phiên bản Debug hiển thị "Microsoft Visual C ++ 8.0 [Gỡ lỗi]".
jyz

9
Điều này là hoàn toàn đúng. Nhưng nó không trả lời câu hỏi nào cả.
imallett

25

Chỉ định công tắc / FA cho trình biên dịch cl. Tùy thuộc vào giá trị của công tắc, chỉ có mã lắp ráp hoặc mã cấp cao và mã lắp ráp được tích hợp. Tên tệp được mở rộng tệp .asm. Dưới đây là các giá trị được hỗ trợ:


  • / Mã hội FA; .asm
  • / FAc Máy và mã lắp ráp; .cod
  • / FAs Nguồn và mã lắp ráp; .asm
  • / FAcs Máy, nguồn, và mã lắp ráp; .cod

10

Cách dễ nhất là kích hoạt trình gỡ lỗi và kiểm tra cửa sổ tháo gỡ .


8

Phiên bản trước của câu trả lời này (một bản "hack" cho rextester.com) hầu hết là dự phòng khi http://gcc.godbolt.org/ cung cấp CL 19 RC cho ARM, x86 và x86-64 (nhắm mục tiêu vào quy ước gọi Windows , không giống như gcc, clang và icc trên trang web đó).

Trình thám hiểm trình biên dịch Godbolt được thiết kế để định dạng đầu ra asm của trình biên dịch độc đáo, loại bỏ "nhiễu" của các lệnh, vì vậy tôi khuyên bạn nên sử dụng nó để xem asm cho các hàm đơn giản lấy args và trả về giá trị (vì vậy chúng sẽ không tối ưu hóa đi).

Trong một thời gian, CL đã có sẵn trên http://gcc.beta.godbolt.org/ nhưng không phải là trang web chính, nhưng bây giờ nó đã có trên cả hai.


Để có được đầu ra asm MSVC từ trình biên dịch trực tuyến http://rextester.com/l/cpp_online_compiler_visual : Thêm /FAsvào các tùy chọn dòng lệnh. Có chương trình của bạn tìm đường dẫn riêng của nó và tìm ra đường dẫn đến .asmvà kết xuất nó. Hoặc chạy một trình dịch ngược trên .exe.

ví dụ: 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 ...

typelà phiên bản DOS của cat. Tôi không muốn bao gồm nhiều mã hơn khiến việc tìm các hàm tôi muốn xem asm trở nên khó khăn hơn. (Mặc dù sử dụng std :: string và boost run đối với các mục tiêu đó! Một số thao tác chuỗi kiểu C tạo ra nhiều giả định về chuỗi mà nó xử lý (và bỏ qua an toàn / phân bổ độ dài tối đa bằng cách sử dụng bộ đệm lớn) trên kết quả củaGetModuleFileNameA Would ít hơn nhiều tổng mã máy.)

IDK tại sao, nhưng cout << p.string() << endlchỉ hiển thị tên cơ sở (tức là tên tệp, không có thư mục), mặc dù việc in chiều dài của nó cho thấy nó không chỉ là tên trần. (Chromium48 trên Ubuntu 15.10). Có thể có một số xử lý thoát dấu gạch chéo ngược tại một số điểm couthoặc giữa thiết bị xuất chuẩn của chương trình và trình duyệt web.


@MichaelPetch: oh, hóa ra đó những gì tôi đã thử. .c_str()in những gì trông giống như một con trỏ. Nếu bạn theo liên kết, bạn sẽ thấy mã để hexdump a std::string(bị vô hiệu hóa #if 0). Hóa ra chuỗi này là tốt, nhưng coutkhông đưa nó vào trình duyệt web. Không có bất kỳ ký tự không phải ascii nào, chỉ là dấu gạch chéo ngược.
Peter Cordes

Tôi có thể thiếu một cái gì đó nhưng khi bạn subdir--; p /= *subdir;không giảm p thành tên tệp? Hoặc có thể tôi đang hiểu nhầm những gì bạn đang cố gắng in.
Michael Petch

Tôi đoán tôi không hoàn toàn hiểu được subdir--tiếp theo p /= *subdirkhi subdirban đầup.end()
Michael Petch

@MichaelPetch: bình luận cập nhật. Tôi cần phải lấy thành phần thư mục cuối cùng của đường dẫn để sử dụng làm tên tệp. Nó làm việc, nhưng tôi phải mất một thời gian dài để làm việc vì tôi nghĩ rằng GetModuleFileNameAnó chỉ trở lại a.exe. Mãi cho đến khi tôi lục lại nó và in độ dài mà tôi biết nó đang hoạt động, và tôi có thể để chương trình điều khiển đường dẫn, tôi chỉ không thể in đường dẫn
Peter Cordes

1
Vâng, dường như là phần \\r(tốt \rkhi trình biên dịch xuất nó) một phần của tên tệp mà nó dịch kém khi kết xuất cho trình duyệt web. Sử dụng p.generic_string()các công việc nhưng dấu gạch chéo ngược là dấu gạch chéo về phía trước.
Michael Petch

5

Trong Visual C ++, các tùy chọn dự án bên dưới, Tệp đầu ra tôi tin rằng có một tùy chọn để xuất danh sách ASM với mã nguồn. Vì vậy, bạn sẽ thấy mã nguồn C / C ++ và ASM kết quả tất cả trong cùng một tệp.


5

Đối với MSVC bạn có thể sử dụng trình liên kết.

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

foo.pdb cần phải có sẵn để có được các biểu tượng


1

.NET Reflector của Red Gate là một công cụ khá tuyệt vời đã giúp tôi nhiều hơn một vài lần. Điểm cộng của tiện ích này ngoài việc dễ dàng hiển thị cho bạn MSIL là bạn có thể phân tích rất nhiều DLL của bên thứ ba và có Reflector đảm nhiệm việc chuyển đổi MSIL sang C # và VB.

Tôi không hứa rằng mã sẽ rõ ràng như nguồn nhưng bạn không nên gặp nhiều rắc rối khi theo dõi nó.


2
Lưu ý: chỉ áp dụng cho các hội đồng được quản lý không được tháo gỡ như trong trình biên dịch chương trình, mã asm.
sean e

Điểm hay, tôi đọc nó là "hai dòng mã giống nhau trong tập hợp" thay vì "là hai dòng mã giống nhau trong tập hợp"
Dave L

Nó sẽ chỉ hoạt động trên các ứng dụng dotnet, trình liên kết hoặc trình biên dịch Not Visual C ++.
Muhammad Ali

1

Nếu bạn đang nói về việc gỡ lỗi để xem mã lắp ráp, cách dễ nhất là Gỡ lỗi-> Windows-> Tháo gỡ (hoặc Alt-8). Điều này sẽ cho phép bạn bước vào một chức năng được gọi và ở lại trong Tháo gỡ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.