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 instrucción y mejorar el rendimiento o simplemente para reducir código que de otro modo sería 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 donde el código se modifica accidentalmente debido a un error como un desbordamiento del búfer .

El código de modificación automática 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 alternativa al método de "establecimiento de banderas" y bifurcació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 condicionalmente código de prueba/depuración sin requerir una sobrecarga computacional adicional para cada ciclo de entrada/salida .

Las modificaciones podrán realizarse:

En cualquier caso, las modificaciones se pueden realizar directamente en las instrucciones del código de máquina , superponiendo nuevas instrucciones sobre las existentes (por ejemplo: alterar una comparación y una rama a una rama 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 auto- modificación aunque no se alteren las instrucciones reales de almacenamiento.

Aplicación en lenguajes de bajo y alto nivel.

La automodificación se puede lograr de varias maneras dependiendo del lenguaje de programación y su soporte para punteros y/o acceso a 'motores' de compilador o intérprete dinámico:

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 superponerse al código existente en un almacenamiento de programa no protegido), [1] en una secuencia equivalente a las que un compilador estándar puede generar como código objeto . Con los procesadores modernos, pueden producirse 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 del ensamblador IBM/360 debidamente comentado . Utiliza la superposición de instrucciones para reducir la longitud de la ruta de instrucción en (N×1) −1 donde N es el número de registros en el archivo (siendo −1 la sobrecarga para realizar la superposición).

SUBRTN NOP ¿ABRIÓ POR PRIMERA VEZ AQUÍ?* El NOP es x'4700'<Dirección_de_abierto> OI SUBRTN+1,X'F0' SÍ, CAMBIAR NOP A RAMA INCONDICIONAL (47F0...) ABRA LA ENTRADA Y ABRA EL ARCHIVO DE ENTRADA YA QUE ES LA PRIMERA VEZABIERTO OBTÉN ENTRADA RESUMEN DEL PROCESAMIENTO NORMAL AQUÍ ...

El código alternativo podría implicar probar una "bandera" cada vez. La rama 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 un almacenamiento protegido, esta técnica no se podía utilizar, por lo que se utilizaría en su lugar cambiar el puntero a la subrutina . El puntero residiría en un almacenamiento dinámico y podría modificarse a voluntad después del primer paso para evitar OPEN (tener que cargar un puntero primero en lugar de una rama directa y un enlace a la subrutina agregaría N instrucciones a la longitud de la ruta, pero no sería una reducción correspondiente de N para la rama 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 CALL FUNC00 HALT ;========== FUNC00: LD A , 6 LD HL , label01 + 1 LD B ,( HL ) label00: INC B LD ( HL ), B etiqueta01: CP $ 0 JP NZ , etiqueta00 RET ;==========         

A veces se utiliza código automodificable para superar las limitaciones del conjunto de instrucciones de una máquina. Por ejemplo, en el conjunto de instrucciones Intel 8080 , no se puede ingresar un byte desde un puerto de entrada 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. Usando código automodificable, es posible almacenar el contenido de un registro en el segundo byte de la instrucción y luego ejecutar la instrucción modificada para lograr el efecto deseado.

Idiomas de alto nivel

Algunos lenguajes compilados permiten explícitamente código automodificable. Por ejemplo, el verbo ALTER en COBOL se puede implementar 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 que se modifica automáticamente. Clipper y SPITBOL también ofrecen posibilidades para la automodificación explícita. El compilador Algol en los sistemas B6700 ofrecía una interfaz para el 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.

Con 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 declaraciones 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 usando una función de evaluación , pero no permiten que se modifique el código existente. La ilusión de modificación (aunque en realidad no se sobrescribe 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 ) { retorno x + 1 };         // asigna una nueva definición a f: f = nueva función ( '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 contiene código de programa.

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

Modificación compuesta

Antes de la llegada 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 comando en ejecución. Supongamos que un archivo de script DOS (o "por lotes") MENU.BAT contiene lo siguiente: [4] [nb 1]

 :comenzar MOSTRARMENU.EXE

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

 :comenzar MOSTRARMENU.EXE LLAMAR A ALGUIEN NOMBRE .BAT IR A inicio

Debido a que el intérprete de comandos de DOS no compila un archivo de script y luego lo ejecuta, ni lee el archivo completo en la memoria antes de iniciar la ejecución, ni depende del contenido de un búfer de registro, cuando SHOWMENU sale, el intérprete de comandos encuentra un nuevo archivo de script. comando a ejecutar (es para invocar el archivo de script SOMENAME , en una ubicación de directorio y a través de un protocolo conocido por SHOWMENU), y una vez que se completa ese comando, regresa al inicio del archivo de script y reactiva SHOWMENU listo para la siguiente selección. . Si la opción del menú fuera salir, el archivo se reescribiría 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 de DOS recuerda la posición del byte del siguiente comando cuando debe iniciar el siguiente comando, por lo que el archivo reescrito debe mantener la alineación para que el siguiente punto de inicio del comando sea realmente el inicio del siguiente comando.

Aparte 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]

