stringtranslate.com

Código automodificable

En informática , el código automodificable ( SMC o SMoC ) es un código que altera sus propias instrucciones mientras se ejecuta , generalmente para reducir la longitud de la ruta de instrucciones y mejorar el rendimiento o simplemente para reducir el código repetitivamente similar , simplificando así el mantenimiento . El término generalmente solo se aplica al código donde la automodificación es intencional, no en situaciones en las que el código se modifica accidentalmente debido a un error como un desbordamiento de búfer .

El código automodificable puede implicar sobrescribir instrucciones existentes o generar código nuevo en tiempo de ejecución y transferir el control a ese código.

La automodificación se puede utilizar como una alternativa al método de "establecimiento de indicadores" y la ramificación condicional del programa, que se utiliza principalmente para reducir la cantidad de veces que es necesario probar una condición.

El método se utiliza con frecuencia para invocar código de prueba/depuración condicional sin requerir sobrecarga computacional adicional para cada ciclo de entrada/salida .

Las modificaciones se podrán realizar:

En cualquier caso, las modificaciones se pueden realizar directamente en las propias instrucciones del código de máquina , superponiendo nuevas instrucciones sobre las existentes (por ejemplo: alterar una comparación y bifurcarla a una bifurcación incondicional o, alternativamente, un ' NOP ').

En la arquitectura IBM System/360 y sus sucesores hasta z/Architecture , una instrucción EXECUTE (EX) superpone lógicamente el segundo byte de su instrucción de destino con los 8 bits de orden inferior del registro 1. Esto proporciona el efecto de automodificación aunque la instrucción real en el almacenamiento no se altera.

Aplicación en lenguajes de bajo y alto nivel

La automodificación se puede lograr de diversas maneras dependiendo del lenguaje de programación y su soporte para punteros y/o acceso a 'motores' de compiladores o intérpretes dinámicos:

Lenguaje ensamblador

El código automodificable es bastante sencillo de implementar cuando se utiliza lenguaje ensamblador . Las instrucciones se pueden crear dinámicamente en la memoria (o bien superponerlas sobre el código existente en el almacenamiento de programas no protegidos), [1] en una secuencia equivalente a las que un compilador estándar puede generar como código objeto . Con los procesadores modernos, puede haber efectos secundarios no deseados en la memoria caché de la CPU que deben tenerse en cuenta. El método se utilizó con frecuencia para probar condiciones de "primera vez", como en este ejemplo de ensamblador IBM/360 comentado adecuadamente . Utiliza la superposición de instrucciones para reducir la longitud de la ruta de instrucciones en (N×1)−1 donde N es el número de registros en el archivo (−1 es la sobrecarga para realizar la superposición).

SUBRTN NOP ¿ABIERTO POR PRIMERA VEZ AQUÍ?* El NOP es x'4700'<Dirección_de_apertura> OI SUBRTN+1,X'F0' SI, CAMBIAR NOP A RAMA INCONDICIONAL (47F0...) ABRIR ENTRADA Y ABRIR EL ARCHIVO DE ENTRADA YA QUE ES LA PRIMERA VEZABIERTO OBTENER ENTRADA EL PROCESAMIENTO NORMAL SE REANUDA AQUÍ ...

Un código alternativo podría implicar probar una "bandera" cada vez. La bifurcación incondicional es ligeramente más rápida que una instrucción de comparación, además de reducir la longitud total de la ruta. En sistemas operativos posteriores para programas que residen en almacenamiento protegido, esta técnica no se podía utilizar y, por lo tanto, se utilizaba en su lugar el cambio del puntero a la subrutina . El puntero residiría en almacenamiento dinámico y se podría alterar a voluntad después del primer paso para omitir la APERTURA (tener que cargar un puntero primero en lugar de una bifurcación directa y un enlace a la subrutina agregaría N instrucciones a la longitud de la ruta, pero habría una reducción correspondiente de N para la bifurcación incondicional que ya no sería necesaria).

