Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

使用编译器解决代码问题的出现

Posted on 2023-01-28

我从未尝试过代码的出现,但我的朋友向我展示了一个他认为我会感兴趣的老问题。这是一个有趣且可能出乎意料的解决方法。

该问题提供了一个用汇编语言编写的小程序,并询问:该程序的什么输入会产生特定的输出?语言非常简单(例如,甚至没有“添加”原语),程序的作用不是很明显,而且特定的代码片段有一些棘手的控制流,跳转相互交叉。

你可以研究代码来理解它,或者让一个快速运行者来暴力破解它,这是合理的,但这是我解决它的方法:让编译器优化代码(从程序集中找到结构),然后反编译器从该输出中恢复人类可读的高级结构,最终将程序集转换成更容易理解的东西。

输入程序是 30 行,从这个开始。该语言有一些修改内容的指令和一些相对跳转:

 cpy ad cpy 4 c cpy 633 b inc d dec b jnz b -2 [...]

我们可以通过使用 goto 进行跳转,将其转换为一个小的等效 C 代码片段。只是为了好玩,这里有一个 awk 程序可以做到这一点(尽管它也只是一个稍长的 Python 等程序)。 (编辑:写完这篇文章后,我发现reddit 上有人有一个惊人相似的 awk 程序,哈! )

 { printf "L" NR ": " } /cpy/ { print $3 "=" $2 ";" } /inc/ { print $2 "++;" } /dec/ { print $2 "--;" } /jnz/ { print "if (" $2 "!=0) goto L" (NR+$3) ";" } /out/ { print "out(" $2 ");" }

根据上面的输入,这会产生如下输出:

 L1: d=a; L2: c=4; L3: b=633; L4: d++; L5: b--; L6: if (b!=0) goto L4;

接下来,我们将该片段粘贴到一个.c文件中,如下所示:

 void run(int a) { // The other registers as used by the input language: int b = 0, c = 0, d = 0; // ...and then the generated code from above: L1: d=a; L2: c=4; // ... }

而且,对于核心技巧,我们使用 C 优化器对其进行编译。重要的是,C 优化器知道寻找循环之类的结构,并用执行相同操作的更简单的代码替换它们。

例如,如果你只看我上面粘贴的小片段,你可以认识到 L4-L6 有效地将b添加到d ,编译器也可以解决这个问题。

 $ cc -O2 -o cpy cpy.c

最后,我们将此输出加载到Ghidra中,它不仅会向我们展示程序集,还会尝试进一步推断结构以将其反编译为更高级别的 C 代码。

它会生成一个以以下方式打开的片段:

 param_1 = param_1 + 0x9e4; iVar2 = param_1; do { ...

一方面,这已经非常简洁了——编译器设法弄清楚初始代码块(涉及输入中的常量 633)实际上只是添加 0x9e4!但另一方面,它仍然不明显,部分原因是没有变量名。

所以接下来我们转向 ChatGPT。提示:“你能重写这段代码以使用更好的变量名吗:”加上代码。它产生(免责声明:我重新运行它以获得更好的这篇文章的输出):

 void run(int inputNumber) { int output; int currentNumber; currentNumber = inputNumber + 0x9e4; do { while (currentNumber == 0) { out(0); currentNumber = inputNumber; } int iteration = 0; do { if (currentNumber == 1) { output = 1; goto endLoop; } iteration++; currentNumber -= 2; } while (currentNumber != 0); output = 0; endLoop: out(output); currentNumber = inputNumber; if (iteration != 0) { currentNumber = iteration; } } while( true ); }

这段代码还是需要思考才能看懂。中间的 do-while 循环每次从currentNumber中减去 2 时都会在iteration中加一,您必须意识到这是除以二。但是从这里可以看出,这个程序将 0x9e4 添加到输入中,然后将其打印为二进制文件,这并不是一个巨大的飞跃。从那里开始,解决原始问题是一个相对较小的步骤。

实际上,我认为这不是我实际用来解决这个问题的方法。但由于我最近一直在关注反汇编,所以这些工具是最重要的,我认为从一个有趣的角度来研究它。

原文: https://neugierig.org/software/blog/2023/01/compiling-advent.html

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme