gpt4 book ai didi

assembly - 解开汇编语言意粉代码

转载 作者:行者123 更新时间:2023-12-02 21:27:06 26 4
gpt4 key购买 nike

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

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

该程序最初由另一家公司编写,然后转移给我的客户,然后在九年前由另一位顾问进行了修改。既没有原始公司,也没有顾问作为资源。

根据对其中一条串行总线上的通信量的分析,我提出了一种破解方法,该方法看起来很有效,但它很丑陋,无法解决根本原因。如果我对程序有更好的了解,我相信我可以解决实际的问题。在冻结代码之前,我还有大约一周的时间来支持月底发货日期。

最初的问题:我需要对程序有足够的了解,以进行更改而不会造成损坏。有没有人开发出处理此类混乱的技术?

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

最佳答案

首先,我将尝试与那些最初开发该代码或至少在我之前维护过代码的人保持联系,希望能获得足够的信息以大致上了解该代码,以便您可以开始在其中添加有用的注释。它。

也许您甚至可以让某人描述代码中最重要的API(包括其签名,返回值和用途)。如果全局状态是通过函数修改的,则还应该使其明确。同样,开始区分功能和过程以及输入/输出寄存器。

您应该向您的雇主清楚地表明,需要这些信息,如果他们不相信您,让他们在您描述应该做的事情和必须做的事情的同时坐在本代码前面与您坐下来它(逆向工程)。在这种情况下,拥有具有计算和编程背景的雇主实际上会有所帮助!

如果您的雇主没有这样的技术背景,请他带另一个程序员/同事向他解释您的步骤,这样做实际上会告诉他您对此很认真和诚实,因为这是一个真实的问题-不仅仅是从您的角度(确保有了解此“项目”的同事)。

如果可行且可行的话,我也要非常清楚地指出,与前开发人员/维护人员签约(或至少联系)(如果他们不再为您的公司工作,则)以帮助记录此代码将是一个先决条件。 -在短时间内切实改进代码并确保将来可以更轻松地维护代码的必要条件。

强调整个情况是由于先前的软件开发过程中的缺陷,这些步骤将有助于改进代码库。因此,当前形式的代码库是一个日益严重的问题,现在为解决此问题所做的一切都是对未来的投资。

这本身对帮助他们评估和了解您的情况也很重要:要做您现在应该做的事情并非易事,他们应该知道这一点-如果只是为了直指他们的期望(例如,关于截止日期和复杂性)任务)。

另外,个人而言,我将开始为我已经足够了解的那些部分添加单元测试,以便我可以慢慢地开始重构/重写一些代码。

换句话说,好的文档和源代码注释是一回事,而拥有全面的测试套件则是另一回事,在没有任何成熟的测试关键功能的方法的情况下,没有人可以期望修改任何不熟悉的代码库。

假定代码为10K,我还将考虑将子例程分解为单独的文件,以使组件更易于识别,最好使用访问包装器而不是全局变量和直观的文件名。

此外,我将研究通过降低复杂性来进一步提高源代码可读性的步骤,使具有多个入口点的子例程(甚至可能具有不同的参数签名?)看起来像是不必要地混淆代码的可靠方法。

同样,巨大的子例程也可以重构为较小的子例程,以帮助提高可读性。

因此,我要做的第一件事就是确定使代码库变得非常复杂的那些事情,然后重新加工这些部分,例如,通过将具有多个入口点的巨大子例程拆分为不同的子例程彼此调用的子例程。
如果由于性能原因或调用开销而无法完成此操作,请改用宏。

另外,如果这是一个可行的选择,我会考虑使用更高级的语言来逐步重写部分代码,或者使用C的子集,或者至少通过大量使用汇编宏来帮助标准化代码。基础,也有助于定位潜在的错误。

如果使用C进行增量重写是可行的选择,那么一种可能的入门方式是将所有明显的函数转换为C函数,这些函数的主体是-从头开始-从汇编文件复制/粘贴的,因此最终得到C具有许多内联汇编的功能。

就我个人而言,我还将尝试在simulator/emulator中运行代码以轻松地逐步遍历代码,并希望开始了解最重要的构造块(在检查寄存器和堆栈使用情况的同时),应该使用具有内置调试器的良好的8051模拟器提供给您,如果您真的必须自己做的话。

这也将帮助您提出初始化序列和主循环结构以及一个调用图。

也许,您甚至可以找到一个很好的开源80851模拟器,可以轻松对其进行修改以自动提供完整的调用图,只需进行快速搜索,我就找到了gsim51,但是显然还有其他几种选择,还有各种专有的选择。

如果您遇到这种情况,我什至会考虑外包修改我的工具以简化使用此源代码的工作,即许多sourceforge项目接受捐款,也许您可​​以说服您的雇主赞助这样的修改。

如果不是经济上的话,也许是通过您提供相应的补丁程序呢?

如果您已经在使用专有产品,您甚至可以与该软件的制造商联系并详细说明您的要求,并询问他们是否愿意以这种方式改进该产品,或者是否至少可以公开一个界面以允许客户进行这样的自定义(某种形式的内部API甚至简单的粘合脚本)。

如果他们没有反应,请表明您的雇主已经考虑使用某种产品已有一段时间了,并且您是唯一坚持使用该特定产品的人... ;-)

如果软件需要特定的I / O硬件和外围设备,则您甚至可能希望研究编写相应的硬件仿真循环以在仿真器中运行该软件。

最终,我知道一个事实,那就是,无论我能喝多少加仑咖啡,我个人都会更喜欢自定义其他软件的过程来帮助我理解这样的意大利面条式代码怪兽,而不是手动单步执行代码并自己玩模拟器得到。

从一个开源8051仿真器中获得一个可用的调用图最多要花一个周末的时间(最多一次),因为这主要是指查找CALL操作码并记录其地址(位置和目标),以便将所有内容都丢弃到文件以供以后检查。

实际上,可以使用仿真器的内部结构也是进一步检查代码的一种好方法,例如,以便找到操作码的重复模式(例如20-50 +),这可能是独立函数/过程的因素,实际上帮助进一步减少代码库的大小和复杂性。

下一步可能是检查堆栈并注册使用情况。并确定所用功能参数的类型/大小及其值范围-这样您就可以构思相应的单元测试。

与手动完成所有这些工作相比,使用点/ graphviz之类的工具来可视化初始化序列和主循环本身的结构将是一种纯粹的乐趣。

而且,从长远来看,您最终将获得有用的数据和文档,它们可以作为更好的文档的基础。

关于assembly - 解开汇编语言意粉代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/983574/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com