A continuación se muestra un ejemplo en lenguaje ensamblador Zilog Z80 . El código incrementa el registro "B" en el rango [0,5]. La instrucción de comparación "CP" se modifica en cada bucle.

;========== ORG 0H LLAMAR FUNC00 DETENER ;========== FUNC00: LD A , 6 LD HL , etiqueta01 + 1 LD B , ( HL ) etiqueta00: INC B LD ( HL ), B etiqueta01: CP $ 0 JP NZ , etiqueta00 RET ;==========         

El código automodificable se utiliza a veces para superar las limitaciones del conjunto de instrucciones de una máquina. Por ejemplo, en el conjunto de instrucciones Intel 8080 , no se puede introducir un byte desde un puerto de entrada que esté especificado en un registro. El puerto de entrada está codificado estáticamente en la propia instrucción, como el segundo byte de una instrucción de dos bytes. Mediante el uso de código automodificable, es posible almacenar el contenido de un registro en el segundo byte de la instrucción y, a continuación, ejecutar la instrucción modificada para lograr el efecto deseado.

Lenguajes de alto nivel

Algunos lenguajes compilados permiten explícitamente la automodificación del código. Por ejemplo, el verbo ALTER en COBOL puede implementarse como una instrucción de bifurcación que se modifica durante la ejecución. [2] Algunas técnicas de programación por lotes implican el uso de código automodificable. Clipper y SPITBOL también proporcionan funciones para la automodificación explícita. El compilador Algol en los sistemas B6700 ofrecía una interfaz al sistema operativo mediante la cual el código en ejecución podía pasar una cadena de texto o un archivo de disco con nombre al compilador Algol y luego podía invocar la nueva versión de un procedimiento.

En los lenguajes interpretados, el "código de máquina" es el texto fuente y puede ser susceptible de edición sobre la marcha: en SNOBOL, las sentencias fuente que se ejecutan son elementos de una matriz de texto. Otros lenguajes, como Perl y Python , permiten que los programas creen código nuevo en tiempo de ejecución y lo ejecuten utilizando una función eval , pero no permiten que se modifique el código existente. La ilusión de modificación (aunque en realidad no se esté sobrescribiendo ningún código de máquina) se logra modificando los punteros de función, como en este ejemplo de JavaScript:

 var f = función ( x ) { devolver x + 1 };         // asigna una nueva definición a f: f = new Function ( 'x' , 'return x + 2' );     

Las macros Lisp también permiten la generación de código en tiempo de ejecución sin analizar una cadena que contenga el código del programa.

El lenguaje de programación Push es un sistema de programación genética diseñado explícitamente para crear programas que se modifican a sí mismos. Si bien no es un lenguaje de alto nivel, no es de tan bajo nivel como el lenguaje ensamblador. [3]

Modificación de compuestos

Antes de la aparición de múltiples ventanas, los sistemas de línea de comandos podían ofrecer un sistema de menú que implicaba la modificación de un script de comandos en ejecución. Supongamos que un archivo de script (o "por lotes") DOS MENU.BAT contiene lo siguiente: [4] [nb 1]

 :comenzar SHOWMENU.EXE

Al iniciar MENU.BAT desde la línea de comandos, SHOWMENU presenta un menú en pantalla, con posible información de ayuda, ejemplos de uso, etc. Finalmente, el usuario realiza una selección que requiere que se ejecute un comando SOMENAME : SHOWMENU sale después de reescribir el archivo MENU.BAT para que contenga

 :comenzar SHOWMENU.EXE Llamar a alguien .BAT IR A inicio

