2010-06-16 14 views
30
  • estoy pensando en escribir recientemente programas auto-modificación, creo que puede ser de gran alcance y divertido ... Así que actualmente estoy buscando un lenguaje que permiten modificar el propio código del programa con facilidad. .código mutante

  • leí sobre C# (como una forma de evitar) y la capacidad para compilar código -y Execute- en tiempo de ejecución, pero que es demasiado sufriendo ..

  • también estoy pensando en montaje ... es más fácil que hay que cambiar la ejecución de código pero no es muy potente (muy crudo) ...

¿Me puede sugerir un poderoso lenguaje -o un feature- que apoyan la modificación de código en tiempo de ejecución ..?

Consejos
Que lo que quiero decir, modificando 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 ser la construcción de una lista de instrucciones:

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

Gracias!

+7

¿Desea compilar/ejecutar código en tiempo de ejecución, o desea modificar el ejecutable mientras se carga en la memoria: esas son dos cosas * muy * diferentes. (Por lo general * "auto-modificación" * significa el segundo) –

+1

@BlueRaja - Danny Pflughoeft: Estoy interesado en el segundo ... El primero es cuando el segundo es imposible o no está disponible ... – Betamoo

+0

Solía ​​pensar en mí mismo -Código de modificación mucho. Nunca he encontrado mucho uso después de aprender sobre punteros de función y lenguajes orientados a objetos. ¿Tienes algún uso en el mundo real para esto? –

Respuesta

42

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

(*) Descargo de responsabilidad: Puede que en realidad no sea divertido.

+19

El lenguaje de programación donde le tomó algunos años a una persona escribir hola mundo ... Oh, espera, el programa hello world fue generado por una computadora. Diviértete lulz. – Warty

0

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

8

Personalmente, me resulta bastante extraño que encuentre el conjunto más fácil de manejar que C#. Encuentro aún más extraño que pienses que el ensamblaje no es tan poderoso: no puedes obtener más poder que el lenguaje de máquina sin procesar. 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 escribe C/C++ y lo emite a un compilador. Esto solo sería viable si su solución no requiere un tiempo de respuesta de autorreversión rápido (del orden de decenas de segundos o más).

Javascript y Python son compatibles con la reflexión también. Si estás pensando en aprender un nuevo y divertido lenguaje de programación que sea poderoso pero no técnicamente masivo, sugeriría Python.

+6

No veo nada extraño aquí. La asamblea es casi tan simple como se puede obtener, mientras que C# es enorme y compleja, ¡y lo digo como alguien que ha estado escribiendo C# durante un par de años! En cuanto al poder, creo que en la programación generalmente significa algo como "capacidad expresiva" o "capacidad de creación de abstracción" (¡obviamente el significado literal de "poder" es inútil aquí!), Y el lenguaje ensamblador es excepcionalmente pobre en eso. – Ken

+0

@Reinderien: me refiero en términos de cambiar el código existente, el ensamblaje es más fácil que C# ... También en términos de legibilidad y escritura, el ensamblaje es menos potente ... – Betamoo

+0

Creo que asm es mucho más fácil que C# o Java. Es muy sencillo y sin complicaciones. –

9

puedo sugerir Python, un buen lenguaje dinámico muy alto nivel, que tiene una rica introspección incluido (y por el uso, por ejemplo, de compile, eval o exec permite una forma de código auto-modificable). 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 solamente se altera en el ámbito de la función.

5

Muchos idiomas le permiten eval code at runtime.

  • Lisp
  • Perl
  • Python
  • PHP
  • Rubí
  • maravilloso (a través de GroovyShell)
20

le recomiendo Lisp. Los datos Lisp se pueden leer y ejecutar como código. El código Lisp se puede escribir como datos.

Se considera uno de los idiomas canónicos modificables por sí mismos.

lista Ejemplo (de datos):

'(+ 1 2 3) 

o, llamando a los datos como código

