Самостоятельной Модификации Кода


  • В последнее время я думаю о написании самоизменяющихся программ, я думаю, что это может быть мощным и интересным... Поэтому в настоящее время я ищу язык, который позволит легко изменять собственный код программы..

  • Я читал о C# (как способ обхода) и способности компилировать и выполнять код во время выполнения, но это слишком больно..

  • я также думаю о сборке... там легче изменить запущенный код, но он не очень мощный (очень сырой)...

можете ли вы предложить мне мощный язык -или функцию-которая поддерживает изменение кода во время выполнения?.?

Подсказки
Вот что я имею в виду, изменяя код во время выполнения:

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

И может составлять список инструкций:

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

Спасибо!

13 30

13 ответов:

Malbolge было бы хорошим местом для начала. Каждая инструкция самоизменяется, и с ней очень весело(*) играть.

(*) отказ от ответственности: на самом деле это не может быть весело.

Я настоятельно рекомендую Lisp. Данные Lisp могут быть прочитаны и исполнены как код. Лисп-код может быть записан в виде данных.

Он считается одним из канонических самомодифицируемых языков.

Пример списка (данных):

'(+ 1 2 3) 

Или, вызывая данные как код

(eval '(+ 1 2 3)) 

Запускает функцию+.

Вы также можете войти и редактировать членов списков на лету.

Правка:

Я написал программу, чтобы динамически генерировать программу и оценивать ее на лету, затем доложите мне, как это произошло по сравнению с базовым уровнем (div by 0 был обычным отчетом, ха).

Все ответы до сих пор касаются компиляции reflection / runtime, но в комментариях, которые вы упомянули, вас интересует фактическийсамоизменяющийся код -код, который изменяет себя в памяти.

Нет способа сделать это в C#, Java или даже (переносимо) в C - то есть вы не можете изменить загруженный в память двоичный файл, используя эти языки.

В общем случае, единственный способ сделать это-это сборка, и она сильно зависит от процессора. На самом деле, это очень операционная система кроме того, для защиты от полиморфных вирусов Большинство современных операционных систем (включая Windows XP+, Linux и BSD) принудительно применяют W^X , что означает, что вы должны пройти через некоторые трудности , чтобы написать полиморфные исполняемые файлы в этих операционных системах, для тех, которые позволяют это вообще.

В некоторых интерпретируемых языках может быть возможно, что программа изменит свой собственный исходный код во время выполнения. Perl, Python (видишь здесь), и все известные мне реализации Javascript этого не допускают.

Могу я предложить Python , хороший динамический язык очень высокого уровня, который включает в себя богатый интроспекционный анализ (и, например, использование compile, eval или exec допускает форму самоизменяющегося кода). Очень простой пример, основанный на вашем вопросе:

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
Обратите внимание, что в приведенном выше примере кода c изменяется только область действия функции.

Лично я нахожу довольно странным, что вы находите сборку более легкой для обработки, чем C#. Я нахожу еще более странным, что вы думаете, что сборка не так мощна: вы не можете получить ничего более мощного, чем сырой машинный язык. Во всяком случае, каждому свое.

C# имеет отличные службы отражения, но если у вас есть отвращение к этому.. Если вы действительно знакомы с C или C++, вы всегда можете написать программу, которая пишет C/C++ и выдает его компилятору. Это было бы только жизнеспособно, если ваш решение не требует быстрого самостоятельного переписывания времени оборота (порядка десятков секунд и более).

Javascript и Python также поддерживают отражение. Если вы хотите изучить новый, интересный язык программирования, который является мощным, но не слишком технически сложным, я бы предложил Python.

Общий шепелявый язык был разработан с учетом такого рода вещей. Вы также можете попробовать Smalltalk , где использование отражения для изменения запущенного кода не является неизвестным.

В обоих этих языках вы, скорее всего, замените всю функцию или весь метод, а не одну строку кода. Методы Smalltalk, как правило, более мелкозернистые, чем функции Lisp, так что это может быть хорошим местом для начала.

Многие языки позволяют вамeval код во время выполнения.

  • Лисп
  • Perl
  • Python
  • PHP
  • Рубин
  • Groovy (через GroovyShell)

В языках высокого уровня, где вы компилируете и выполняете код во время выполнения, это не самоизменяющийся код, а динамическая загрузка класса. Используя принципы наследования, можно заменить фабрику классов и изменить поведение приложения во время выполнения.

Только в языке ассемблера вы действительно имеете истинную самомодификацию, записывая непосредственно в сегмент кода. Но практического применения у него мало. Если вам нравится вызов, напишите самошифрующийся, возможно, полиморфный вирус. Это было бы забавно.

Я написал код класса Python, который позволяет добавлять и удалять новые строки кода к объекту, печатать код и выделять его. Код класса показан в конце.

Пример: если x == 1, то код изменяет свое значение на x = 2, а затем удаляет весь блок с условием, которое проверяло это условие.

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

После создания кода Вы можете распечатать его:

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

Вывод:

Initial Code:

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

x = 1

Выполните cade, вызвав объект: code ()

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

Вывод 2:

Code after execution:

global x, code

x = 2
Как вы можете видеть, код изменил переменную x на значение 2 и удалил весь блок if. Это может быть полезно, чтобы избежать проверки условий после их выполнения. В реальной жизни этот сценарий может быть обработан системой сопрограмм, но этот эксперимент с самоизменяющимся кодом - просто забава.
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]

