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:
- sólo durante la inicialización – basada en parámetros de entrada (cuando el proceso se describe más comúnmente como ' configuración ' de software y es algo análogo, en términos de hardware, a la configuración de puentes para placas de circuitos impresos ). La alteración de los punteros de entrada del programa es un método indirecto equivalente de automodificación, pero que requiere la coexistencia de una o más rutas de instrucciones alternativas, lo que aumenta el tamaño del programa .
- Durante la ejecución ("sobre la marcha") – en función de estados específicos del programa que se hayan alcanzado durante la ejecución
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:
- superposición de instrucciones existentes (o partes de instrucciones como código de operación, registro, indicadores o direcciones) o
- creación directa de instrucciones completas o secuencias de instrucciones en la memoria
- Creación o modificación de declaraciones de código fuente seguida de una 'minicompilación' o una interpretación dinámica (ver declaración eval )
- Crear un programa completo de forma dinámica y luego ejecutarlo.
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 VEZ
ABIERTO 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 podría modificarse a voluntad después del primer paso para omitir la APERTURA (tener que cargar primero un puntero 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 semiautomática de un bucle dependiente del estado.
- Optimización dinámica de código in situ para la velocidad en función del entorno de carga. [10] [11] [nb 2]
- Generación de código en tiempo de ejecución o especialización de un algoritmo en tiempo de ejecución o tiempo de carga (lo cual es popular, por ejemplo, en el dominio de gráficos en tiempo real), como una utilidad de clasificación general: preparación del código para realizar la comparación de claves descrita en una invocación específica.
- Modificación del estado en línea de un objeto o simulación de la construcción de alto nivel de cierres .
- Parcheado de la llamada de dirección de subrutina ( puntero ), generalmente como se realiza en el momento de carga/inicialización de bibliotecas dinámicas , o bien en cada invocación, parcheando las referencias internas de la subrutina a sus parámetros para usar sus direcciones reales (es decir, automodificación indirecta).
- Sistemas de computación evolutiva como la neuroevolución , la programación genética y otros algoritmos evolutivos .
- Ocultación de código para evitar ingeniería inversa (mediante el uso de un desensamblador o depurador ) o para evadir la detección por parte de software de escaneo de virus/spyware y similares.
- Llenar el 100% de la memoria (en algunas arquitecturas) con un patrón rotatorio de códigos de operación repetitivos , para borrar todos los programas y datos, o para grabar hardware o realizar pruebas de RAM . [12]
- Código de compresión para ser descomprimido y ejecutado en tiempo de ejecución, por ejemplo, cuando la memoria o el espacio en disco son limitados. [10] [11]
- Algunos conjuntos de instrucciones muy limitados no dejan otra opción que usar código automodificable para realizar ciertas funciones. Por ejemplo, una computadora con un conjunto de instrucciones único (OISC) que usa solo la "instrucción" de restar y ramificar si es negativo no puede hacer una copia indirecta (algo así como el equivalente de "*a = **b" en el lenguaje C ) sin usar código automodificable.
- Arranque . Los primeros microordenadores solían utilizar código automodificable en sus cargadores de arranque. Dado que el cargador de arranque se introducía mediante el panel frontal cada vez que se encendía el ordenador, no importaba si el cargador de arranque se modificaba a sí mismo. Sin embargo, incluso hoy en día muchos cargadores de arranque se reubican automáticamente y algunos incluso se modifican a sí mismos. [nb 3]
- Modificación de instrucciones para tolerancia a fallos. [13]
Optimización de un bucle dependiente del estado
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: que cada valor pueda 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 autorreescrituras 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 los 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 raramente, 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
- Se pueden establecer rutas rápidas para la ejecución de un programa, reduciendo algunas ramas condicionales que de otro modo serían repetitivas .
- El código automodificable puede mejorar la eficiencia algorítmica .
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:
- El software de aplicación que se ejecuta en un sistema operativo con seguridad W^X estricta no puede ejecutar instrucciones en las páginas en las que tiene permitido escribir; solo el sistema operativo tiene permitido escribir instrucciones en la memoria y luego ejecutar esas instrucciones.
- Muchos microcontroladores de arquitectura Harvard no pueden ejecutar instrucciones en la memoria de lectura-escritura, sino sólo instrucciones en la memoria en la que no pueden escribir, ROM o memoria flash no autoprogramable .
- Una aplicación multiproceso puede tener varios subprocesos que ejecutan la misma sección de código automodificable, lo que posiblemente genere errores de cálculo y fallas en la aplicación.
Véase también
- Código superpuesto
- Código polimórfico
- Motor polimórfico
- Estructura de datos persistente
- Código AARD
- Eficiencia algorítmica
- Datos como código
- Declaración de evaluación
- IBM 1130 (Ejemplo)
- Compilación justo a tiempo : esta técnica a menudo puede brindar a los usuarios muchos de los beneficios del código automodificable (excepto el tamaño de la memoria) sin las desventajas.
- Eliminación dinámica de código muerto
- Homoiconicidad
- PCASTL
- Quine (informática)
- Autorreplicación
- Programación reflexiva
- Parche de mono : una modificación del código de tiempo de ejecución que no afecta el código fuente original de un programa.
- Programación extensible : un paradigma de programación en el que un lenguaje de programación puede modificar su propia sintaxis.
- Virus informático que se modifica automáticamente
- Hospedaje propio
- Programación sintética
- Arranque del compilador
- Microcódigo parcheable
Notas
- ^ 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.
- ^ 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 bitsREP 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] - ^ 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
- ^ "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 .
- ^ "La declaración ALTER". Referencia del lenguaje COBOL. Micro Focus .
- ^ Spector, Lee. "Computación evolutiva con Push: Push, PushGP y Pushpop" . Consultado el 25 de abril de 2023 .
- ^ ab Fosdal, Lars (2001). "Archivo por lotes automodificable". Archivado desde el original el 21 de abril de 2008.
- ^ 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).
- ^ 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.
- ^ 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 .
- ^ 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)
- ^ 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 .
- ^ abcd "Caldera OpenDOS Machine Readable Source Kit (MRS) 7.01". Caldera, Inc. 1 de mayo de 1997. Archivado desde el original el 7 de agosto de 2021. Consultado el 2 de enero de 2022 .[1]
- ^ 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]
- ^ 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). […]
- ^ Ortiz, Carlos Enrique (2015-08-29) [2007-08-18]. "Sobre el código automodificable y el sistema operativo del transbordador espacial" . Consultado el 25 de abril de 2023 .
- ^ Publicaciones de Jürgen Schmidhuber sobre código automodificable para sistemas de aprendizaje automático autorreferenciales
- ^ 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 .
- ^ Wieczorkiewicz, Pawel. «Alternativas al kernel de Linux» . Consultado el 27 de noviembre de 2022 .
- ^ 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]
- ^ 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 .
- ^ 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
- Åkesson, Linus (31 de marzo de 2013). «Descodificación GCR sobre la marcha». Archivado desde el original el 21 de marzo de 2017. Consultado el 21 de marzo de 2017 .
- Bürckert, Christian Félix (20 de marzo de 2012). Eine Bibliothek für Selbstmodifikationen zur Laufzeit in Java [Una biblioteca para automodificaciones en tiempo de ejecución en Java ] (PDF) (Tesis) (en alemán). Universität des Saarlandes , Naturwissenschaftlich-Technische Fakultät I, Fachrichtung Informatik. Archivado (PDF) desde el original el 18 de agosto de 2023 . Consultado el 18 de agosto de 2023 .(80 páginas)
Enlaces externos
- Uso de código automodificable en Linux
- Código C automodificable
- Código certificado de automodificación