怎么反编译 Emacs 字节码 到 源代码 ?

发现 elpa 的一个 package,其 .elc 的行为和对应 .el 不一致。

我怀疑是作者 release 时候的疏漏。

现在想反编译 .elc,看看到底哪里和 .el不同,有没有什么好的反编译工具?

这里有,可是对开启 lexical-binding 的字节码不怎么样。函数名不一定会被保留,注释肯定没有,反编译后得到的的控制结构也会与源代码不同,所以不适合和源代码对比。

Emacs 没提供反编译到源代码的方法,只有 disassemble

elpa 的包是统一(:link:elpa-packages)构建的,不存在「作者 release」的问题。你可以自己编译一份 .elc,跟下载的 .elc 比较看看是否确实有什么不同。

也有些 bug 很隐蔽,设计时觉察不到,编译成 .elc 才会爆发。

1 个赞

要使用这个工具,需要先把elc转成lap,我使用它提供的dedis.el里的disassemble-file发现不行,不是对所有elc都可以转。

今天重新看了一下这个老问题,发现原来是 .elc 编译版本不一致导致的,记录一下:

假设当前 Emacs 版本是 29.3,你有一个两个 .elc,其中:

a.elc 使用 Emacs 29.3 编译,

b.elc 使用 Emacs 27.2 编译。

大部分情况下,这两个 .elc 看似可以正常交互,但并不尽然。有时候,为了图方便,会拷贝之前编译好的 .elc,这在升级 Emacs 版本的时候就会有问题(猜测是 .elc 格式有 breaking change)。所以一定要保持所有的 .elc 版本和当前 Emacs 版本一致。

神奇的是,在 Emacs 29.3 下,使用 Emacs 27.2 编译的 a.elcb.elc 也可以正常运行。

开发原则上 Emacs byte code 解释器是不会 breaking change 的,但是架不住后来一些 macro,和很多 eval-when-compile 在不同版本会改变定义,尤其是 compat 包直接把 byte code 兼容的意义破坏了,elpa 没法在不同大版本 Emacs 里共用了

嗯,已经转到 straight.el (cabal 既视感 :smiling_face_with_three_hearts:)。

P.S. Emacs 内置的 package.el 其实不是很好,之前为了 producibility 备份了整个 elpa 目录。

我电脑上一直都有多个版本的 Emacs,包安装到 ~/.emacs.d/<major-version>.<minor-version>/elpa 隔离开,并保持最后两个大版本是可用的,其中:

  • 正式版只有遇到问题时才更新与之相关的包,相当于半冻结状态;
  • 开发版偶尔会批量更新包,并在日常使用中发现和解决问题。

如此直到开发版正式发布,然后我又有了新的两个大版本。