dynamic-languages self-modifying

dynamic languages - Código auto modificable



dynamic-languages self-modifying (13)

¿Has mirado a Java? Java 6 tiene una API de compilación , por lo que puede escribir código y compilarlo dentro de Java VM.

  • Recientemente estoy pensando en escribir programas auto-modificables , creo que puede ser poderoso y divertido ... Así que actualmente estoy buscando un lenguaje que permita modificar el código propio del programa fácilmente.

  • Leí sobre C # (como una forma de evitarlo) y la capacidad de compilar y ejecutar el código en tiempo de ejecución, pero eso es demasiado doloroso.

  • También estoy pensando en el ensamblaje ... es más fácil cambiar el código de ejecución pero no es muy poderoso (muy simple) ...

¿Pueden sugerirme un lenguaje potente -o una característica- que admita la modificación de código en tiempo de ejecución ...?

Sugerencias
Eso es lo que quiero decir al modificar el código en tiempo de ejecución:

Start: a=10,b=20,c=0; label1: c=a+b; .... label1= c=a*b; goto label1;

y puede estar construyendo una lista de instrucciones:

code1.add(c=a+b); code1.add(c=c*(c-1)); code1. execute();

¡Gracias!


A veces, aunque muy raramente hago código de auto modificación en Ruby.

A veces tiene un método en el que realmente no sabe si los datos que está utilizando (por ejemplo, un caché perezoso) se inicializan correctamente o no. Por lo tanto, debe verificar al comienzo de su método si los datos están correctamente inicializados y luego tal vez inicializarlos. Pero realmente solo tienes que hacer esa inicialización una vez, pero la verificas cada vez.

Entonces, a veces escribo un método que realiza la inicialización y luego se reemplaza a sí mismo con una versión que no incluye el código de inicialización.

class Cache def [](key) @backing_store ||= self.expensive_initialization def [](key) @backing_store[key] end @backing_store[key] end end

Pero honestamente, no creo que valga la pena. De hecho, me avergüenza admitir que nunca he realizado una evaluación comparativa para ver si ese condicional realmente hace alguna diferencia. (En una implementación moderna de Ruby con un compilador JIT basado en la retroalimentación que optimiza agresivamente probablemente no).

Tenga en cuenta que, dependiendo de cómo defina el "código de auto-modificación", esto puede o no ser lo que desea. Está reemplazando parte del programa que se está ejecutando actualmente , así que ...

EDIT: Ahora que lo pienso, esa optimización no tiene mucho sentido. La costosa inicialización solo se ejecuta una vez de todos modos. Lo único que evita la modificación, es el condicional. Sería mejor tomar un ejemplo donde el cheque en es caro, pero no puedo pensar en uno.

Sin embargo, pensé en un buen ejemplo de código de auto modificación: el Maxine JVM . Maxine es una VM de investigación (técnicamente no se puede llamar "JVM" porque sus desarrolladores no ejecutan las pruebas de compatibilidad) escritas completamente en Java. Ahora, hay muchas JVM escritas en sí mismas, pero Maxine es la única que conozco que también se ejecuta en sí misma. Esto es extremadamente poderoso. Por ejemplo, el compilador JIT puede compilarse JIT para adaptarlo al tipo de código que está compilando JIT.

Algo muy similar sucede en la máquina virtual de Klein, que es una máquina virtual para el lenguaje de programación automática.

En ambos casos, la máquina virtual puede optimizar y recompilarse en tiempo de ejecución.


En Lua , puede "enganchar" el código existente, lo que le permite asociar código arbitrario a las llamadas de función. Es algo parecido a esto:

local oldMyFunction = myFunction myFunction = function(arg) if arg.blah then return oldMyFunction(arg) end else --do whatever end end

También puede simplemente arar las funciones, lo que le da un código de auto-modificación.


En los lenguajes de alto nivel donde compila y ejecuta el código en tiempo de ejecución, no es realmente un código auto-modificable, sino una carga dinámica de clases. Al usar los principios de herencia, puede reemplazar una clase de Factory y cambiar el comportamiento de la aplicación en tiempo de ejecución.