Mesas de control

Se puede considerar que los intérpretes de tablas de control son, en cierto sentido, 'automodificados' por valores de datos extraídos de las entradas de la tabla (en lugar de codificados específicamente a mano en declaraciones condicionales del formulario "IF inputx = 'yyy'").

Programas de canal

Algunos métodos de acceso de IBM utilizaban tradicionalmente programas de canal automodificables , donde un valor, como una dirección de disco, se lee en un área a la que hace referencia un programa de canal, donde un comando de canal posterior lo utiliza 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, esta 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, mejorar el rendimiento, o ambas cosas. A veces también se usaba para implementar llamadas y retornos de subrutinas cuando el conjunto de instrucciones solo proporcionaba instrucciones simples de bifurcación o omisión para variar el flujo de control . [7] [8] Este uso sigue siendo relevante en ciertas arquitecturas ultra- RISC , al menos teóricamente; consulte, por ejemplo , computadora con un conjunto de instrucciones . La arquitectura MIX de Donald Knuth también utilizó código automodificable para implementar llamadas a subrutinas. [9]

Uso

El código automodificable se puede utilizar para varios propósitos:

Optimización de un bucle dependiente del estado

Ejemplo de pseudocódigo :

repetir N veces { si el ESTADO es 1 aumentar A en uno demás disminuir A en uno hacer algo con A}

El código automodificado, en este caso, sería simplemente cuestión de reescribir el bucle de esta manera:

repetir N veces { aumentar A en uno hacer 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 va a calcular un conjunto de estadísticas como promedio, extremos, ubicación de los extremos, desviación estándar, etc. para un conjunto de datos grande. En una situación general, puede haber una opción de asociar ponderaciones con los datos, de modo que cada x i se asocie con awi y , en lugar de probar la presencia de ponderaciones en cada valor del índice, podría haber dos versiones del cálculo, una para uso con pesas y uno no, con una prueba al inicio. Ahora considere una opción adicional, que cada valor pueda tener asociado un booleano para indicar si ese valor se debe omitir o no. Esto podría manejarse produciendo cuatro lotes de código, uno para cada resultado de permutación y exceso de código. Alternativamente, las matrices de peso y omisión podrían fusionarse en una matriz temporal (con pesos cero para los valores que se omitirán), a costa del procesamiento y aún así habrá hinchazón. Sin embargo, con la modificación del código, a la plantilla para calcular las estadísticas se podría agregar, según corresponda, el código para omitir valores no deseados y para aplicar ponderaciones. No habría pruebas repetidas de las opciones y se accedería a la matriz de datos una vez, al igual que 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, puede usarse como protección contra la ingeniería inversa y el craqueo de software . El código automodificable se utilizó para ocultar instrucciones de protección contra copia en programas basados ​​en disco de la década de 1980 para plataformas como IBM PC y Apple II . Por ejemplo, en una PC IBM (o compatible ), la instrucción de acceso a la unidad de disquete noint 0x13 aparecería en la imagen del programa ejecutable, pero se escribiría en la imagen de la memoria del ejecutable después de que el programa comenzara a ejecutarse.

El código de modificación automática también lo utilizan a veces programas que no quieren revelar su presencia, como los virus informáticos y algunos códigos shell . Los virus y shellcodes que utilizan código que se modifica automáticamente 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 del búfer .

Sistemas de aprendizaje automático autorreferenciales

Los sistemas tradicionales de aprendizaje automático cuentan con 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 autorreescrituras catastróficas al asegurarse de que las automodificaciones sobrevivan solo si son útiles de acuerdo con una función de aptitud , error o recompensa determinada por el usuario . [14]

Sistemas operativos

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

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

Núcleo de síntesis de Massalin

El núcleo de síntesis presentado en el doctorado de Alexia Massalin. La tesis [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 identificadores de archivos. La generación de código para tareas específicas permite que el kernel de 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 de Synthesis era muy rápido, pero estaba escrito íntegramente en ensamblador. La resultante falta de portabilidad ha impedido que las ideas de optimización de Massalin sean 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 más complejo que los lenguajes de nivel medio existentes. Un lenguaje y un compilador de este tipo podrían permitir el desarrollo de aplicaciones y sistemas operativos más rápidos.

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

Interacción de caché y código automodificable

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

En algunos casos, secciones cortas de código que se modifica automáticamente se ejecutan más lentamente en los procesadores modernos. Esto se debe a que un procesador moderno normalmente 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 caché, lo que resulta en un ligero retraso, si el codelet modificado comparte la misma línea de caché con el código modificador, como es el caso cuando la memoria modificada La dirección se encuentra a unos pocos bytes de la del código de modificación.

El problema de invalidación de caché en los procesadores modernos generalmente significa que el código automodificado sería más rápido solo cuando la modificación ocurrirá raramente, como en el caso de un cambio de estado dentro de un bucle interno. [ cita necesaria ]

La mayoría de los procesadores modernos cargan el código de 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 como estaba antes de ser modificado. Consulte cola de entrada de captación previa (PIQ). Los procesadores de PC deben manejar correctamente el código que se modifica automáticamente por razones de compatibilidad con versiones anteriores, pero están lejos de ser eficientes en hacerlo. [ cita necesaria ]

Temas de seguridad

Debido a las implicaciones de seguridad que tiene el código automodificado, todos los principales sistemas operativos tienen cuidado de eliminar dichas vulnerabilidades a medida que se conocen. Por lo general, la preocupación no es que los programas se modifiquen a sí mismos intencionalmente, sino que puedan ser modificados maliciosamente mediante un exploit .

Un mecanismo para evitar la modificación de código malicioso es una característica del sistema operativo llamada W^X (para "escribir x o ejecutar"). Este mecanismo prohíbe que un programa haga que cualquier página de la memoria sea escribible y ejecutable. Algunos sistemas impiden que una página grabable se cambie para que sea ejecutable, incluso si se elimina el permiso de escritura. [ cita necesaria ] 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 omitir W^X es crear un archivo con todos los permisos y luego asignar el archivo a la memoria dos veces. En Linux, se puede utilizar un indicador de memoria compartida SysV no documentado para obtener memoria compartida ejecutable sin necesidad de crear un archivo. [ cita necesaria ]

Ventajas

Desventajas

El código automodificable 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 automodificación que consiste en la sustitución de punteros de función podría no ser tan críptica, si está claro que los nombres de las funciones que se llamarán son marcadores de posición para funciones que se identificarán más adelante.

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

El código de modificación automática 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 por separado de su forma original, lo que entra en conflicto con las soluciones de administración de memoria que normalmente descartan el código en la RAM y lo recargan desde el archivo ejecutable según sea necesario.

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

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

Ver también

Notas

  1. ^ Las versiones posteriores de DOS (desde la versión 6.0) introdujeron el comando CHOICE externo (en DR-DOS también el comando interno y la directiva CONFIG.SYS SWITCH ), por lo que, para este ejemplo específico de aplicación de un sistema de menús, ya no era necesario se refiere a trabajos por lotes de modificación automática; 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 kernel 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 número de repeticiones necesarias) para acelerar las transferencias de datos en disco. Se solucionan los casos extremos , como los recuentos impares. [10] [11]
  3. ^ Como ejemplo, los MBR de DR-DOS y los sectores de arranque (que también contienen la tabla de particiones y el bloque de parámetros del BIOS , dejando menos de 446, respectivamente, 423 bytes para el código) tradicionalmente podían ubicar el archivo de arranque en el archivo FAT12 o FAT16 . sistema por sí mismos y cargarlo en la memoria como un todo, en contraste con sus contrapartes MS-DOS / PC DOS , que en cambio dependían de los archivos del sistema para ocupar las dos primeras entradas del directorio en el sistema de archivos y los primeros tres sectores de IBMBIO. COM se almacenará al inicio del área de datos en sectores contiguos que contienen un cargador secundario para cargar el resto del archivo en la memoria (lo que requiere que SYS se encargue de todas estas condiciones). Cuando se agregó soporte para FAT32 y LBA , Microsoft incluso pasó a requerir 386 instrucciones y dividió el código de arranque en dos sectores por razones de tamaño, lo cual no era una opción para DR-DOS ya que se habría roto hacia atrás y la compatibilidad cruzada con otros sistemas operativos. sistemas 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 multinivel y técnicas de plegado algorítmico para aun así encajar todo en un sector físico de sólo 512 bytes sin renunciar a ninguna de sus funciones extendidas.

Referencias

  1. ^ "HP 9100A/B". MoHPC: el museo de las calculadoras HP . 1998. Memoria de programas y datos superpuestos / 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. Microenfoque .
  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 distribuida modular controlado centralmente para la configuración automática del cliente y la implementación de software con mecanismo de actualización de autorreparación en entornos LAN basado en trabajos por lotes autorreplicantes e indirectamente automodificables con huella de memoria cero en lugar de necesidad de software de administració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) . Revista IBM de investigación y desarrollo . 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 . pag. 365: El SSEC fue la primera computadora operativa capaz de tratar sus propias instrucciones almacenadas exactamente como datos, modificarlas y actuar sobre el resultado. 
  7. ^ Molinero, Barton P. (30 de octubre de 2006). "Parche de código binario: un arte antiguo refinado para el siglo XXI". Serie de profesores distinguidos de informática de Triangle: seminarios 2006-2007. Universidad Estatal de Carolina del Norte , Departamento de Ciencias de la Computación . Consultado el 25 de abril de 2023 .
  8. ^ Wenzl, Matías; Merzdovnik, Georg; Ullrich, Johanna; Weippl, Edgar R. (junio de 2019) [febrero de 2019, noviembre de 2018, mayo de 2018]. "Del truco a la técnica elaborada: un estudio sobre la reescritura binaria" (PDF) . Encuestas de Computación ACM . Viena, Austria. 52 (3): 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 . pag. 49:1: […] Originalmente, la reescritura binaria estaba motivada por la necesidad de cambiar partes de un programa durante la ejecución (por ejemplo, parches en tiempo de ejecución en el PDP-1 en la década de 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 "Kit de código fuente legible por máquina (MRS) Caldera OpenDOS 7.01". Caldera, Inc. 1997-05-01. Archivado desde el original el 7 de agosto de 2021 . Consultado el 2 de enero de 2022 .[1]
  11. ^ abcd Paul, Matthias R. (2 de octubre de 1997). "Caldera OpenDOS 7.01/7.02 Actualización 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 la empresa Heath de Bill Wilkinson . 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 actualizar 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 un byte de datos. Si uno de los chips 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 recupera una instrucción, pero obtiene 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 obtenidas son de la ROM , no de la RAM […] lo que hace que el H89 pase la prueba de memoria pero aún funcione de manera errática en algunos programas. […] Este es un programa que prueba la memoria reubicándose a través de la RAM. Al hacerlo, la CPU imprime la dirección actual del programa en el CRT y luego recupera la instrucción en esa dirección. Si los circuitos integrados 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 circuitos integrados 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 manera impredecible. Sin embargo, es probable que la pantalla se bloquee mostrando la dirección del IC defectuoso. Esto reduce el problema a ocho circuitos integrados, lo que supone una mejora con respecto a tener que comprobar hasta 32. […] El […] programa realizará una prueba de gusano presionando una instrucción RST 7 (RESTART 7) desde el extremo inferior de la memoria. hasta la última dirección laboral. El resto del programa permanece estacionario y maneja la visualización de 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 de NOP (NO OPERACIÓN). […]
  13. ^ Ortiz, Carlos Enrique (29 de agosto de 2015) [18 de agosto de 2007]. "Sobre el código automodificable y el sistema operativo del transbordador espacial" . Consultado el 25 de abril de 2023 .
  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 kernel de Linux: qué, dónde y cómo" . Consultado el 27 de noviembre de 2022 .
  16. ^ Wieczorkiewicz, Pawel. "Alternativas del 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, Estados Unidos: 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 servicios fundamentales de 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 .

Otras lecturas

enlaces externos