Это похоже на проблему в сгенерированном IL для метода test
. В точке сбоя мы читаем **c
, а c
- местный номер 5.
IL_00a5 11 05 ldloc.s 0x5
IL_00a7 4a ldind.i4
IL_00a8 4f ldind.r8
IL_00a9 28 11 00 00 0a call 0xA000011
Итак, мы видим, что IL говорит загрузить значение c
, затем загрузить 4-байтовое целое число со знаком, затем обработать это целое число как указатель и загрузить 8-байтовый вещественный тип (double).
На 64-битной платформе указатели должны быть либо нейтральными по размеру, либо 64-битными. Таким образом, ldind.i4
проблематичен, поскольку базовый адрес составляет 8 байтов. И поскольку IL определяет чтение только 4 байта, jit должен расширить результат, чтобы получить 8-байтовое значение. Здесь он решает подписать расширение.
library.h @ 27:
00007ffd`b0cf2119 488b45a8 mov rax,qword ptr [rbp-58h]
00007ffd`b0cf211d 8b00 mov eax,dword ptr [rax]
00007ffd`b0cf211f 4863c0 movsxd rax,eax // **** sign extend ****
>>> 00007ffd`b0cf2122 c4e17b1000 vmovsd xmm0,qword ptr [rax]
00007ffd`b0cf2127 e854f6ffff call System.Console.WriteLine(Double) (00007ffd`b0cf1780)
Вам, очевидно, повезло, когда вы работаете на полной платформе, поскольку адрес массива мал и умещается в 31 бит или менее, поэтому чтение 4 байтов и последующее расширение знака до 8 байтов по-прежнему дает правильный адрес. Но на Core это не так, поэтому приложение там падает.
Похоже, вы создали свою библиотеку, используя цель Win32. Если вы перестроите его с целью x64, IL будет использовать 64-битную загрузку для *c
:
IL_00ab: ldloc.s V_5
IL_00ad: ldind.i8
IL_00ae: ldind.r8
IL_00af: call void [mscorlib]System.Console::WriteLine(float64)
и приложение работает нормально.
Похоже, что это особенность C ++ / CLI - создаваемые им двоичные файлы неявно зависят от архитектуры даже в чистом режиме. Только /clr:safe
может создавать независимые от архитектуры сборки, и вы не можете использовать это с этим кодом, поскольку он содержит непроверяемые конструкции, такие как указатели.
Также обратите внимание, что не все функции C ++ / CLI поддерживаются в .Net Core 2.x. В этом конкретном примере избегаются неподдерживаемые биты, но более сложные могут этого не делать.