Solo en lenguaje ensamblador realmente tiene auto-modificación verdadera, escribiendo directamente en el segmento de código. Pero hay poco uso práctico para ello. Si te gusta un desafío, escribe un autocifrado, tal vez un virus polimórfico. Eso sería divertido.


Escribí el código de clase de Python que le permite agregar y eliminar nuevas líneas de código al objeto, imprimirlo y ejecutarlo. Código de clase que se muestra al final.

Ejemplo: si x == 1, el código cambia su valor a x = 2 y luego elimina todo el bloque con el condicional que verificó esa condición.

#Initialize Variables x = 1 #Create Code code = Code() code + ''global x, code'' #Adds a new Code instance code[0] with this line of code => internally code.subcode[0] code + "if x == 1:" #Adds a new Code instance code[1] with this line of code => internally code.subcode[1] code[1] + "x = 2" #Adds a new Code instance 0 under code[1] with this line of code => internally code.subcode[1].subcode[0] code[1] + "del code[1]" #Adds a new Code instance 0 under code[1] with this line of code => internally code.subcode[1].subcode[1]

Después de crear el código puedes imprimirlo:

#Prints print "Initial Code:" print code print "x = " + str(x)

Salida:

Initial Code: global x, code if x == 1: x = 2 del code[1] x = 1

Ejecute el cade llamando al objeto: code ()

print "Code after execution:" code() #Executes code print code print "x = " + str(x)

Salida 2:

Code after execution: global x, code x = 2

Como puede ver, el código cambió la variable x al valor 2 y eliminó todo el bloque if. Esto podría ser útil para evitar verificar las condiciones una vez que se cumplen. En la vida real, este caso de caso podría ser manejado por un sistema coroutine, pero este experimento de código modificador es solo por diversión.