Debido a que el intérprete de comandos DOS no compila un archivo de script y luego lo ejecuta, ni lee el archivo completo en la memoria antes de comenzar la ejecución, ni tampoco se basa en el contenido de un búfer de registro, cuando SHOWMENU sale, el intérprete de comandos encuentra un nuevo comando para ejecutar (es invocar el archivo de script SOMENAME , en una ubicación de directorio y a través de un protocolo conocido por SHOWMENU), y después de que ese comando se completa, vuelve al inicio del archivo de script y reactiva SHOWMENU listo para la próxima selección. Si la opción del menú es salir, el archivo se reescribiría de nuevo a su estado original. Aunque este estado inicial no tiene uso para la etiqueta, se requiere esta, o una cantidad equivalente de texto, porque el intérprete de comandos DOS recuerda la posición de byte del próximo comando cuando debe iniciar el próximo comando, por lo tanto, el archivo reescrito debe mantener la alineación para que el punto de inicio del próximo comando sea de hecho el inicio del próximo comando.

Además de la conveniencia de un sistema de menú (y posibles funciones auxiliares), este esquema significa que el sistema SHOWMENU.EXE no está en la memoria cuando se activa el comando seleccionado, una ventaja significativa cuando la memoria es limitada. [4] [5]

Tablas de control

Los intérpretes de la tabla de control pueden considerarse, en cierto sentido, "automodificados" por los valores de datos extraídos de las entradas de la tabla (en lugar de estar codificados manualmente de forma específica en declaraciones condicionales del formato "SI entradax = 'yyy'").

Programas del canal

Algunos métodos de acceso de IBM tradicionalmente utilizaban programas de canal automodificables , donde un valor, como una dirección de disco, se lee en un área referenciada por un programa de canal, donde es utilizado por un comando de canal posterior para acceder al disco.

Historia

El IBM SSEC , demostrado en enero de 1948, tenía la capacidad de modificar sus instrucciones o tratarlas exactamente como datos. Sin embargo, la capacidad rara vez se utilizó en la práctica. [6] En los primeros días de las computadoras, el código automodificable se usaba a menudo para reducir el uso de memoria limitada, o mejorar el rendimiento, o ambas cosas. También se usaba a veces para implementar llamadas y retornos de subrutinas cuando el conjunto de instrucciones solo proporcionaba instrucciones simples de ramificación o salto para variar el flujo de control . [7] [8] Este uso todavía es relevante en ciertas arquitecturas ultra- RISC , al menos teóricamente; vea por ejemplo la computadora de un conjunto de instrucciones . La arquitectura MIX de Donald Knuth también usó código automodificable para implementar llamadas de subrutinas. [9]

Uso

El código automodificable se puede utilizar para diversos fines:

Optimización de un bucle dependiente del estado

Ejemplo de pseudocódigo :

repetir N veces { Si ESTADO es 1 Aumentar A en uno demás Disminuir A en uno Haz algo con A}

En este caso, el código automodificable sería simplemente una cuestión de reescribir el bucle de esta manera:

repetir N veces { aumentar A en uno Haz algo con A cuando el ESTADO tiene que cambiar { Reemplace el código de operación "aumentar" anterior con el código de operación para disminuir, o viceversa. }}

Tenga en cuenta que el reemplazo de dos estados del código de operación se puede escribir fácilmente como 'xor var en la dirección con el valor "opcodeOf(Inc) xor opcodeOf(dec)"'.

La elección de esta solución debe depender del valor de N y de la frecuencia del cambio de estado.

Especialización

Supongamos que se debe calcular un conjunto de estadísticas, como promedio, valores extremos, ubicación de los valores extremos, desviación estándar, etc., para un conjunto de datos grande. En una situación general, puede haber una opción para asociar pesos con los datos, de modo que cada x i se asocie con un w i y, en lugar de probar la presencia de pesos en cada valor de índice, podría haber dos versiones del cálculo, una para usar con pesos y otra que no, con una prueba al comienzo. Ahora, considere otra opción: cada valor puede tener asociado un booleano para indicar si ese valor se debe omitir o no. Esto se puede manejar generando cuatro lotes de código, uno para cada permutación y los resultados de hinchazón del código. Alternativamente, las matrices de pesos y omisiones se pueden fusionar en una matriz temporal (con cero pesos para los valores que se deben omitir), a costa del procesamiento y aún así hay hinchazón. Sin embargo, con la modificación del código, a la plantilla para calcular las estadísticas se le puede agregar, según corresponda, el código para omitir valores no deseados y para aplicar pesos. No habría pruebas repetidas de las opciones y se accedería a la matriz de datos una sola vez, como también a las matrices de peso y omisión, si estuvieran involucradas.

Usar como camuflaje

El código automodificable es más complejo de analizar que el código estándar y, por lo tanto, se puede utilizar como protección contra la ingeniería inversa y el pirateo de software . El código automodificable se utilizó para ocultar las instrucciones de protección de copia en programas basados ​​en disco de la década de 1980 para sistemas como IBM PC compatibles y Apple II . Por ejemplo, en una IBM PC, la instrucción de acceso a la unidad de disqueteint 0x13 no aparecería en la imagen del programa ejecutable, sino que se escribiría en la imagen de memoria del ejecutable después de que el programa comenzara a ejecutarse.

El código automodificable también es utilizado a veces por programas que no quieren revelar su presencia, como los virus informáticos y algunos shellcodes . Los virus y shellcodes que utilizan código automodificable lo hacen principalmente en combinación con código polimórfico . La modificación de un fragmento de código en ejecución también se utiliza en ciertos ataques, como los desbordamientos de búfer .

Sistemas de aprendizaje automático autorreferenciales

Los sistemas de aprendizaje automático tradicionales tienen un algoritmo de aprendizaje fijo y preprogramado para ajustar sus parámetros . Sin embargo, desde la década de 1980, Jürgen Schmidhuber ha publicado varios sistemas automodificables con la capacidad de cambiar su propio algoritmo de aprendizaje. Evitan el peligro de autoreescrituras catastróficas al asegurarse de que las automodificaciones sobrevivirán solo si son útiles de acuerdo con una función de aptitud , error o recompensa dada por el usuario . [14]

Sistemas operativos

El núcleo Linux hace un uso amplio de código automodificable; lo hace para poder distribuir una única imagen binaria para cada arquitectura principal (por ejemplo, IA-32 , x86-64 , ARM de 32 bits , ARM64 ...) al tiempo que adapta el código del núcleo en la memoria durante el arranque dependiendo del modelo de CPU específico detectado, por ejemplo, para poder aprovechar las nuevas instrucciones de la CPU o para solucionar errores de hardware. [15] [16] En menor medida, el núcleo DR-DOS también optimiza secciones críticas para la velocidad de sí mismo en el momento de la carga dependiendo de la generación del procesador subyacente. [10] [11] [nb 2]

De todos modos, a un nivel meta , los programas aún pueden modificar su propio comportamiento cambiando datos almacenados en otro lugar (ver metaprogramación ) o mediante el uso de polimorfismo .

El núcleo de síntesis de Massalin

El núcleo Synthesis presentado en la tesis doctoral de Alexia Massalin [17] [18] es un pequeño núcleo Unix que adopta un enfoque estructurado , o incluso orientado a objetos , para el código automodificable, donde el código se crea para quajects individuales , como manejadores de archivos. La generación de código para tareas específicas permite que el núcleo Synthesis (como lo haría un intérprete JIT) aplique una serie de optimizaciones como el plegado constante o la eliminación de subexpresiones comunes .

El núcleo Synthesis era muy rápido, pero estaba escrito completamente en lenguaje ensamblador. La falta de portabilidad resultante ha impedido que las ideas de optimización de Massalin fueran adoptadas por cualquier núcleo de producción. Sin embargo, la estructura de las técnicas sugiere que podrían ser capturadas por un lenguaje de nivel superior , aunque uno más complejo que los lenguajes de nivel medio existentes. Un lenguaje y un compilador de este tipo podrían permitir el desarrollo de sistemas operativos y aplicaciones más rápidos.