(eval '(+ 1 2 3)) 

ejecuta la función +.

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

edición:

escribí un programa para generar dinámicamente un programa y evaluar sobre la marcha, entonces me informará cómo se compara con una línea de base (div por 0 fue el informe de costumbre, ja).

7

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

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

4

En los lenguajes de alto nivel en los que compila y ejecuta código en tiempo de ejecución, no se trata en realidad de código de automodificación, sino de carga dinámica de clases. Usando principios de herencia, puede reemplazar una clase Factory y cambiar el comportamiento de la aplicación en tiempo de ejecución.

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

11

Hasta ahora, todas las respuestas se refieren a la compilación de reflexión/tiempo de ejecución, pero en los comentarios que mencionas te interesan self-modifying code - código que se modifica en la memoria.

No hay forma de hacerlo en C#, Java o incluso (de forma portátil) en C, es decir, no puede modificar el binario cargado en memoria utilizando 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 polymorphic viruses, los sistemas operativos más modernos (incluidos Windows XP +, Linux y BSD) imponen W^X, lo que significa que tiene que escribir go through some trouble para ejecutar ejecutables polimórficos en esos 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 está ejecutando. Perl, Python (ver here), y todas las implementaciones de Javascript que conozco no permiten esto, sin embargo.

+0

Tiene un buen punto. Dependiendo de cómo lo mires, C#/otros sabores de .NET/Java usan bytecode en lugar del ensamblaje correcto, pero el problema es el siguiente. – Reinderien

+0

Debo añadir que, si lo hiciera, la forma indirecta y poco convencional de emitir código fuente de forma iterativa a un compilador, ejecutar el binario y luego modificar ese código binario para volver a emitirlo al compilador ... Eso tendría (efectivamente) acceso de lectura y escritura al código del programa, aunque el tiempo de respuesta de lectura-escritura sea malo. – Reinderien

+0

Aunque estoy de acuerdo con la esencia del sentimiento, sugeriría la posibilidad (en Python por ejemplo: http://geofft.mit.edu/blog/sipb/73) de alterar directamente el bytecode generado/en ejecución (que conceptualmente no lo hace) difieren mucho de hacer lo mismo con el ensamblaje). – ChristopheD

2

A veces, aunque muy rara vez 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é diferido) están inicializados correctamente o no. Por lo tanto, debe verificar al comienzo de su método si los datos están inicializados correctamente y luego tal vez inicializarlos. Pero realmente solo tienes que hacer esa inicialización una vez, pero la compruebas todas las veces.

Por lo tanto, a veces escribo un método que realiza la inicialización y luego se reemplaza 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, sinceramente, no creo que valga la pena. De hecho, me da vergüenza admitir que nunca comparé realmente para ver si ese condicional de realmente hace alguna diferencia. (En una moderna aplicación rubí con un compilador JIT optimización agresiva perfil de retroalimentación impulsada probablemente no.)

Tenga en cuenta que, dependiendo de cómo se definir "código mutante", esto puede o no ser lo que querer. Usted es reemplazando alguna parte del programa de ejecución actualmente, así que & hellip;

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 sí mismo es costoso, 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 es realmente que se le haya permitido llamar como "JVM" porque sus desarrolladores no ejecutan las pruebas de compatibilidad) escrito completamente en Java. Ahora, hay muchas JVM escritas, pero Maxine es la única que sé que también ejecuta en sí mismo. 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 ocurre en el Klein VM que es una máquina virtual para el lenguaje de auto programación.

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

1

Puede hacerlo en Maple (el lenguaje de álgebra computacional).A diferencia de las muchas respuestas anteriores que utilizan lenguajes compilados que solo le permiten crear y vincular en el nuevo código en tiempo de ejecución, aquí puede modificar honestamente el código de un programa actualmente en ejecución. (Ruby y Lisp, según lo indicado por otros respondedores, también le permiten hacer esto, probablemente también Smalltalk).

En realidad, en Maple solía ser 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 han indicado otros: necesita un lenguaje interpretado con fuertes instalaciones de reflexión y reificación para lograr esto.

He escrito un normalizador/simplificador automatizado para el código de Maple, que procedí a ejecutar en toda la biblioteca (incluido él mismo); y debido a que no fui muy cuidadoso en todo mi código, el normalizador sí se modificó. También escribí un Partial Evaluator (recientemente aceptado por SCP) llamado MapleMIX - available on sourceforge - pero no pude aplicarlo completamente a sí mismo (ese no era el objetivo del diseño).

0

En Lua, puede "enganchar" el código existente, 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 más funciones, que tipo de auto le da la modificación de código.

2

Escribí el código de clase de Python que le permite agregar y eliminar nuevas líneas de código al objeto, imprimir el código y superarlo. 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] 

Una vez creado el código se puede imprimir:

#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 

Ejecutar la cade llamando al objeto: Código()

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 por el valor 2 y borró todo el bloque if. Esto podría ser útil para evitar verificar las condiciones una vez que se cumplen. En la vida real, este escenario de caso podría ser manejado por un sistema coroutine, pero este experimento de código de auto modificación 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] 
Cuestiones relacionadas