class Code: def __init__(self,line = '''',indent = -1): if indent < -1: raise NameError(''Invalid {} indent''.format(indent)) self.strindent = '''' for i in xrange(indent): self.strindent = '' '' + self.strindent self.strsubindent = '' '' + self.strindent self.line = line self.subcode = [] self.indent = indent def __add__(self,other): if other.__class__ is str: other_code = Code(other,self.indent+1) self.subcode.append(other_code) return self elif other.__class__ is Code: self.subcode.append(other) return self def __sub__(self,other): if other.__class__ is str: for code in self.subcode: if code.line == other: self.subcode.remove(code) return self elif other.__class__ is Code: self.subcode.remove(other) def __repr__(self): rep = self.strindent + self.line + ''/n'' for code in self.subcode: rep += code.__repr__() return rep def __call__(self): print ''executing code'' exec(self.__repr__()) return self.__repr__() def __getitem__(self,key): if key.__class__ is str: for code in self.subcode: if code.line is key: return code elif key.__class__ is int: return self.subcode[key] def __delitem__(self,key): if key.__class__ is str: for i in range(len(self.subcode)): code = self.subcode[i] if code.line is key: del self.subcode[i] elif key.__class__ is int: del self.subcode[key]


Hasta ahora, cada respuesta tiene que ver con la compilación de reflexión / tiempo de ejecución, pero en los comentarios que mencionó está interesado en el código de auto-modificación real, código que se modifica a sí mismo en la memoria.

No hay forma de hacer esto en C #, Java o incluso (de manera portátil) en C, es decir, no puede modificar el binario en memoria cargado usando estos idiomas.

En general, la única forma de hacerlo es con el ensamblaje, y es altamente dependiente del procesador. De hecho, también depende en gran medida del sistema operativo: para proteger contra los virus polimórficos , la mayoría de los sistemas operativos modernos (incluidos Windows XP +, Linux y BSD) imponen W^X , lo que significa que tiene que pasar por algunos problemas para escribir ejecutables polimórficos en Aquellos sistemas operativos, para los que lo permiten en absoluto.

Es posible que en algunos idiomas interpretados el programa modifique su propio código fuente mientras se ejecuta. Sin embargo, Perl, Python (ver here ) y todas las implementaciones de Javascript que conozco no permiten esto.


Muchos idiomas le permiten eval código en tiempo de ejecución.

  • Ceceo
  • Perl
  • Pitón
  • PHP
  • Rubí
  • Groovy (a través de GroovyShell)

Personalmente, me parece bastante extraño que encuentre el ensamblaje más fácil de manejar que C #. Me parece aún más extraño que piense que el ensamblaje no es tan poderoso: no puede obtener más poderoso que el lenguaje de máquina en bruto. De todos modos, para cada uno.

C # tiene excelentes servicios de reflexión, pero si tiene una aversión a eso ... Si realmente se siente cómodo con C o C ++, siempre puede escribir un programa que escriba C / C ++ y lo emita a un compilador. Esto solo sería viable si su solución no requiere un tiempo rápido de auto-reescritura (en el orden de decenas de segundos o más).

Javascript y Python también soportan la reflexión. Si estás pensando en aprender un lenguaje de programación nuevo y divertido que sea potente pero que no sea muy exigente desde el punto de vista técnico, te sugiero Python.


Puedes hacer esto en Maple (el lenguaje de álgebra computacional). A diferencia de las muchas respuestas anteriores que usan lenguajes compilados que solo le permiten crear y vincular un código nuevo en tiempo de ejecución, aquí puede modificar el código de un programa actualmente en ejecución. (Ruby y Lisp, como lo indican otros respondedores, también te permiten hacer esto; probablemente Smalltalk también).

En realidad, solía ser estándar en Maple que la mayoría de las funciones de la biblioteca eran trozos pequeños que cargaban su auto "real" desde el disco en la primera llamada, y luego se auto-modificaban a la versión cargada. Este ya no es el caso ya que la carga de la biblioteca se ha virtualizado.

Como otros lo han indicado: necesita un lenguaje interpretado con sólidas instalaciones de reflexión y reificación para lograrlo.

He escrito un normalizador / simplificador automatizado para el código Maple, que procedí a ejecutar en toda la biblioteca (incluso a sí mismo); y como no tenía mucho cuidado con todo mi código, el normalizador se modificó a sí mismo. También escribí un Evaluador Parcial (recientemente aceptado por SCP) llamado MapleMIX, disponible en sourceforge , pero no pude aplicarlo completamente a sí mismo (ese no era el objetivo del diseño).


Puedo sugerir Python , un buen lenguaje dinámico de alto nivel que incluye una rica introspección (y, por ejemplo, el uso de compile , eval o exec permite una forma de código de modificación automática). Un ejemplo muy simple basado en su pregunta:

def label1(a,b,c): c=a+b return c a,b,c=10,20,0 print label1(a,b,c) # prints 30 newdef= / """ def label1(a,b,c): c=a*b return c """ exec(newdef,globals(),globals()) print label1(a,b,c) # prints 200

Tenga en cuenta que en el ejemplo de código anterior c solo se altera en el alcance de la función.


Recomiendo mucho a Lisp. Los datos de Lisp se pueden leer y ejecutar como código. El código Lisp se puede escribir como datos.

Es considerado uno de los lenguajes canónicos auto-modificables.

Ejemplo de lista (datos):

''(+ 1 2 3)

o, llamando a los datos como código

(eval ''(+ 1 2 3))

ejecuta la función +.

También puede entrar y editar los miembros de las listas sobre la marcha.

editar:

Escribí un programa para generar dinámicamente un programa y evaluarlo sobre la marcha, luego me informo cómo lo hizo en comparación con una línea de base (div por 0 era el informe habitual, ha).


Common Lisp fue diseñado con este tipo de cosas en mente. También puede probar Smalltalk , donde el uso de la reflexión para modificar el código en ejecución no es desconocido.

En ambos idiomas es probable que reemplace una función completa o un método completo, no una sola línea de código. Los métodos de Smalltalk tienden a ser más específicos que las funciones de Lisp, por lo que puede ser un buen lugar para comenzar.


Malbolge sería un buen lugar para comenzar. Cada instrucción es auto-modificable, y es muy divertido jugar con ella.

(*) Descargo de responsabilidad: en realidad no puede ser divertido.