stringtranslate.com

Lengua Intermedia Común

El lenguaje intermedio común ( CIL ), anteriormente llamado lenguaje intermedio de Microsoft ( MSIL ) o lenguaje intermedio ( IL ), [1] es el conjunto de instrucciones binarias del lenguaje intermedio definido dentro de la especificación de infraestructura de lenguaje común (CLI). [2] Las instrucciones CIL se ejecutan mediante un entorno de ejecución compatible con CIL, como Common Language Runtime . Los idiomas destinados a la CLI se compilan en CIL. CIL es un código de bytes basado en pilas y orientado a objetos . Los tiempos de ejecución normalmente compilan instrucciones CIL justo a tiempo en código nativo .

CIL se conocía originalmente como Microsoft Intermediate Language (MSIL) durante las versiones beta de los lenguajes .NET. Debido a la estandarización de C# y CLI, el código de bytes ahora se conoce oficialmente como CIL. [3] Las definiciones de virus de Windows Defender continúan refiriéndose a los archivos binarios compilados con él como MSIL. [4]

información general

Durante la compilación de los lenguajes de programación CLI , el código fuente se traduce a código CIL en lugar de a código objeto específico de la plataforma o del procesador . CIL es un conjunto de instrucciones independiente de la CPU y la plataforma que se puede ejecutar en cualquier entorno que admita la infraestructura de lenguaje común, como el tiempo de ejecución .NET en Windows o el tiempo de ejecución Mono multiplataforma . En teoría, esto elimina la necesidad de distribuir diferentes archivos ejecutables para diferentes plataformas y tipos de CPU. La seguridad del código CIL se verifica durante el tiempo de ejecución, lo que proporciona mayor seguridad y confiabilidad que los archivos ejecutables compilados de forma nativa. [5] [6]

El proceso de ejecución se ve así:

  1. El código fuente se convierte a código de bytes CIL y se crea un ensamblaje CLI .
  2. Tras la ejecución de un ensamblado CIL, su código pasa a través del compilador JIT del tiempo de ejecución para generar código nativo. También se puede utilizar la compilación anticipada, lo que elimina este paso, pero a costa de la portabilidad del archivo ejecutable.
  3. El procesador de la computadora ejecuta el código nativo.

Instrucciones

El código de bytes CIL tiene instrucciones para los siguientes grupos de tareas:

Modelo computacional

El lenguaje intermedio común está orientado a objetos y basado en pilas , lo que significa que los parámetros y resultados de las instrucciones se mantienen en una sola pila en lugar de en varios registros u otras ubicaciones de memoria, como en la mayoría de los lenguajes de programación .

Código que suma dos números en lenguaje ensamblador x86 , donde eax y edx especifican dos registros diferentes de propósito general :

agregar eax , edx  

Código en un lenguaje intermedio (IL), donde 0 es eax y 1 es edx:

ldloc . 0 // empuja la variable local 0 a la pila ldloc . 1 // empuja la variable local 1 a la pila add // saca y agrega los dos elementos superiores de la pila y luego empuja el resultado a la pila stloc . 0 // extrae y almacena el elemento de la pila superior en la variable local 0    

En el último ejemplo, los valores de los dos registros, eax y edx, se colocan primero en la pila. Cuando se llama a la instrucción de adición, los operandos se "explotan" o se recuperan, y el resultado se "empuja" o se almacena en la pila. Luego, el valor resultante se extrae de la pila y se almacena en eax.

Conceptos orientados a objetos

CIL está diseñado para estar orientado a objetos. Puede crear objetos, llamar a métodos y utilizar otros tipos de miembros, como campos.

Cada método necesita (con algunas excepciones) residir en una clase. También lo hace este método estático:

. clase pública Foo { . método público estático int32 Agregar ( int32 , int32 ) cil administrado { . maxstack 2 ldarg . 0 // carga el primer argumento; ldarg . 1 // carga el segundo argumento; agregar // agregarlos; ret // devuelve el resultado; } }                       

El método Add no requiere que se declare ninguna instancia de Foo porque se declara como estático y luego se puede usar así en C#:

int r = Foo . Añadir ( 2 , 3 ); // 5     

En CIL se vería así:

PMA . i4 . 2 PMA . i4 . 3 llamar a int32 Foo :: Agregar ( int32 , int32 ) stloc . 0   

Clases de instancia

Una clase de instancia contiene al menos un constructor y algunos miembros de instancia . La siguiente clase tiene un conjunto de métodos que representan acciones de un objeto Car.

. coche público de clase { . método nombre especial público rtnombre especial instancia vacía . ctor ( int32 , int32 ) cil administrado { /* Constructor */ }                 . método public void Move ( int32 ) cil administrado { /* Omitiendo implementación */ } . método public void TurnRight () cil administrado { /* Omitiendo implementación */ } . método public void TurnLeft () cil administrado { /* Omitiendo implementación */ } . método public void Brake () cil administrado { /* Omitiendo implementación */ } }                                   

Creando objetos

En C# las instancias de clase se crean así:

Coche miCoche = Coche nuevo ( 1 , 4 ); Coche tuCoche = coche nuevo ( 1 , 3 );           

Y esas declaraciones son más o menos las mismas que estas instrucciones en CIL:

PMA . i4 . 1 PMA . i4 . 4 instancia de newobj void Car ::. ctor ( int , int ) stloc . 0 // miCoche = coche nuevo(1, 4); PMA . i4 . 1 PMA . i4 . 3 instancia de newobj void Car ::. ctor ( int , int ) stloc . 1 // tuCoche = coche nuevo(1, 3);          

Invocar métodos de instancia

Los métodos de instancia se invocan en C# como el siguiente:

mi coche . Mover ( 3 );

Como se invoca en CIL:

ldloc . 0 // Carga el objeto "myCar" en la pila ldc . i4 . 3 instancia de llamada void Car :: Move ( int32 )    

Metadatos

La Common Language Infrastructure (CLI) registra información sobre las clases compiladas como metadatos . Al igual que la biblioteca de tipos en el modelo de objetos componentes , esto permite que las aplicaciones admitan y descubran las interfaces, clases, tipos, métodos y campos en el ensamblaje. El proceso de lectura de dichos metadatos se denomina " reflexión ".

Los metadatos pueden ser datos en forma de "atributos". Los atributos se pueden personalizar ampliando la Attributeclase. Esta es una característica poderosa. Permite al creador de la clase la posibilidad de adornarla con información adicional que los consumidores de la clase pueden utilizar de varias maneras significativas, según el dominio de la aplicación.

Ejemplo

A continuación se muestra un "¡Hola, mundo!" básico. Programa escrito en ensamblador CIL. Mostrará la cadena "¡Hola, mundo!".

. ensamblaje Hola {} . ensamblador externo mscorlib {} . método static void Main () { . punto de entrada . maxstack 1 ldstr "¡Hola mundo!" llamar al sistema void [ mscorlib ] . Consola :: WriteLine ( cadena ) ret }                 

El siguiente código es más complejo en número de códigos de operación.

Este código también se puede comparar con el código correspondiente en el artículo sobre código de bytes de Java .

static void Main ( string [] args ) { for ( int i = 2 ; i < 1000 ; i ++ ) { for ( int j = 2 ; j < i ; j ++ ) { if ( i % j == 0 ) ir al exterior ; } Consola . Línea de escritura ( yo ); exterior :; } }                                   

En la sintaxis del ensamblador CIL se ve así:

. método privado hidebysig estático vacío Principal ( cadena [] args ) cil administrado { . punto de entrada . pila máxima 2 . inicio local ( int32 V_0 , int32 V_1 )                  PMA . i4 .2 stloc .0 br . s IL_001f IL_0004 : PMA . i4 .2 stloc .1 br . s IL_0011 IL_0008 : ldloc .0 ldloc .1 rem brfalse . s IL_001b ldloc .1 ldc . i4 .1 agregar stloc .1 IL_0011 : ldloc .1 ldloc .0 blt . s IL_0008 ldloc .0 llamada nula [ mscorlib ] Sistema . Consola :: WriteLine ( int32 ) IL_001b : ldloc .0 ldc . i4 .1 agregar stloc .0 IL_001f : ldloc .0 ldc . i4 0x3e8 blt . s IL_0004 retir }                                       

Esta es solo una representación de cómo se ve CIL cerca del nivel de máquina virtual (VM). Cuando se compilan, los métodos se almacenan en tablas y las instrucciones se almacenan como bytes dentro del ensamblado, que es un ejecutable portátil (PE).

Generación

Un ensamblado CIL y sus instrucciones se generan mediante un compilador o una utilidad llamada IL Assembler ( ILAsm ) que se envía con el entorno de ejecución.

El CIL ensamblado también se puede desarmar en código nuevamente usando el Desensamblador de IL (ILDASM). Existen otras herramientas como .NET Reflector que pueden descompilar CIL en un lenguaje de alto nivel (por ejemplo, C# o Visual Basic ). Esto convierte a CIL en un objetivo muy fácil para la ingeniería inversa. Este rasgo se comparte con el código de bytes de Java . Sin embargo, existen herramientas que pueden ofuscar el código y lo hacen de manera que el código no sea fácilmente legible pero sí ejecutable.

Ejecución

Compilación justo a tiempo

La compilación justo a tiempo (JIT) implica convertir el código de bytes en código inmediatamente ejecutable por la CPU. La conversión se realiza gradualmente durante la ejecución del programa. La compilación JIT proporciona optimización específica del entorno, seguridad del tipo de tiempo de ejecución y verificación de ensamblaje. Para lograr esto, el compilador JIT examina los metadatos del ensamblado en busca de accesos ilegales y maneja las violaciones de manera adecuada.

Compilación anticipada

Los entornos de ejecución compatibles con CLI también vienen con la opción de realizar una compilación anticipada (AOT) de un ensamblado para que se ejecute más rápido eliminando el proceso JIT en tiempo de ejecución.

En .NET Framework existe una herramienta especial llamada Native Image Generator (NGEN) que realiza el AOT. Un enfoque diferente para AOT es CoreRT que permite la compilación de código .Net Core en un único ejecutable sin dependencia de un tiempo de ejecución. En Mono también existe la opción de hacer un AOT.

Instrucciones de puntero: C++/CLI

Una diferencia notable con el código de bytes de Java es que CIL viene con ldind, stind, ldlocay muchas instrucciones de llamada que son suficientes para la manipulación de punteros de datos/funciones necesarios para compilar código C/C++ en CIL.

clase A { público : virtual void __stdcall meth () {} }; void test_pointer_operaciones ( int param ) { int k = 0 ; int * ptr = & k ; * ptr = 1 ; ptr = & parámetro ; * ptr = 2 ; Una una ; A * ptra = &a a ; ptra -> metanfetamina (); }                             

El código correspondiente en CIL se puede representar así:

. método ensamblado modopt vacío estático ([ mscorlib ] System . Runtime . CompilerServices . CallConvCdecl ) test_pointer_operaciones ( int32 param ) cil administrado { . vtentry 1 : 1 // Tamaño del código 44 (0x2c) . pila máxima 2 . locales ([ 0 ] int32 * ptr , [ 1 ] tipo de valor A * V_1 , [ 2 ] tipo de valor A * a , [ 3 ] int32 k ) // k = 0; IL_0000 : PMA . i4 .0 IL_0001 : stloc .3 // ptr = &k; IL_0002 : ldloca . s k // carga la instrucción de dirección local IL_0004 : stloc .0 // *ptr = 1; IL_0005 : ldloc .0 IL_0006 : ldc . i4 .1 IL_0007 : stind . i4 // instrucción de indirección // ptr = ¶m IL_0008 : ldarga . s param // carga la instrucción de dirección del parámetro IL_000a : stloc .0 // *ptr = 2 IL_000b : ldloc .0 IL_000c : ldc . i4 .2 IL_000d : stind . i4 // a = nueva A; IL_000e : ldloca . s a IL_0010 : llamada tipo de valor A * modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvThiscall ) ' A .{ ctor } ' ( tipo de valor A * modopt ([ mscorlib ]                                                                        Sistema . Tiempo de ejecución . Servicios del compilador . IsConst ) modopt ([ mscorlib ] Sistema . Tiempo de ejecución . CompilerServices . IsConst )) IL_0015 : pop // ptra = &a; IL_0016 : ldloca . s a IL_0018 : stloc .1 // ptra->meth(); IL_0019 : ldloc .1 IL_001a : dup IL_001b : ldind . i4 // leyendo el VMT para la llamada virtual IL_001c : ldind . i4 IL_001d : calli stdcall no administrado void modopt ([ mscorlib ] System . Runtime . CompilerServices . CallConvStdcall )( nativo int ) IL_0022 : ret } // fin del método 'Funciones globales'::test_pointer_operaciones                           

Ver también

Referencias

  1. ^ "Lenguaje intermedio y ejecución".
  2. ^ "Infraestructura de lenguaje común (CLI) ECMA-335".
  3. ^ "¿Qué es el lenguaje intermedio (IL)/MSIL/CIL en .NET?" . Consultado el 17 de febrero de 2011 . CIL: ... Cuando compilamos [a]. NET, no se convierte directamente a código binario sino al lenguaje intermedio. Cuando se ejecuta un proyecto, cada lenguaje de programación .NET se convierte en código binario en CIL. Sólo una parte de CIL que se requiere en tiempo de ejecución se convierte en código binario. DLL y EXE de .NET también están en formato CIL.
  4. ^ "HackTool: MSIL/SkypeCracker". Microsoft . Consultado el 26 de noviembre de 2019 .
  5. ^ Troelsen, Andrew (2 de mayo de 2009). Beneficios del CIL. ISBN 9781590598849. Consultado el 17 de febrero de 2011 .
  6. ^ "Extensiones administradas y no administradas para C++, administradas y .Net Framework". www.visualcplusdotnet.com . Consultado el 7 de julio de 2020 .

Otras lecturas

enlaces externos