Paul Haeberli y Bruce Karsh se han opuesto a la "marginación" del código automodificable y de la optimización en general, en favor de la reducción de los costos de desarrollo. [19]

Interacción entre la caché y el código automodificable

En arquitecturas sin caché de datos e instrucciones acopladas (por ejemplo, algunos núcleos SPARC , ARM y MIPS ), la sincronización de caché debe ser realizada explícitamente por el código modificador (vaciar el caché de datos e invalidar el caché de instrucciones para el área de memoria modificada).

En algunos casos, las secciones cortas de código que se modifica a sí mismo se ejecutan más lentamente en los procesadores modernos. Esto se debe a que un procesador moderno generalmente intentará mantener bloques de código en su memoria caché. Cada vez que el programa reescribe una parte de sí mismo, la parte reescrita debe cargarse nuevamente en la memoria caché, lo que genera un ligero retraso si el código modificado comparte la misma línea de caché con el código modificador, como es el caso cuando la dirección de memoria modificada se encuentra a unos pocos bytes de la del código modificador.

El problema de invalidación de caché en los procesadores modernos generalmente significa que el código automodificable seguirá siendo más rápido solo cuando la modificación ocurra con poca frecuencia, como en el caso de un cambio de estado dentro de un bucle interno. [ cita requerida ]

La mayoría de los procesadores modernos cargan el código de la máquina antes de ejecutarlo, lo que significa que si se modifica una instrucción que está demasiado cerca del puntero de instrucción , el procesador no lo notará, sino que ejecutará el código tal como estaba antes de ser modificado. Véase cola de entrada de precarga (PIQ). Los procesadores de PC deben manejar el código que se modifica automáticamente correctamente por razones de compatibilidad con versiones anteriores, pero están lejos de ser eficientes en hacerlo. [ cita requerida ]

Problemas de seguridad

Debido a las implicaciones de seguridad que tiene el código que se modifica a sí mismo, todos los principales sistemas operativos tienen cuidado de eliminar dichas vulnerabilidades a medida que se descubren. La preocupación no suele ser que los programas se modifiquen a sí mismos intencionalmente, sino que puedan ser modificados de forma maliciosa mediante un exploit .

Un mecanismo para evitar la modificación de código malicioso es una característica del sistema operativo llamada W^X (por "write xorexecute "). Este mecanismo prohíbe a un programa hacer que cualquier página de memoria sea tanto escribible como ejecutable. Algunos sistemas impiden que una página escribible se cambie a ejecutable, incluso si se elimina el permiso de escritura. [ cita requerida ] Otros sistemas proporcionan una especie de " puerta trasera ", que permite que múltiples asignaciones de una página de memoria tengan diferentes permisos. Una forma relativamente portátil de evitar W^X es crear un archivo con todos los permisos y luego asignar el archivo a la memoria dos veces. En Linux, se puede usar una bandera de memoria compartida SysV no documentada para obtener memoria compartida ejecutable sin necesidad de crear un archivo. [ cita requerida ]

Ventajas

Desventajas

El código que se modifica a sí mismo es más difícil de leer y mantener porque las instrucciones en la lista del programa fuente no son necesariamente las instrucciones que se ejecutarán. La modificación automática que consiste en la sustitución de punteros de función puede no ser tan críptica, si está claro que los nombres de las funciones que se llamarán son marcadores de posición para las funciones que se identificarán más adelante.

El código automodificable se puede reescribir como código que prueba una bandera y se ramifica a secuencias alternativas según el resultado de la prueba, pero el código automodificable normalmente se ejecuta más rápido.

El código automodificable entra en conflicto con la autenticación del código y puede requerir excepciones a las políticas que exigen que todo el código que se ejecuta en un sistema esté firmado.

