Tôi quan tâm đến việc xem đầu ra lắp ráp x86 thực tế bằng chương trình C# (không phải hướng dẫn bytecode CLR). Có cách nào tốt để làm điều này?Truy xuất đầu ra JIT
Trả lời
Bạn nên sử dụng WinDbg với SOS/SOSEX, đảm bảo rằng phương pháp bạn muốn xem mã x86 là JITted trong bảng phương thức và sau đó xem gỡ bỏ thực tế với lệnh u
. Vì vậy, bạn sẽ thấy mã thực tế.
Như những người khác được đề cập ở đây, với ngen bạn có thể thấy mã không khớp chính xác với kết quả biên dịch JIT thực tế. Với Visual Studio nó cũng có thể bởi vì biên dịch của JIT phụ thuộc rất nhiều vào thực tế nếu trình gỡ lỗi có mặt hay không.
UPD: Một số làm rõ. WinDbg cũng là một trình gỡ lỗi, nhưng nó là gốc một.
Here bạn có thể đọc kỹ về kỹ thuật này.
Trong khi gỡ lỗi ứng dụng của bạn trong Visual Studio, bạn có thể nhấp chuột phải vào mã mà bạn đã dừng (sử dụng điểm ngắt) và nhấp vào "Chuyển sang tháo gỡ". Bạn có thể gỡ lỗi thông qua các hướng dẫn gốc.
Để làm điều đó với tệp * .exe trên đĩa, có thể bạn sử dụng NGen để tạo ra đầu ra gốc và sau đó tháo rời (mặc dù tôi chưa bao giờ thử điều đó, vì vậy tôi không thể đảm bảo rằng nó sẽ hoạt động).
Dưới đây là một số opcodes mẫu từ hoạt động số học đơn giản mà được viết bằng C#:
int x = 5; mov dword ptr [ebp-40h],5 int y = 6; mov dword ptr [ebp-44h],6 int z = x + y; mov eax,dword ptr [ebp-40h] add eax,dword ptr [ebp-44h] mov dword ptr [ebp-48h],eax
Bạn có thể sử dụng Visual Studio Debugger bằng cách đặt một breakpoint và sau đó xem cửa sổ Dissassembly (Alt + Ctrl + D) hoặc thử Native Image Generator Tool (ngen.exe).
Bạn có thể thực hiện kết xuất bộ nhớ. Tuy nhiên, lưu ý rằng mã trong bộ nhớ không nhất thiết phải chứa mọi phương thức.
Ngừng thực hiện AOT hoặc Tạo mã theo thời gian, có thể khác với mã JIT.
Là @IvanDanilov answered, bạn có thể sử dụng WinDbg và SOS. Tôi đang trả lời riêng để cung cấp một bước đi.
Trong ví dụ này, tôi muốn xem tháo của phương pháp AreEqual() từ:
using System;
namespace TestArrayCompare
{
class Program
{
static bool AreEqual(byte[] a1, byte[] a2)
{
bool result = true;
for (int i = 0; i < a1.Length; ++i)
{
if (a1[i] != a2[i])
result = false;
}
return result;
}
static void Main(string[] args)
{
byte[] a1 = new byte[100];
byte[] a2 = new byte[100];
if (AreEqual(a1, a2))
{
Console.WriteLine("`a1' equals `a2'.");
}
else
{
Console.WriteLine("`a1' does not equal `a2'.");
}
}
}
}
bước:
- mở WinDbg. Từ trình đơn Tệp, chọn "Mở thực thi ...". Duyệt đến vị trí của EXE (trong trường hợp của tôi là
C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release\TestArrayCompare.exe
). Thêm thư mục chứa tệp PDB vào đường dẫn biểu tượng.Ví dụ:
.sympath "C:\Users\Daniel\Documents\Visual Studio 2013\Projects\TestArrayCompare\TestArrayCompare\bin\Release"
Trong cửa sổ Command WinDbg của, thiết lập một breakpoint khi
clr.dll
được nạp qua:sxe ld:clr
Tiếp tục bằng cách chạy 'Go' lệnh:
g
- Tại
clr.dll
ModLoad, tải SOS:.loadby sos clr
Chạy BPMD để phá vỡ phương pháp mà bạn sử dụng sh để xem việc tháo gỡ. Ví dụ:
0:000> !BPMD TestArrayCompare.exe TestArrayCompare.Program.AreEqual Adding pending breakpoints...
Tiếp tục một lần nữa bằng cách chạy lệnh 'Go':
g
Run Name2EE để xem mô tả phương pháp. Ví dụ:
0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual Module: 00a62edc Assembly: TestArrayCompare.exe Token: 06000001 MethodDesc: 00a637a4 Name: TestArrayCompare.Program.AreEqual(Byte[], Byte[]) Not JITTED yet. Use !bpmd -md 00a637a4 to break on run.
Chạy lệnh BPMD trong dòng "Chưa được JITTED". Ví dụ:
0:000> !bpmd -md 00a637a4 MethodDesc = 00a637a4 Adding pending breakpoints...
Tiếp tục một lần nữa:
g
Bạn sẽ thấy "JITted ..." trong cửa sổ lệnh. Chạy lại lệnh Name2EE để xem địa chỉ của mã JIT. Ví dụ:
0:000> !Name2EE TestArrayCompare.exe TestArrayCompare.Program.AreEqual Module: 00a62edc Assembly: TestArrayCompare.exe Token: 06000001 MethodDesc: 00a637a4 Name: TestArrayCompare.Program.AreEqual(Byte[], Byte[]) JITTED Code Address: 00b500c8
Sử dụng lệnh
u
để tháo rời, bắt đầu từ địa chỉ mã được liệt kê. Ví dụ:0:000> u 00b500c8 L20 00b500c8 55 push ebp 00b500c9 8bec mov ebp,esp 00b500cb 57 push edi 00b500cc 56 push esi ...
(Đối với ở trên, tôi đã sử dụng WinDbg 6.3.9600.17200 X86 từ Windows 8.1 SDK.)
Một tài liệu tham khảo có ích là SOS.dll (SOS Debugging Extension) reference page on MSDN.
Lưu ý rằng bạn cần thực hiện theo các bước [tại đây] (https://stackoverflow.com/a/4678883/238419) nếu bạn muốn xem mã được tối ưu hóa thực tế –