Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El proceso de ejecución administrada incluye los pasos siguientes, que se describen en detalle más adelante en este tema:
- Elección de un compilador. Para obtener las ventajas proporcionadas por Common Language Runtime, debe usar uno o varios compiladores de lenguaje que tienen como destino el entorno de ejecución.
- Compilar el código en lenguaje intermedio. La compilación traduce el código fuente en lenguaje intermedio común (CIL) y genera los metadatos necesarios.
- Compilación de la CIL en código nativo. En tiempo de ejecución, un compilador Just-In-Time (JIT) convierte la CIL en código nativo. Durante esta compilación, el código debe pasar un proceso de comprobación que examine la CIL y los metadatos para averiguar si el código se puede determinar como seguro para tipos.
- Ejecutando código. Common Language Runtime proporciona la infraestructura que permite que la ejecución se realice y los servicios que se pueden usar durante la ejecución.
Elección de un compilador
Para obtener las ventajas proporcionadas por Common Language Runtime (CLR), debe usar uno o varios compiladores de lenguaje que tienen como destino el entorno de ejecución, como Visual Basic, C#, Visual C++, F#, o uno de muchos compiladores de terceros, como un compilador Eiffel, Perl o COBOL.
Dado que es un entorno de ejecución multilanguage, el entorno de ejecución admite una amplia variedad de tipos de datos y características de lenguaje. El compilador de lenguaje que usa determina qué características en tiempo de ejecución están disponibles y diseña el código con esas características. El compilador, no el tiempo de ejecución, establece la sintaxis que debe usar el código. Si el componente debe ser completamente utilizable por los componentes escritos en otros lenguajes, los tipos exportados del componente deben exponer solo las características de lenguaje que se incluyen en Common Language Specification (CLS). Puede usar el atributo CLSCompliantAttribute para asegurarse de que su código sea compatible con CLS. Para obtener más información, consulte Independencia del lenguaje y componentes independientes del lenguaje.
Compilar en CIL
Al compilar en código administrado, el compilador traduce el código fuente en lenguaje intermedio común (CIL), que es un conjunto independiente de CPU de instrucciones que se pueden convertir de forma eficaz en código nativo. CIL incluye instrucciones para cargar, almacenar, inicializar y llamar a métodos en objetos, así como instrucciones para operaciones aritméticas y lógicas, flujo de control, acceso directo a memoria, control de excepciones y otras operaciones. Antes de que se pueda ejecutar el código, la CIL debe convertirse en código específico de CPU, normalmente mediante un compilador Just-In-Time (JIT). Dado que Common Language Runtime proporciona uno o varios compiladores JIT para cada arquitectura de equipo que admite, el mismo conjunto de CIL puede compilarse JIT y ejecutarse en cualquier arquitectura compatible.
Cuando un compilador genera CIL, también genera metadatos. Los metadatos describen los tipos del código, incluida la definición de cada tipo, las firmas de los miembros de cada tipo, los miembros a los que hace referencia el código y otros datos que el tiempo de ejecución usa en tiempo de ejecución. La CIL y los metadatos se contienen en un archivo ejecutable portátil (PE) que se basa en el formato de archivo ejecutable publicado por Microsoft PE y extiende el formato común de archivo de objeto (COFF), usado históricamente para contenido ejecutable. Este formato de archivo, que admite CIL o código nativo, así como metadatos, permite al sistema operativo reconocer imágenes de Common Language Runtime. La presencia de metadatos en el archivo junto con CIL permite que el código se describa a sí mismo, lo que significa que no hay necesidad de bibliotecas de tipos ni lenguaje de definición de interfaz (IDL). El tiempo de ejecución busca y extrae los metadatos del archivo según sea necesario durante la ejecución.
Compilación de la CIL en código nativo
Para poder ejecutar el lenguaje intermedio común (CIL), debe compilarse en Common Language Runtime en código nativo para la arquitectura de la máquina de destino. .NET proporciona dos maneras de realizar esta conversión:
- Un compilador Just-In-Time (JIT) de .NET.
- Ngen.exe (Generador de imágenes nativas).
Compilación por el compilador JIT
La compilación JIT convierte la CIL en código nativo a petición en tiempo de ejecución de la aplicación, cuando se carga y ejecuta el contenido de un ensamblado. Dado que Common Language Runtime proporciona un compilador JIT para cada arquitectura de CPU compatible, los desarrolladores pueden crear un conjunto de ensamblados de CIL que se pueden compilar y ejecutar en diferentes equipos con diferentes arquitecturas de máquina. Sin embargo, si el código administrado llama a api nativas específicas de la plataforma o una biblioteca de clases específica de la plataforma, solo se ejecutará en ese sistema operativo.
La compilación JIT tiene en cuenta la posibilidad de que nunca se llame a algún código durante la ejecución. En lugar de usar el tiempo y la memoria para convertir toda la CIL de un archivo PE en código nativo, convierte la CIL según sea necesario durante la ejecución y almacena el código nativo resultante en memoria para que sea accesible para las llamadas posteriores en el contexto de ese proceso. El cargador crea y asocia un código auxiliar a cada método de un tipo cuando este tipo se carga y se inicializa. Cuando se llama a un método por primera vez, el código auxiliar pasa el control al compilador JIT, que convierte la CIL para ese método en código nativo y modifica el código auxiliar para que apunte directamente al código nativo generado. Por lo tanto, las llamadas posteriores al método compilado JIT van directamente al código nativo.
Generación de código en tiempo de instalación mediante NGen.exe
Dado que el compilador JIT convierte la CIL de un ensamblado en código nativo cuando se llama a métodos individuales definidos en ese ensamblado, afecta negativamente al rendimiento en tiempo de ejecución. En la mayoría de los casos, esa disminución del rendimiento es aceptable. Lo más importante es que el código generado por el compilador JIT esté enlazado al proceso que desencadenó la compilación. No se puede compartir entre varios procesos. Para permitir que el código generado se comparta en varias invocaciones de una aplicación o en varios procesos que comparten un conjunto de ensamblados, Common Language Runtime admite un modo de compilación anticipada. Este modo de compilación anticipada usa el Ngen.exe (Generador de imágenes nativas) para convertir ensamblados CIL en código nativo de forma muy similar al compilador JIT. Sin embargo, el funcionamiento de Ngen.exe difiere del del compilador JIT de tres maneras:
- Realiza la conversión de CIL a código nativo antes de ejecutar la aplicación en lugar de mientras se ejecuta la aplicación.
- Compila un ensamblado completo a la vez, en lugar de un método a la vez.
- Conserva el código generado en la caché de imágenes nativas como un archivo en el disco.
Comprobación de código
Como parte de su compilación en código nativo, el código CIL debe pasar un proceso de comprobación a menos que un administrador haya establecido una directiva de seguridad que permita que el código omita la comprobación. La comprobación examina la CIL y los metadatos para averiguar si el código es seguro para tipos, lo que significa que solo tiene acceso a las ubicaciones de memoria a las que está autorizado el acceso. La seguridad de tipos contribuye a aislar los objetos unos de otros y los protege de corrupción accidental o malintencionada. También proporciona garantía de que se pueden aplicar restricciones de seguridad en el código de forma confiable.
El motor en tiempo de ejecución se basa en el hecho de que se cumplan las siguientes condiciones para el código seguro comprobable:
- Una referencia a un tipo es estrictamente compatible con el tipo al que se hace referencia.
- Solo se invocan operaciones definidas adecuadamente en un objeto .
- Las identidades son lo que dicen ser.
Durante el proceso de comprobación, el código CIL se examina en un intento de confirmar que el código puede acceder a ubicaciones de memoria y llamar a métodos solo a través de tipos definidos correctamente. Por ejemplo, un código no permite el acceso a los campos de un objeto si esta acción sobrecarga las ubicaciones de memoria. Además, la comprobación inspecciona el código para determinar si la CIL se ha generado correctamente, ya que la CIL incorrecta puede provocar una infracción de las reglas de seguridad de tipo. El proceso de comprobación pasa un conjunto de código seguro bien definido, y pasa exclusivamente código seguro. Sin embargo, es posible que algún código seguro de tipos no pase la comprobación debido a algunas limitaciones del proceso de comprobación y algunos lenguajes, por diseño, no generan código seguro para tipos verificables. Si la directiva de seguridad requiere código seguro de tipos, pero el código no pasa la comprobación, se produce una excepción cuando se ejecuta el código.
Ejecutar código
Common Language Runtime proporciona la infraestructura que permite que la ejecución administrada tenga lugar y los servicios que se pueden usar durante la ejecución. Para poder ejecutar un método, debe compilarse en código específico del procesador. Cada método para el que se ha generado la CIL se compila mediante JIT cuando se llama por primera vez y, posteriormente, se ejecuta. La próxima vez que se ejecute el método, se ejecuta el código nativo compilado por JIT existente. El proceso de compilación JIT y, a continuación, la ejecución del código se repite hasta que se completa la ejecución.
Durante la ejecución, el código administrado recibe servicios como la recolección de elementos no utilizados, la seguridad, la interoperabilidad con código no administrado, la compatibilidad con la depuración entre lenguajes y la compatibilidad mejorada con la implementación y el control de versiones.
En Microsoft Windows Vista, el cargador del sistema operativo comprueba los módulos administrados mediante el examen de un bit del encabezado de COFF. El bit que se establece indica un módulo administrado. Si el cargador detecta módulos administrados, carga mscoree.dlly _CorValidateImage
_CorImageUnloading
notifica al cargador cuándo se cargan y descargan las imágenes del módulo administrado.
_CorValidateImage
realiza las siguientes acciones:
- Garantiza que el código es código administrado válido.
- Cambia el punto de entrada de la imagen a un punto de entrada en tiempo de ejecución.
En Windows de 64 bits, _CorValidateImage
modifica la imagen que está en memoria transformándola de FORMATO PE32 a PE32+.