Một cách để làm điều đó là để đổ IL tương ứng với phương pháp mà các mảng đã được tạo ra trong.
Thứ nhất, sử dụng !clrstack
để có được những phương pháp mà bạn đang ở. Trong trường hợp của tôi, tôi đang ở một ứng dụng giả trong phương pháp Main
:
0:000> !clrstack
OS Thread Id: 0x7d0 (0)
Child SP IP Call Site
0016f094 758dc42d [HelperMethodFrame: 0016f094]
0016f120 003200af ConsoleApplication4.Program.Main(System.String[]) [c:\Users\smt\Documents\Visual Studio 2012\Projects\ConsoleApplication4\Program.cs @ 215]
0016f2bc 743b3de2 [GCFrame: 0016f2bc]
tiếp theo sử dụng !name2ee
để có được những desc phương pháp của phương pháp này (lệnh tiếp theo cần nó):
0:000> !name2ee ConsoleApplication4!ConsoleApplication4.Program.Main
Module: 00282eac
Assembly: ConsoleApplication4.exe
Token: 0600013c
MethodDesc: 00283dbc
Name: ConsoleApplication4.Program.Main(System.String[])
JITTED Code Address: 00320050
Bây giờ, đổ IL của phương pháp này:
0:000> !dumpil 00283dbc
ilAddr = 002d4bc4
IL_0000: nop
IL_0001: newobj class [mscorlib]System.Collections.Generic.List`1<?????? ??????n?.::.ctor
IL_0006: stloc.0
IL_0007: br.s IL_001e
IL_0009: nop
IL_000a: ldc.i4 2147483647
IL_000f: newarr System.Single
IL_0014: stloc.1
IL_0015: ldloc.0
IL_0016: ldloc.1
IL_0017: callvirt class [mscorlib]System.Collections.Generic.List`1<?????? ??????N?.::Add
IL_001c: nop
IL_001d: nop
IL_001e: ldc.i4.1
IL_001f: stloc.2
IL_0020: br.s IL_0109
Để so sánh, đây là phương pháp của tôi trong C#:
static void Main(string[] args)
{
List<float[]> arrays = new List<float[]>();
while (true)
{
float[] f = new float[Int32.MaxValue];
arrays.Add(f);
}
Console.ReadKey();
}
Bạn có thể nhìn thấy trên đường IL_000f rằng một mảng mới của loại System.Single
đang được tạo .
Tôi đã đi xuống con đường này vì tôi không thể giải mã đối số được chuyển đến phương thức gốc thực tế tạo mảng. Nếu bạn chạy kb
tại điểm ngoại lệ được ném:
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0016efa4 74502a42 e0434352 00000001 00000005 KERNELBASE!RaiseException+0x58
0016f048 745d55ef 00000000 bc1d0b3d 0016f10c clr!RaiseTheExceptionInternalOnly+0x276
0016f078 7464ae51 bc1d0a7d 0016f150 00000000 clr!UnwindAndContinueRethrowHelperAfterCatch+0x83
0016f118 003200af 00000000 02202480 00000000 clr!JIT_NewArr1+0x1af
0016f138 743b3de2 00720198 0016f198 743c3315 0x3200af
0016f144 743c3315 0016f1dc 0016f188 74502c66 clr!CallDescrWorkerInternal+0x34
...
Bạn có thể thấy rằng clr!JIT_NewArr1
đang được gọi, mà tạo ra một mảng một chiều. Để làm điều đó, it needs the type and the size. Những lập luận này được sao chép vào ecx
và edx
, tương ứng:
0:000> !u 003200AF
...
003200a0 b9e2302a73 mov ecx,offset mscorlib_ni+0x30e2 (732a30e2)
003200a5 baffffff7f mov edx,7FFFFFFFh
003200aa e89121f5ff call 00272240 (JitHelp: CORINFO_HELP_NEWARR_1_VC)
>>> 003200af 8945e8 mov dword ptr [ebp-18h],eax
003200b2 8b45e8 mov eax,dword ptr [ebp-18h]
003200b5 8945f0 mov dword ptr [ebp-10h],eax
...
Như bạn thấy, ecx
được 732a30e2
, mà bằng cách nào đó các bản đồ với các thông tin kiểu cho System.Single
, nhưng tôi không thể tìm ra cách ...
Loại mảng thực sự được truyền trong ECX. Tuy nhiên, thay vì mã thông báo siêu dữ liệu thông thường, nó là một 'xử lý cho một mã thông báo siêu dữ liệu'. Điều này được tạo ra bởi JIT. Tôi không biết cách nào để chuyển từ thẻ điều khiển sang mã thông báo siêu dữ liệu gốc. Thay vào đó, kể từ khi IL tồn tại, nó dễ dàng hơn để xem nó để xác định loại mảng. – Dono