Articulo de referencia

Arranque (compiladores)

En informática , el bootstrapping es la técnica para producir un compilador autocompilable , es decir, un compilador (o ensamblador ) escrito en el lenguaje de programación fuen...

En informática , el bootstrapping es la técnica para producir un compilador autocompilable , es decir, un compilador (o ensamblador ) escrito en el lenguaje de programación fuente que pretende compilar. Se genera una versión inicial del núcleo del compilador (el compilador bootstrap ) en un lenguaje diferente (que podría ser lenguaje ensamblador); las versiones sucesivas y ampliadas del compilador se desarrollan utilizando este subconjunto mínimo del lenguaje. El problema de compilar un compilador autocompilable se ha denominado el problema del huevo o la gallina en el diseño de compiladores, y el bootstrapping es una solución a este problema. [ 1 ] [ 2 ]

El arranque es una práctica bastante común al crear un lenguaje de programación . Muchos compiladores para muchos lenguajes de programación se basan en el arranque, incluidos los compiladores para ALGOL , BASIC , C , Common Lisp , D , Eiffel , Elixir , Factor , Go , Haskell , Java , Modula-2 , Nim , Oberon , OCaml , Pascal , PL/I , Python , Rust , Scala , Scheme , TypeScript , Vala , Zig y más.

Proceso

Un proceso de arranque típico funciona en tres o cuatro etapas: [ 3 ] [ 4 ] [ 5 ]

  • Etapa 0: preparación del entorno para el compilador de arranque . Aquí se eligen el lenguaje fuente y el lenguaje de salida del compilador. En el caso de una máquina sin compilador (que no dispone de compilador para ningún lenguaje), el código fuente y el de salida se escriben como código máquina binario o se generan mediante compilación cruzada en una máquina distinta a la de destino. En caso contrario, el compilador de arranque se escribe en uno de los lenguajes de programación existentes en la máquina de destino, y este genera código ejecutable en ella, como un lenguaje de programación de alto nivel , un lenguaje ensamblador , un archivo objeto o incluso código máquina.
  • Etapa 1: se genera el compilador de arranque. Este compilador es suficiente para traducir su propio código fuente a un programa ejecutable en la máquina de destino. A partir de este punto, todo el desarrollo posterior se realiza utilizando el lenguaje definido por el compilador de arranque, y comienza la etapa 2.
  • Etapa 2: El compilador de arranque genera un compilador completo. Esto se suele realizar por etapas según sea necesario; por ejemplo, el compilador para la versión X del lenguaje podrá compilar características de la versión X+1, pero no las utilizará. Una vez que este compilador haya sido probado y pueda compilarse a sí mismo, las versiones posteriores podrán utilizar las características de la versión X+1.
  • Etapa 3: El compilador completo de la etapa 2 genera un compilador completo. Si se desean agregar más funcionalidades, el trabajo se reanuda en la etapa 2, y el compilador completo actual de la etapa 3 reemplaza al compilador de arranque.

El compilador completo se construye dos veces para comparar las salidas de las dos etapas. Si son diferentes, el compilador de arranque o el compilador completo contienen un error. [ 3 ]

Métodos

Si se necesita compilar un compilador para el lenguaje X escrito en el lenguaje X, surge la cuestión de cómo compilar el primer compilador. Los diferentes métodos que se utilizan en la práctica incluyen:

  • Implementar un intérprete o compilador para el lenguaje X en el lenguaje Y. Niklaus Wirth informó que escribió el primer compilador de Pascal en Fortran . [ 6 ]
  • Ya se ha escrito otro intérprete o compilador para X en otro lenguaje Y; así es como a menudo se inicia Scheme .
  • Las versiones anteriores del compilador se escribieron en un subconjunto de X para el cual ya existía otro compilador; así es como se inician algunos superconjuntos de Java , Haskell y el compilador inicial de Free Pascal .
  • Un compilador que admita extensiones de lenguaje no estándar o características de lenguaje opcionales puede escribirse sin utilizar dichas extensiones y características, para que pueda compilarse con otro compilador que admita el mismo lenguaje base pero un conjunto diferente de extensiones y características. Las partes principales del compilador de C++ clang se escribieron en un subconjunto de C++ que puede compilarse tanto con g++ como con Microsoft Visual C++ . Las características avanzadas se escribieron con algunas extensiones de GCC.
  • El compilador para X se compila de forma cruzada desde otra arquitectura donde ya existe un compilador para X; así es como se suelen portar los compiladores de C a otras plataformas. Este es también el método utilizado para Free Pascal tras el arranque inicial.
  • Escribir el compilador en X; luego compilarlo manualmente desde el código fuente (probablemente sin optimizarlo) y ejecutarlo sobre el código para obtener un compilador optimizado. Donald Knuth utilizó este método para su sistema de programación web .

