2009-10-02 15 views
57

In .NET, l'opzione del compilatore "Piattaforma target: qualsiasi CPU" consente a un assembly .NET di funzionare come 64   bit su un computer x64 e 32   bit su una macchina x86. È anche possibile forzare un assembly a funzionare come x86 su una macchina x64 usando l'opzione del compilatore 'Piattaforma Target: x86'.Force x86 CLR su un assembly .NET "Any CPU"

È possibile eseguire un assembly con il flag "Any CPU", ma determinare se deve essere eseguito nel CLR x86 o x64? Normalmente questa decisione viene presa da CLR/OS Loader (come da mia comprensione) in base alla testimonianza del sistema sottostante.

Sto cercando di scrivere un'applicazione C# .NET in grado di interagire con (leggi: inserire codice in) altri processi in esecuzione. i processi x64 possono solo essere iniettati in altri processi x64 e lo stesso con x86. Idealmente, vorrei sfruttare la compilazione JIT e l'opzione Qualsiasi CPU per consentire a una singola applicazione di essere utilizzata per l'iniezione nei processi x64 o x86 (su una macchina x64).

L'idea è che l'applicazione sia compilata come Qualsiasi CPU. Su una macchina x64, sarebbe eseguito come x64. Se il processo di destinazione è x86, dovrebbe riavviarsi da solo, forzando il CLR a eseguirlo come x86. È possibile?

risposta

9

È stato un po 'di tempo da quando ho provato questo, ma credo che il testimone del processo che chiama l'assembly determina se sarà JIT come x86 o x64.

Quindi se si scrive una piccola applicazione di console e la si compila come x86 e un'altra come x64, l'esecuzione dell'uno o dell'altro farà sì che altri assembly caricati nel processo vengano eseguiti come 32 o 64 bit. Questo, ovviamente, presuppone che tu stia girando su una macchina a 64 bit.

+3

Sì, sono consapevole che è possibile forzarlo avvolgendolo in un assembly di avvio x86, ma mi chiedevo se fosse possibile forzarlo dinamicamente per assembly "Qualsiasi CPU" compilati. Grazie comunque, probabilmente tornerò su questo se non trovo altro. Sarebbe un voto negativo ma non abbastanza. – jeffora

+1

I processi sono a 64 bit o a 32 bit. Se l'assembly è caricato in un processo a 32 bit ed è costruito come Any CPU, verrà JIT come 32 bit, nel processo a 64 bit sarà JITed come 64. Come pensate di creare l'assembly che ospita i vostri assembly? – jnoss

6

Non sono sicuro di poterti aiutare con questo. Ma questa è la mia esperienza.

ho un'applicazione host, A.exe (compilato come x 86), e ho un'applicazione client, B.exe (compilato come ANY CPU), dall'applicazione host. E lancio B.exe da A.exe, utilizzando la classe System.Diagnostic.Process.

Il problema ora è se metto i due su una macchina x64, quindi A.exe verrà eseguito come x86, mentre il B.exe verrà eseguito x64.

Ma se A.exe chiamate assemblaggio c (c.dll, compilato come Any CPU), e B.exe chiamate anche c.dll, quindi C.dll seguirà l'applicazione che chiama. In altre parole, nella macchina a 64 bit quando lo chiama A.exe, si comporterà come x86 dll, mentre quando lo chiama B.exe, si comporterà come x64.

61

È possibile trovare il modo in cui l'applicazione verrà eseguita e modificarla staticamente utilizzando l'applicazione CorFlags. Per scoprire come l'applicazione funzionerà, uso:

corflags <PathToExe> 

Per modificare come l'applicazione funzionerà, uso:

corflags /32bit+ <PathToExe> 

Questo renderà il file EXE eseguito come un processo a 32 bit. Le informazioni su come deve essere eseguito l'assembly sono memorizzate nell'intestazione PE.Vedere la domanda Overflow stack How to find if a native DLL file is compiled as x64 or x86?.

Se si desidera inserire il codice in fase di esecuzione, è necessario scrivere un profiler .NET in C++/COM. Vedi .NET Internals: The Profiling API e Profiling (Unmanaged API Reference) per ulteriori dettagli.

È necessario implementare il callback JitCompilationStarted e svolgere il proprio lavoro lì. Se sei in questa direzione, dovrai costruire il file DLL iniettato sia come x86 che x64. I file DLL nativi verranno caricati dal CLR volta verranno impostati i seguenti variabili d'ambiente:

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

Se lo avete impostato correttamente poi la versione a 64 bit si 'vedere' i processi a 64 bit e il 32- la versione bit vedrà i processi a 32 bit.

+0

Grazie per le informazioni :) Ero a conoscenza dell'app corflags, ma mi chiedevo se esistesse un modo per ottenere un risultato simile a livello di codice in fase di esecuzione. – jeffora

+1

Una volta che il processo è in esecuzione, non c'è modo di cambiare il suo contesto! –

+0

Cambiare il contesto in fase di esecuzione non significa solo impostare un bit sull'intestazione PE, il processo a 32 bit è in esecuzione sotto il livello di emulazione WOW. Non riesco a vedere come il processo possa salvare il suo stato in fase di esecuzione, eseguire un cambio di contesto e continuare a funzionare. Vedere questo link: http://blogs.msdn.com/oldnewthing/archive/2008/12/22/9244582.aspx –

6

Ho fatto qualcosa di simile creando due (davvero tre) binari. Ho avuto uno rilevare se il processo che stavo cercando di iniettare era 32 o 64 bit. Questo processo avvierà quindi la versione a 32-bit o 64-bit del tuo binario di iniezione (invece di rilanciare se stesso come hai detto tu).

Sembra disordinato, ma è possibile ottenerlo facilmente in fase di produzione con un evento post-build che esegue una copia del file binario di output e utilizza l'utilità CorFlags per forzare l'esecuzione della copia come 32 bit. In questo modo non è necessario distribuire l'utilità CorFlags con l'applicazione, che probabilmente non è legale per qualche motivo comunque.

Penso che questo sia abbastanza simile alla tua idea iniziale e in realtà non richiede più lavoro se non per un evento di build a due righe.