35
  • 我最近在想写自修改程序,我觉得它可能是强大而有趣的。所以我目前正在寻找一种可以轻松修改程序自己代码的语言。
  • 我阅读了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();
4

14 回答 14

48

Malbolge将是一个很好的起点。每条指令都是自我修改的,玩起来很有趣(*)。

(*) 免责声明:实际上可能并不有趣。

于 2010-06-16T22:00:55.307 回答
23

我强烈推荐 Lisp。Lisp 数据可以作为代码读取和执行。Lisp 代码可以写成数据。

它被认为是规范的自修改语言之一。

示例列表(数据):

'(+ 1 2 3) 

或者,将数据调用为代码

(eval '(+ 1 2 3)) 

运行 + 函数。

您还可以即时进入并编辑列表的成员。

编辑:

我编写了一个程序来动态生成程序并动态评估它,然后向我报告它与基线相比的效果(div by 0 是通常的报告,哈哈)。

于 2010-06-16T22:28:01.947 回答
16

到目前为止,每个答案都是关于反射/运行时编译,但在您提到的评论中,您对实际的自修改代码感兴趣——在内存中修改自身的代码。

在 C#、Java 甚至(可移植的)C 中都无法做到这一点——也就是说,您无法使用这些语言修改加载的内存中二进制文件。

一般来说,做到这一点的唯一方法是使用汇编,并且它高度依赖于处理器。事实上,它也高度依赖于操作系统:为了防止多态病毒,大多数现代操作系统(包括 Windows XP+、Linux 和 BSD)都强制执行W^X,这意味着您必须在编写多态可执行文件时遇到一些麻烦。那些操作系统,对于那些完全允许它的操作系统。

在某些解释性语言中,程序可能会在运行时修改自己的源代码。不过,Perl、Python (参见此处和我所知道的每个 Javascript 实现都不允许这样做。

于 2010-06-16T22:51:52.307 回答
10

就个人而言,我觉得很奇怪你发现汇编比 C# 更容易处理。我发现您认为汇编没有那么强大更奇怪:您无法获得比原始机器语言更强大的功能。无论如何,对每个他/她自己。

C# 有很好的反射服务,但如果你对此有反感。如果你真的对 C 或 C++ 感到满意,你总是可以编写一个编写 C/C++ 的程序并将其发布给编译器。这只有在您的解决方案不需要快速的自重写周转时间(大约几十秒或更长时间)时才可行。

Javascript 和 Python 也都支持反射。如果您正在考虑学习一种新的、有趣的、功能强大但对技术要求不高的编程语言,我建议您使用 Python。

于 2010-06-16T22:06:49.267 回答
10

我可以推荐Python 吗,这是一种很好的高级动态语言,它包含丰富的自省功能(例如,使用compile,evalexec允许一种形式的自修改代码)。基于您的问题的一个非常简单的示例:

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仅在函数范围内进行了更改。

于 2010-06-16T22:16:39.667 回答
9

Common Lisp的设计考虑了这种事情。您也可以尝试Smalltalk,其中使用反射来修改正在运行的代码并不陌生。

在这两种语言中,您可能会替换整个函数或整个方法,而不是一行代码。Smalltalk 方法往往比 Lisp 函数更细粒度,因此这可能是一个很好的起点。

于 2010-06-16T22:40:22.523 回答
7

许多语言允许您在运行时评估代码。

  • 语言
  • Perl
  • Python
  • PHP
  • 红宝石
  • Groovy(通过 GroovyShell)
于 2010-06-16T22:28:01.027 回答
4

在您在运行时编译和执行代码的高级语言中,它并不是真正的自修改代码,而是动态类加载。使用继承原则,您可以替换类 Factory 并在运行时更改应用程序行为。

只有在汇编语言中,你才真正拥有真正的自我修改,通过直接写入代码段。但它的实际用途很少。如果你喜欢挑战,写一个自加密的,也许是多态的病毒。这应该很有趣。

于 2010-06-16T22:47:17.070 回答
3

我有时,虽然很少在 Ruby 中进行自我修改代码。

有时您有一种方法,您并不真正知道您正在使用的数据(例如一些惰性缓存)是否已正确初始化。因此,您必须在方法开始时检查数据是否已正确初始化,然后可能会对其进行初始化。但是你真的只需要做一次初始化,但你每次都检查它。

因此,有时我会编写一个方法来进行初始化,然后将其自身替换为不包含初始化代码的版本。

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

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

    @backing_store[key]
  end
end

但老实说,我认为这不值得。事实上,我很尴尬地承认,我从未真正进行过基准测试,看看那个条件是否真的任何区别。(在具有积极优化配置文件反馈驱动的 JIT 编译器的现代 Ruby 实现中,可能不会。)

请注意,根据您如何定义“自修改代码”,这可能是也可能不是您想要的。您正在替换当前正在执行的程序 的某些部分,所以……</p>

编辑:现在我想起来了,这种优化没有多大意义。无论如何,昂贵的初始化只执行一次。修改避免的唯一事情是条件。最好举一个支票本身很贵的例子,但我想不出一个。

但是,我想到了一个很酷的自修改代码示例:Maxine JVM。Maxine 是一个完全用 Java 编写的研究 VM(从技术上讲,实际上不允许将其称为“JVM”,因为它的开发人员不运行兼容性测试套件)。现在,有很多 JVM 是自己编写的,但 Maxine 是我所知道的唯一一个也可以自己运行的 JVM 。这是非常强大的。例如,JIT 编译器可以对其自身进行 JIT 编译,以使其适应其正在 JIT 编译的代码类型。

Klein VM中也发生了非常相似的事情,它是自编程语言的 VM。

在这两种情况下,VM 都可以在运行时优化和重新编译自己

于 2010-06-16T23:30:30.033 回答
2

我编写了 Python 类 Code,它使您能够向对象添加和删除新的代码行,打印代码并执行它。类代码显示在最后。

示例:如果 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]
于 2013-12-22T20:31:17.823 回答
1

您可以在 Maple(计算机代数语言)中执行此操作。与上面那些使用编译语言的许多答案不同,这些语言只允许您在运行时创建和链接代码,在这里您可以诚实地修改当前正在运行的程序的代码。(正如其他回答者所指出的,Ruby 和 Lisp 也允许您这样做;可能 Smalltalk 也是如此)。

实际上,在 Maple 中过去的标准是大多数库函数都是小存根,它们会在第一次调用时从磁盘加载它们的“真实”自我,然后自我修改到加载的版本。这不再是这种情况,因为库加载已被虚拟化。

正如其他人所指出的:您需要一种具有强大反射和具体化功能的解释语言来实现这一目标。

我为 Maple 代码编写了一个自动规范化器/简化器,我继续在整个库(包括它自己)上运行它;而且因为我在所有代码中都不太小心,所以规范器确实修改了自己。我还编写了一个名为MapleMIX的Partial Evaluator(最近被 SCP 接受) ——可在 sourceforge 上获得——但不能完全将其应用于自身(这不是设计目标)。

于 2010-06-17T00:28:56.023 回答
0

你看过 Java 吗?Java 6 有一个编译器 API,因此您可以在 Java VM 中编写和编译代码。

于 2010-06-16T22:01:58.613 回答
0

Lua中,您可以“挂钩”现有代码,这允许您将任意代码附加到函数调用。它是这样的:

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

您也可以简单地遍历函数,这可以让您自行修改代码。

于 2010-06-19T02:19:01.140 回答
0

Dlang 的 LLVM 实现包含 @dynamicCompile 和 @dynamicCompileConst 函数属性,允许您在编译时根据本机主机的指令集进行编译,并通过重新编译在运行时更改编译时常量。

https://forum.dlang.org/thread/bskpxhrqyfkvaqzoospx@forum.dlang.org

于 2019-09-05T22:58:43.997 回答