El código modificado debe almacenarse separado de su forma original, lo que entra en conflicto con las soluciones de gestión de memoria que normalmente descartan el código en la RAM y lo vuelven a cargar desde el archivo ejecutable según sea necesario.

En los procesadores modernos con un pipeline de instrucciones , el código que se modifica a sí mismo con frecuencia puede ejecutarse más lentamente si modifica instrucciones que el procesador ya ha leído desde la memoria en el pipeline. En algunos de estos procesadores, la única forma de garantizar que las instrucciones modificadas se ejecuten correctamente es vaciar el pipeline y volver a leer muchas instrucciones.

El código automodificable no se puede utilizar en absoluto en algunos entornos, como los siguientes:

Véase también

Notas

  1. ^ Las versiones posteriores de DOS (desde la versión 6.0) introdujeron el comando externo CHOICE (en DR-DOS también el comando interno y la directiva CONFIG.SYS SWITCH ), por lo que, para esta aplicación de ejemplo específica de un sistema de menú, ya no era necesario hacer referencia a trabajos por lotes automodificables; sin embargo, para otras aplicaciones siguió siendo una solución viable.
  2. ^ ab Por ejemplo, cuando se ejecuta en procesadores 386 o superiores, las actualizaciones posteriores de Novell DOS 7 , así como DR-DOS 7.02 y superiores, reemplazarán dinámicamente algunas secuencias predeterminadas de REP MOVSWinstrucciones de 16 bits ("copiar palabras") en la imagen de tiempo de ejecución del núcleo por instrucciones de 32 bits REP MOVSD("copiar palabras dobles") al copiar datos de una ubicación de memoria a otra (y la mitad del recuento de repeticiones necesarias) para acelerar las transferencias de datos del disco. Se tienen en cuenta los casos extremos, como los recuentos impares. [10] [11]
  3. ^ A modo de ejemplo, los MBR y sectores de arranque DR-DOS (que también contienen la tabla de particiones y el bloque de parámetros del BIOS , dejando menos de 446 y 423 bytes respectivamente para el código) tradicionalmente podían localizar el archivo de arranque en el sistema de archivos FAT12 o FAT16 por sí mismos y cargarlo en la memoria como un todo, a diferencia de sus contrapartes MS-DOS / PC DOS , que en cambio dependían de que los archivos del sistema ocuparan las dos primeras entradas de directorio en el sistema de archivos y los primeros tres sectores de IBMBIO.COM se almacenaran al comienzo del área de datos en sectores contiguos que contenían un cargador secundario para cargar el resto del archivo en la memoria (lo que requería que SYS se encargara de todas estas condiciones). Cuando se añadió el soporte para FAT32 y LBA , Microsoft incluso cambió a requerir 386 instrucciones y dividió el código de arranque en dos sectores por razones de tamaño, lo que no era una opción para DR-DOS ya que habría roto la compatibilidad con versiones anteriores y cruzadas con otros sistemas operativos en escenarios de arranque múltiple y carga en cadena , así como con PC más antiguas . En cambio, los sectores de arranque de DR-DOS 7.07 recurrieron a código automodificable, programación a nivel de código de operación en lenguaje de máquina , utilización controlada de efectos secundarios (documentados), superposición de datos/código de múltiples niveles y técnicas de plegado algorítmico para encajar todo en un sector físico de solo 512 bytes sin renunciar a ninguna de sus funciones extendidas.