Los métodos para distribuir compiladores en código fuente incluyen proporcionar una versión de bytecode portátil del compilador, para así iniciar el proceso de compilación del compilador consigo mismo. El diagrama T es una notación utilizada para explicar estas técnicas de inicio del compilador. [ 7 ] En algunos casos, la forma más conveniente de ejecutar un compilador complejo en un sistema con poco o ningún software instalado implica una serie de ensambladores y compiladores cada vez más sofisticados. [ 8 ]

Historia

Los ensambladores fueron las primeras herramientas de lenguaje en autoarrancarse.

El primer lenguaje de alto nivel que proporcionó tal mecanismo de arranque fue NELIAC en 1958. Los primeros lenguajes ampliamente utilizados que lo hicieron fueron Burroughs B5000 Algol en 1961 y LISP en 1962.

Hart y Levin escribieron un compilador LISP en LISP en el MIT en 1962, probándolo dentro de un intérprete LISP existente. Una vez que mejoraron el compilador hasta el punto en que podía compilar su propio código fuente, se volvió autoalojado. [ 9 ]

El compilador, tal como aparece en la cinta de compilación estándar, es un programa en lenguaje máquina que se obtuvo al hacer que la definición de la expresión S del compilador funcionara sobre sí misma a través del intérprete.

Memorando de IA 39 [ 9 ]

Esta técnica solo es posible cuando ya existe un intérprete para el mismo lenguaje que se va a compilar. Se basa directamente en la idea de ejecutar un programa sobre sí mismo como entrada, que también se utiliza en diversas demostraciones de informática teórica , como la variante de la demostración de que el problema de la parada es indecidible que utiliza el teorema de Rice .

Esfuerzos actuales

Debido a las preocupaciones de seguridad relacionadas con el Ataque de Confianza Confiable (que implica la modificación maliciosa de un compilador para introducir puertas traseras ocultas en los programas que compila o incluso replicar la modificación maliciosa en futuras versiones del propio compilador, creando un ciclo perpetuo de desconfianza) y diversos ataques contra la confiabilidad binaria, varios proyectos están trabajando para reducir el esfuerzo no solo para el arranque desde el código fuente, sino también para permitir que todos verifiquen que el código fuente y el ejecutable se corresponden. Estos incluyen el proyecto de compilaciones de arranque [ 10 ] y el proyecto de compilaciones reproducibles [ 11 ] .

Véase también

Referencias

  1. Reynolds, John H. (diciembre de 2003). "Arranque de un compilador autocompilador de la máquina X a la máquina Y" . CCSC: Conferencia del Este. Journal of Computing Sciences in Colleges . 19 (2): 175–181 . La idea de un compilador escrito en el lenguaje que compila plantea el viejo dilema del huevo o la gallina: ¿De dónde viene el primero?
  2. Glück, Robert (2012). "Generación de compiladores a partir de evaluadores parciales". En Clarke, Edmund; Virbitskaite, Irina; Voronkov, Andrei (eds.). Perspectivas de la informática de sistemas: 8.ª Conferencia Internacional en Memoria de Andrei Ershov, PSI 2011, Novosibirsk, Rusia, 27 de junio - 1 de julio de 2011, Artículos seleccionados revisados . Lecture Notes in Computer Science. Vol. 7162. Springer. pp. 125–141 . doi : 10.1007/978-3-642-29709-0_13 . ISBN   978-3-642-29708-3Para empezar , surge el problema del huevo y la gallina, familiar en la construcción de compiladores: se necesita un compilador para inicializar otro compilador, y la inicialización de generadores de compiladores no es una excepción.
  3. 1 2 "Instalación de GCC: Compilación" . Proyecto GNU - Fundación del Software Libre (FSF) .
  4. "rust-lang/rust: bootstrap" . GitHub .
  5. "Configuraciones de compilación avanzadas — Documentación de LLVM 10" . llvm.org .
  6. Wirth, Niklaus (22 de febrero de 2021). "50 años de Pascal". Communications of the ACM . 64 (3). Association for Computing Machinery (ACM): 39– 41. doi : 10.1145/3447525 . ISSN 0001-0782 . S2CID 231991096 .  
  7. Patrick D. Terry (1997). "3. Construcción y arranque del compilador" . Compiladores y generadores de compiladores: Una introducción con C++ . International Thomson Computer Press. ISBN 1-85032-298-8Archivado del original el 23 de noviembre de 2009.
  8. Edmund Grimley-Evans (23 de abril de 2003). "Creación de un compilador simple desde cero" . homepage.ntlworld.com . Archivado del original el 3 de marzo de 2010.
  9. 1 2 Tim Hart y Mike Levin. "AI Memo 39-The new compiler" (PDF) . Archivado del original (PDF) el 6 de julio de 2017. Recuperado el 23 de mayo de 2008 .
  10. "Builds Bootstrapable" . bootstrappable.org .
  11. "Compilaciones reproducibles: un conjunto de prácticas de desarrollo de software que crean una ruta verificable de forma independiente desde el código fuente hasta el código binario" . reproducible-builds.org .