Force x86 CLR на сборке "Любой процессор".NET

В .NET параметр компилятора "Платформа целевой: любой процессор" позволяет сборке .NET работать как 64 бит на машине x64, так и 32 бит на машине x86. Также возможно заставить сборку работать как x86 на машине x64 с использованием компилятора "Платформа Target: x86".

Возможно ли запустить сборку с флагом "Любой процессор", но определить, следует ли ее запускать в CLR x86 или x64? Обычно это решение выполняется загрузчиком CLR/OS (как я понимаю) на основе битности базовой системы.

Я пытаюсь написать приложение С#.NET, которое может взаимодействовать с (прочитайте: вставляйте код) в другие запущенные процессы. Процессы x64 могут только внедряться в другие процессы x64 и то же самое с x86. В идеале я хотел бы воспользоваться компиляцией JIT и опцией Any CPU, чтобы можно было использовать одно приложение для ввода в процессы x64 или x86 (на машине x64).

Идея заключается в том, что приложение будет скомпилировано как любой процессор. На машине x64 она будет работать как x64. Если целевой процесс равен x86, он должен перезапустить себя, заставляя CLR запускать его как x86. Возможно ли это?

Ответ 1

Вы можете найти, как приложение будет запускаться и изменять его статически с помощью приложения CorFlags. Чтобы узнать, как приложение будет работать, используйте:

corflags <PathToExe>

Чтобы изменить способ запуска приложения, используйте:

corflags /32bit+  <PathToExe>

Это приведет к тому, что EXE файл будет запущен как 32-разрядный процесс. Информация о том, как должна выполняться сборка, хранится в заголовке PE. См. Вопрос о переполнении стека Как найти, если собственный DLL файл скомпилирован как x64 или x86?.

Если вы хотите ввести код во время выполнения, вам нужно написать .NET в С++/COM. См. .NET Internals: API профилирования и Профилирование (Unmanaged API Reference ) для получения более подробной информации.

Вам нужно будет реализовать обратный вызов JitCompilationStarted и выполнять свою работу там. Если вы находитесь в этом направлении, вам нужно будет создать инъецируемый DLL файл как x86, так и x64. Собственные DLL файлы будут загружены CLR после установки следующих переменных среды:

Cor_Enable_Profiling=0x1
COR_PROFILER={CLSID-of-your-native-DLL-file}

Если вы его правильно установили, то 64-битная версия увидит 64-битные процессы, а 32-разрядная версия увидит 32-битные процессы.

Ответ 2

Прошло некоторое время с тех пор, как я пробовал это, но я считаю, что битность процесса, вызывающего сборку, определяет, будет ли она JITed как x86 или x64.

Итак, если вы пишете небольшое консольное приложение и создаете его как x86, а другое как x64, то запущенный тот или другой приведет к тому, что другие сборки загрузятся в процесс для запуска как 32 или 64 бит. Это, конечно, предполагает, что вы работаете на 64-битной машине.

Ответ 3

Я не уверен, смогу ли я помочь вам в этом. Но это мой опыт.

У меня есть хост-приложение, A.exe (скомпилировано как x86), и у меня есть клиентское приложение B.exe (скомпилировано как ANY CPU) из хост-приложения. И я запускаю B.exe из A.exe, используя System.Diagnostic.Process класс.

Проблема теперь в том, что если я поместил два на машину x64, то A.exe будет выполняться как x86, , тогда как B.exe будет работать как x64.

Но если A.exe вызывает сборку c (c.dll, которая скомпилирована как ANY CPU), а B.exe также вызывает c.dll, то c.dll будет следовать за приложением, которое ее вызывает. Другими словами, на 64-битной машине, когда A.exe вызывает ее, она будет вести себя как x86 dll, тогда как при вызове B.exe она будет вести себя как x64.

Ответ 4

Я сделал что-то подобное, создав два (действительно три) двоичных файла. Я обнаружил, что процесс, который я пытался внедрить, был 32 или 64-битным. Затем этот процесс запускает либо 32-битную, либо 64-разрядную версию вашего двоичного кода для инъекций (в отличие от перезапуска, как вы упомянули).

Это звучит беспорядочно, но вы можете легко достичь этого во время сборки с событием после сборки, которое делает копию вашего выходного двоичного файла и использует CorFlags, чтобы заставить копию работать как 32-разрядная. Таким образом, вам не нужно развертывать утилиту CorFlags с вашим приложением, что по какой-то причине, по всей видимости, не является законным.

Я думаю, что это очень похоже на вашу первоначальную идею и на самом деле не требует больше работы, за исключением события с двумя строками.