Referencias

  1. ^ "HP 9100A/B". MoHPC - El museo de las calculadoras HP . 1998. Datos superpuestos y memoria de programa / Código automodificable. Archivado desde el original el 23 de septiembre de 2023. Consultado el 23 de septiembre de 2023 .
  2. ^ "La declaración ALTER". Referencia del lenguaje COBOL. Micro Focus .
  3. ^ Spector, Lee. "Computación evolutiva con Push: Push, PushGP y Pushpop" . Consultado el 25 de abril de 2023 .
  4. ^ ab Fosdal, Lars (2001). "Archivo por lotes automodificable". Archivado desde el original el 21 de abril de 2008.
  5. ^ Paul, Matthias R. (13 de octubre de 1996) [21 de agosto de 1996, 1994]. Konzepte zur Unterstützung Administrator Aufgaben in PC-Netzen und deren Realisierung für eine konkrete Novell-LAN-Umgebung unter Benutzung der Batchsprache von DOS . 3.11 (en alemán). Aquisgrán, Alemania: Lehrstuhl für Kommunikationsnetze ( ComNets ) & Institut für Kunststoffverarbeitung (IKV), RWTH. págs. 51, 71–72.(110+3 páginas, disquete) (NB. Diseño e implementación de un sistema de gestión distribuido modular controlado centralmente para la configuración automática de clientes y la implementación de software con un mecanismo de actualización autorreparador en entornos LAN basado en trabajos por lotes autorreplicantes y automodificables indirectamente con consumo de memoria cero en lugar de la necesidad de un software de gestión residente en los clientes).
  6. ^ Bashe, Charles J.; Buchholz, Werner ; Hawkins, George V.; Ingram, J. James; Rochester, Nathaniel (septiembre de 1981). "La arquitectura de las primeras computadoras de IBM" (PDF) . IBM Journal of Research and Development . 25 (5): 363–376. CiteSeerX 10.1.1.93.8952 . doi :10.1147/rd.255.0363. ISSN  0018-8646 . Consultado el 25 de abril de 2023 . p. 365: El SSEC fue el primer ordenador operativo capaz de tratar sus propias instrucciones almacenadas exactamente como datos, modificándolas y actuando sobre el resultado. 
  7. ^ Miller, Barton P. (30 de octubre de 2006). "Binary Code Patching: An Ancient Art Refined for the 21st Century" (Parcheo de código binario: un arte antiguo perfeccionado para el siglo XXI). Triangle Computer Science Distinguished Lecturer Series - Seminars 2006-2007 (Serie de conferenciantes destacados de Triangle Computer Science: seminarios 2006-2007). NC State University , Computer Science Department (Universidad Estatal de Carolina del Norte, Departamento de Ciencias de la Computación ). Consultado el 25 de abril de 2023 .
  8. ^ Wenzl, Matthias; Merzdovnik, Georg; Ullrich, Johanna; Weippl, Edgar R. (junio de 2019) [febrero de 2019, noviembre de 2018, mayo de 2018]. "Del hack a la técnica elaborada: una encuesta sobre reescritura binaria" (PDF) . Encuestas de computación de la ACM . 52 (3). Viena, Austria: 49:1–49:36 [49:1]. doi :10.1145/3316415. S2CID  195357367. Artículo 49. Archivado (PDF) desde el original el 15 de enero de 2021 . Consultado el 28 de noviembre de 2021 . p. 49:1: […] Originalmente, la reescritura binaria estaba motivada por la necesidad de cambiar partes de un programa durante la ejecución (por ejemplo, la aplicación de parches en tiempo de ejecución en el PDP-1 en los años 1960) […](36 páginas)
  9. ^ Knuth, Donald Ervin (2009) [1997]. «MMIX 2009: una computadora RISC para el tercer milenio». Archivado desde el original el 27 de noviembre de 2021. Consultado el 28 de noviembre de 2021 .
  10. ^ abcd "Caldera OpenDOS Machine Readable Source Kit (MRS) 7.01". Caldera, Inc. 1997-05-01. Archivado desde el original el 2021-08-07 . Consultado el 2022-01-02 .[1]
  11. ^ abcd Paul, Matthias R. (2 de octubre de 1997). «Caldera OpenDOS 7.01/7.02 Update Alpha 3 IBMBIO.COM README.TXT». Archivado desde el original el 4 de octubre de 2003. Consultado el 29 de marzo de 2009 .[2]
  12. ^ Wilkinson, William "Bill" Albert (2003) [1996, 1984]. "El gusano H89: prueba de memoria del H89". Página de Bill Wilkinson en Heath Company . Archivado desde el original el 13 de diciembre de 2021. Consultado el 13 de diciembre de 2021. […] Además de buscar una instrucción, el Z80 utiliza la mitad del ciclo para refrescar la RAM dinámica . […] dado que el Z80 debe dedicar la mitad de cada ciclo de búsqueda de instrucciones a realizar otras tareas, no tiene tanto tiempo para buscar un byte de instrucción como para buscar un byte de datos. Si uno de los chips de RAM en la ubicación de memoria a la que se accede es un poco lento, el Z80 puede obtener el patrón de bits incorrecto cuando busca una instrucción, pero obtener el correcto cuando lee datos. […] la prueba de memoria incorporada no detectará este tipo de problema […] es estrictamente una prueba de lectura/escritura de datos. Durante la prueba, todas las instrucciones se obtienen de la ROM , no de la RAM […] lo que da como resultado que el H89 pase la prueba de memoria pero siga funcionando de forma errática en algunos programas. […] Este es un programa que prueba la memoria reubicándose a través de la RAM. Mientras lo hace, la CPU imprime la dirección actual del programa en el CRT y luego obtiene la instrucción en esa dirección. Si los IC de RAM están bien en esa dirección, la CPU reubica el programa de prueba en la siguiente ubicación de memoria, imprime la nueva dirección y repite el procedimiento. Pero, si uno de los IC de RAM es lo suficientemente lento como para devolver un patrón de bits incorrecto, la CPU malinterpretará la instrucción y se comportará de forma impredecible. Sin embargo, es probable que la pantalla se bloquee mostrando la dirección del IC defectuoso. Esto reduce el problema a ocho IC, lo que es una mejora con respecto a tener que verificar hasta 32. […] El […] programa realizará una prueba de gusano enviando una instrucción RST 7 (RESTART 7) desde el extremo inferior de la memoria hasta la última dirección de trabajo. El resto del programa permanece estacionario y se encarga de mostrar la ubicación actual del comando RST 7 y su reubicación . Por cierto, el programa se llama prueba de gusano porque, a medida que la instrucción RST 7 avanza por la memoria, deja un rastro viscoso de NOP (NO OPERATION). […]
  13. ^ Ortiz, Carlos Enrique (2015-08-29) [2007-08-18]. "Sobre el código automodificable y el sistema operativo del transbordador espacial" . Consultado el 2023-04-25 .
  14. ^ Publicaciones de Jürgen Schmidhuber sobre código automodificable para sistemas de aprendizaje automático autorreferenciales
  15. ^ Paltsev, Evgeniy (30 de enero de 2020). "Código automodificable en el núcleo de Linux: qué, dónde y cómo" . Consultado el 27 de noviembre de 2022 .
  16. ^ Wieczorkiewicz, Pawel. «Alternativas al kernel de Linux» . Consultado el 27 de noviembre de 2022 .
  17. ^ Pu, Calton ; Massalin, Henry ; Ioannidis, John (1992). Síntesis: una implementación eficiente de los servicios fundamentales del sistema operativo (PDF) (tesis doctoral). Nueva York, EE. UU.: Departamento de Ciencias de la Computación, Universidad de Columbia . Número de pedido UMI GAX92-32050 . Consultado el 25 de abril de 2023 .[3]
  18. ^ Henson, Valerie (20 de febrero de 2008). "KHB: Síntesis: una implementación eficiente de los servicios fundamentales de los sistemas operativos". LWN.net . Archivado desde el original el 17 de agosto de 2021 . Consultado el 19 de mayo de 2022 .
  19. ^ Haeberli, Pablo ; Karsh, Bruce (3 de febrero de 1994). "Io Noi Boccioni - Antecedentes de la programación futurista". Gráfica Oscura . Consultado el 25 de abril de 2023 .

Lectura adicional

Enlaces externos