解开汇编语言意粉代码

时间:2009-06-11 20:48:58

标签: assembly coding-style embedded 8051

我继承了用8051汇编语言编写的10K行程序,需要进行一些更改。不幸的是,它是用最好的意大利面条代码传统写成的。程序 - 作为单个文件编写 - 是CALL和LJMP语句的迷宫(总共约1200个),子程序具有多个入口和/或出口点,如果它们可以被识别为子程序的话。所有变量都是全局的。有评论;有些是正确的。没有现有的测试,也没有重构预算。

应用程序的一些背景知识:该代码控制当前在国际上部署的自动售货应用程序中的通信中心。它同时处理两个串行流(在单独的通信处理器的帮助下),并且可以与最多四个不同的物理设备通信,每个物理设备来自不同的供应商。其中一个设备的制造商最近做了一个改变(“是的,我们做了一个改变,但软件完全相同!”)导致一些系统配置不再起作用,并且不想改变它(无论它是什么他们没有改变。)

该计划最初由另一家公司编写,转让给我的客户,然后由另一位顾问在九年前修改。原始公司和顾问都不是资源。

基于对其中一条串行总线上的流量的分析,我想出了一个看似有效的黑客攻击,但它很难看并且没有解决根本原因。如果我对该计划有更好的理解,我相信我可以解决实际问题。在代码被冻结之前我还有一周时间来支持月末发货日期。

原始问题:我需要很好地理解该程序,以便在不破坏的情况下进行更改。有没有人开发过处理这种混乱的技术?

我在这里看到一些很棒的建议,但受到时间的限制。但是,我将来可能有另一个机会去寻求一些更复杂的行动方案。

11 个答案:

答案 0 :(得分:17)

答案 1 :(得分:7)

我担心这种问题没有灵丹妙药。我发现唯一的解决方案是打印出ASM文件然后安静地去模拟在你脑海中逐行运行程序(同时在记事本上写入寄存器和内存位置的内容)。过了一段时间,你发现这不会像你期望的那样长。 准备好花很多时间做这个并喝加仑咖啡。过了一会儿,你将了解它在做什么,你可以考虑改变。

8051是否有任何未使用的IO端口?如果确实如此,并且在调用某些例程时无法解决问题,则添加代码以将这些备用端口发送到高或低。然后 当程序运行时,用示波器观察这些端口。

祝你好运

答案 2 :(得分:6)

我知道这听起来很疯狂......但我失业了(我选择了错误的时间告诉大多数伙伴下地狱)并且有空闲时间。我愿意看看它。我曾经为苹果[和原版PC]编写程序集。如果我可以在模拟器上玩你的代码几个小时,我可以给你一个想法,如果我有机会为你记录它(没有运行我的计划外假期)。由于我对8051一无所知这对像我这样的人来说可能是不可能的,但模拟器看起来很有希望。我不想要任何钱来做这件事。它足以让我们接触8051嵌入式开发。我告诉过你这听起来很疯狂。

答案 3 :(得分:4)

认真寻找另一份工作!如果没有“使用遗留代码有效地工作”这本书可能会有所帮助 - 尽管我认为它将遗留代码称为没有单元测试的代码。

答案 4 :(得分:4)

我做过几次这样的事情。一些建议:

  • 首先回顾原理图, 这应该有助于你理解什么 端口和引脚您想要的更改 影响。
  • 使用grep查找所有来电, 分支,跳跃和回报。这个可以 帮助理解流程并识别 代码块。
  • 查看重置向量和 中断表来识别 主线。
  • 使用grep创建交叉引用 适用于所有代码标签和数据 引用(如果你的汇编程序 工具不能为你做这个。)。

请记住Hofstadter定律: 即使考虑到霍夫施塔特定律,它也总是比你预期的要长。

祝你好运。

答案 5 :(得分:3)

您对此代码运行的硬件平台有多了解?

  • 是否已进入断电模式(Pcon = 2)以节省电量 如果是这样,它是如何被唤醒的。 (复位或硬件中断)

  • 在进行串行通信之前,您是否必须等待振荡器稳定后才能进行串口通信

  • 是否已进入睡眠模式(Pcon = 1)

现场是否有不同版本的硬件?

确保您拥有要测试的所有不同硬件版本。

不要在模拟器上浪费你的时间 - 这很难处理,你必须对硬件做出很多假设。给自己一个In Circuit Emulator (ICE)并在硬件上运行。

该软件是用汇编语言编写的,原因是您需要找出原因。 即 - 内存限制 - 速度限制

这个代码可能有一个混乱的原因

查看以下链接文件:

XDATA SPACE,IDATA SPACE和CODE SPACE:

如果没有免费代码空间或Xdata或Idata?

原作者可能已将其优化以适应可用的存储空间。

如果是这种情况,您需要与原始开发人员交谈以了解他的所作所为

答案 6 :(得分:1)

您不需要特殊的预算来进行重构和测试 - 它们可以节省您的资金并让您更快地工作 - 实现目标。这是您应该使用的技术来添加对旧的,继承的代码的更改,因为这是最简单的方法,没有“没有破坏”。

大多数时候,我认为有一个权衡,你可以获得更多的质量来换取花费更多的时间,但是对于你不熟悉的遗留代码,我认为进行测试更快 - 你必须运行发货之前的代码,对吗?

答案 7 :(得分:1)

这是为数不多的几次,我建议你将软技能用于工作,并向你的PM /经理/ CXO提供重写后的理由,并节省时间/成本。承诺

答案 8 :(得分:1)

把它切成碎片。

答案 9 :(得分:1)

我和8052软件有一些非常类似的问题。所以公司继承了这样一个野兽,代码ROM满(64K字节),大约1.5兆的装配意大利面模块和两个3000行PL / M模块组成了这个编码怪物。该软件的原始开发人员已经死了(这并不意味着没有人,但实际上没有人能够理解它),编译这些软件的编译器来自运行在MDS-70仿真器上的80年代中期,以及几个关键的模块处于这些编译器的极限。就像添加一个全局符号一样,链接器会崩溃。再向ASM文件添加一个符号,编译器就会崩溃。

那么如何才能开始削减它?

首先你需要工具。例如Notepad ++是一件非常好的事情,因为它可以用于一次跨多个文件进行交叉搜索,非常适合查找哪些模块引用全局符号。这可能是最关键的因素。

如果可能,请获取您可以在该软件上找到的任何文件。这些野兽要解决的最直接的问题是要了解它们是如何粗略组成的,它们的架构是什么。这通常不包含在软件本身中,即使它被正确评论也没有。

要自行获取架构,首先您可以尝试构建调用图。它比数据流图更简单,因为通常有较少的跨文件调用和跳跃比全局变量。对于此调用图,只考虑全局符号,假设源文件应该是模块(不一定是真的,但通常应该是这样)。

要执行此操作,请使用您的工具进行跨文件搜索,创建一个大型列表(例如在OpenOffice Calc中),您可以在其中收集在哪个文件中定义的符号,以及哪些文件引用此符号来调用它。

然后从绘图仪中偷取一些大的(!)纸张,并开始绘制草图。如果你非常精通某些图形软件,你可以使用它,但除非是这样,否则它更有可能阻止你。因此,绘制一个调用图表,显示哪个文件已调用其他文件(不显示符号本身,有50个左右的文件,您将无法管理它)。

最有可能的结果是意大利面。我们的目标是理顺它,使其成为一个带有根的分层树(它将是包含程序入口点的文件),没有循环。你可以在这个过程中吞下几张纸,反复拉直野兽。您可能还会发现某些文件是如此混杂,以至于没有循环就无法表示它们。在这种情况下,很可能单个“模块”以某种方式分成两个文件,或者更多的概念模块被纠缠在一起。返回到您的呼叫列表,并对符号进行分组,以便以较小的独立单位切割有问题的文件(您还需要检查文件本身是否也可以在此处进行本地跳转,以查看您的假定切割是否可行)。

除非你已经为了自己的利益而在其他地方工作,否则你将获得一个带有概念模块的分层调用图。由此可以推断出软件的有意架构并进一步发挥作用。

下一个目标是架构。通过先前制作的地图,您需要浏览软件,找出它的线程(中断和主程序任务),以及每个模块/源文件的粗略目的。如何做到这一点以及你得到的内容更多地取决于应用程序域。

当这两个完成后,“休息”相当简单。通过这些,你应该基本知道事物的每个部分应该做什么,因此你知道当你开始处理源文件时你可能会处理什么。重要的是,无论何时你在源代码中发现“鱼腥”的东西,程序似乎都会做一些无关紧要的事情,回到你的架构和调用图形,并在必要时进行修正。

其他人提到的方法很适用。我刚刚概述了这些内容,以便对在真正可怕的情况下可以做些什么有所了解。我希望我当时只有10K行代码来处理......

答案 10 :(得分:0)

我会说IanW的答案(只是将其打印出来并保持跟踪)可能是最好的。也就是说,我有一点想法:

尝试通过可以重建C代码的解析器运行代码(可能是二进制代码)(如果可以找到8051的代码)。也许它会识别一些你不能(轻松)的例程。

也许它会有所帮助。