El código automodificable (SMC) es una técnica de programación en la que una aplicación crea o cambia parte de su código de programa en tiempo de ejecución. Dicho código se usa generalmente en programas escritos para un procesador con una organización de memoria de von Neumann .
En el momento de la modificación, el método se divide en:
En ambos casos, el cambio tiene lugar directamente en el código máquina cuando las nuevas instrucciones sobrescriben las antiguas (por ejemplo, una rama condicional JZ , JNZ , JE , JNE , etc. se reemplaza por una rama incondicional JMP o NOP ). Los conjuntos de instrucciones de IBM/360 y Z/Architecture tienen una instrucción EXECUTE (EX) que sobrescribe la instrucción de destino (registrada en el segundo byte de la instrucción EX) con los 8 bits menos significativos del registro 1. En estas arquitecturas, implementa un método estándar y legítimo para cambiar temporalmente las instrucciones.
Principales aplicaciones del código automodificable:
En la arquitectura Harvard , la memoria para código y la memoria para datos están separadas. En consecuencia, el trabajo del código automodificable se vuelve mucho más complicado en ellos. Aunque la arquitectura x86 se define como von Neumann (código único y memoria de datos), la mayoría de los procesadores modernos tienen áreas de caché separadas para código y datos. Al mismo tiempo, el caché de código no admite la escritura y, al cambiar el área de memoria caché, se realiza un restablecimiento parcial o completo del hardware del caché de código (x86) o una instrucción explícita al procesador para restablecer el caché de código ( SPARC ) puede ser requerido. Debido a esto, el código recién modificado puede ejecutarse más lentamente o requerir comandos adicionales para funcionar correctamente. Además, cambiar el código restablece la canalización del procesador . [2]
Además, algunas ideas de la arquitectura de Harvard se implementan en el sistema operativo (por ejemplo, prevención de ejecución de datos en Windows, W^X en OpenBSD ) y en procesadores (para x86 - NX bit y similares). En estas implementaciones, los fragmentos individuales de memoria se pueden marcar como no ejecutables (es decir, datos) o como ejecutables pero no modificables (es decir, código sin derecho a cambios). El uso de código automodificable en dichos entornos de programación es complicado, ya que debe ubicarse en un área de memoria desprotegida (a veces, esta área es la pila ), o deshabilitar explícitamente la protección para que el código se cambie. .
Perl , PHP y Python permiten que un programa cree código nuevo en tiempo de ejecución y lo ejecute usando la función eval, pero no permiten que el código existente se automodifique (shell interactivo de python) :
>>> x = 1 >>> valor ( 'x + 1' ) 2 >>> valor ( 'x' ) 1La ilusión de modificación (suponiendo que no se cambie realmente el código nativo) se logra cambiando el puntero de función, como en este ejemplo de JavaScript :
var f = función ( x ) { devuelve x + 1 }; alerta ( f ( 0 )); //una f = nueva función ( 'x' , 'return x + 2' ); // asigna una nueva definición a f alert ( f ( 0 )); //2