Я иногда, хотя Очень редко делаю самоизменяющийся код в Ruby.

Иногда у вас есть метод, в котором вы действительно не знаете, правильно ли инициализированы данные, которые вы используете (например, какой-то ленивый кэш). Таким образом, вы должны проверить в начале вашего метода, правильно ли инициализированы данные, а затем, возможно, инициализировать его. Но на самом деле вам нужно сделать эту инициализацию только один раз, но вы проверяете ее каждый раз.

Итак, иногда я пишу метод, который выполняет инициализацию и затем заменяет себя версией, которая не включает код инициализации.

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

    def [](key)
      @backing_store[key]
    end

    @backing_store[key]
  end
end
Но, честно говоря, я не думаю, что это того стоит. На самом деле, мне стыдно признаться, что я никогда не проводил сравнительный анализ, чтобы увидеть, действительно ли это одно условие имеет какое-либо значение. (На современной реализации Ruby с агрессивно оптимизирующим JIT-компилятором, управляемым обратной связью профиля, вероятно, нет.)

Обратите внимание, что в зависимости от того, как вы Определите "самоизменяющийся код", это может быть или не быть тем, что вы хотите. Вы заменяете некоторую часть текущей исполняемой программы, так что ...

EDIT: теперь, когда я думаю об этом, эта оптимизация не имеет большого смысла. Дорогостоящая инициализация все равно выполняется только один раз. Единственное, чего избегает модификация, - это условности. Было бы лучше взять пример, где чек сам по себе стоит дорого, но я не могу придумать один.

Тем не менее, я подумал о классном примере самоизменяющегося кода: Maxine JVM. Maxine-это исследовательская виртуальная машина (технически она не может называться "JVM", потому что ее разработчики не запускают тесты совместимости), написанная полностью на Java. Теперь, есть много JVMs, написанных в себе, но Максин-единственная, которую я знаю, которая также работает в себе. Это чрезвычайно мощное средство. Например, JIT-компилятор может JIT-компилировать себя в адаптировать его к типу кода он JIT-компиляцию.

Очень похожая вещь происходит в Klein VM, которая является виртуальной машиной для языка самопрограммирования.

В обоих случаях виртуальная машина может оптимизировать и перекомпилироватьсаму себя во время выполнения.

Это можно сделать на языке Maple (язык компьютерной алгебры). В отличие от многих ответов выше, которые используют скомпилированные языки, которые позволяют только создавать и связывать в Новый код во время выполнения, здесь вы можете честно модифицировать код текущей программы. (Ruby и Lisp, как указывают другие респонденты, также позволяют вам это делать; вероятно, Smalltalk тоже).

На самом деле, раньше в Maple было стандартным, что большинство библиотечных функций были небольшими заглушками, которые загружались их "реальное" я с диска по первому вызову, а затем самоизменяется до загруженной версии. Это уже не так, поскольку загрузка библиотеки была виртуализирована.

Как указывали другие: для этого вам нужен интерпретируемый язык с мощными средствами отражения и овеществления.

Я написал автоматический нормализатор / упрощатель для кода Maple, который я начал запускать на всей библиотеке (включая саму библиотеку); и потому, что я не был слишком осторожен во всех моих код, нормализатор изменил сам себя. Я также написалчастичный оценщик (недавно принятый SCP) под названиемMapleMIX - доступный на sourceforge - но не смог полностью применить его к себе (это не было целью дизайна).

Вы смотрели на Java ? Java 6 имеет API компилятора , поэтому вы можете написать код и скомпилировать его в виртуальной машине Java.

В Lua можно "зацепить" существующий код, что позволяет присоединять произвольный код к вызовам функций. Это звучит примерно так:

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

Вы также можете просто перепахать функции, что в некотором роде дает вам самоизменяющийся код.