UEFI开发探索26 – UEFI下观察汇编代码

栏目: 编程语言 · 发布时间: 5年前

内容简介:上一篇博客中遇到了奇怪的问题,明明没有使用的函数,在编译的时候竟然报错使用了,并导致无法链接。这让我意识到,还是得建立完整的调试环境,帮助学习开发。一直以来,我调试代码的方法大概有三种:

上一篇博客中遇到了奇怪的问题,明明没有使用的函数,在编译的时候竟然报错使用了,并导致无法链接。

这让我意识到,还是得建立完整的调试环境,帮助学习开发。

一直以来,我调试代码的方法大概有三种:

1) 打印输出。这是最常用的,也最方便的。不管是通过屏幕打印输出,还是通过串口、USB口等硬件设备打印,都能知道很多程序的内部信息;

2) 观察汇编代码。主要用来准确的知道程序内部运行状况、库的链接、各种变量等,配合map、lst等文件综合分析。用来解决一些疑难杂症;

3) 断点调试。这是最好的调试方法,不过视开发的产品,有时候很难实现。如果是调试Windows driver&app,VS系列产品以及Windbg能发挥很大作用;Linux下用gdb,也很好;调试DOS和Legacy bios时,我用debug.exe较多。开发固件代码时就比较麻烦了,要么用软件模拟器调试,要么用JTAG调试。

帮朋友打个小广告,建议读一读张银奎的《软件调试》, 目前他在筹划第二版四卷本的计划。第二版的第一卷已经出版,值得好好读一读。承张老师惠赠一本,正在拜读:

UEFI开发探索26 – UEFI下观察汇编代码
图1 软件调试第二版 卷1

UEFI下开发APP和Driver,以及我目前的目标Option ROM,在实际硬件中是法使用断点调试的,至少目前我没有找到方法。实在很怀念用debug.exe调试DOS程序的日子,工具虽然简单,该有的功能都有,UEFI下怎么就没提供这种类似的 工具 呢?

我准备用几篇博客,谈一谈如何建立第二种观察汇编代码和第三种断点调试的方法。当然,断点调试只能在TianoCore(模拟环境)配合下工作,实际硬件就无能为力了。这就足够了,能大大加快各种代码的开发。

这篇介绍如何去观察汇编代码。

1 回顾问题

上一篇One More Thing的环节,我遇到了很奇怪的问题,再把图贴一下:

UEFI开发探索26 – UEFI下观察汇编代码
图2 编译错误

在代码中加了红线所标的一行代码,就出现了右边的编译错误提示。这行代码怎么看也不像会调用memset。

我的第一个反应就是把这个C文件的汇编代码抓出来看看,到底是怎么编译的。不过当时还没有找到方法反汇编,生成的中间文件中有obj文件,使用dumpbin /DISASM尝试一下,提示如下:

UEFI开发探索26 – UEFI下观察汇编代码
图2 dumpbin尝试反汇编obj文件

看来还是必须从编译选项下手,幸好编译器是VS2015,微软的资料比较全,可以从这儿着手。

2 如何打开汇编清单开关

我是使用VS2015+UDK2018进行开发的,编译用的工具链是VS2015x86。平常编译的时候,是直接使用build进行编译。

这是UDK2018中准备好的批处理工具,所有配置的文件可以再Conf文件夹下找到,它定义了很多宏,以支持在Windows和 Linux 下编译。

我把build的参数打印出来,仔细研究了一下。

比较有用的是-a、-p、-m、-t几个常用的参数,分别指定目标架构、编译的Package、编译的模块以及工具链指定。其他参数中也没有与汇编清单相关的。

看来还得从编译工具本身入手。我知道VS使用cl.exe、link、和nmake.exe进行编译,汇编清单的参数指定应该与cl.exe有关。 很快,就在微软提供的文档中找到了答案(cl.exe的帮助文档)。

UEFI开发探索26 – UEFI下观察汇编代码
图3 汇编清单开关

接下来的工作比较简单。

在UDK的Conf文件夹中,找到tools_def.txt文件,所有的工具链参数都在此配置。我在target.txt中设置的TARGET = DEBUG,TOOL_CHAIN_TAG = VS2015x86,在tool_def.txt中找到DEBUG_VS2015x86_IA32_CC_FLAGS,在最后添加/FAs参数。

运行build -m _LuoApp/Luo2/Luo2.inf,编译。汇编文件就生成了,我的环境中生成的汇编代码都在C:\MyWorkspace\Build\AppPkg\DEBUG_VS2015x86\IA32\_LuoApp\Luo2\Luo2下。

3 寻找问题原因

打开问题文件Pictures.asm,找到使用了memset的地方:

UEFI开发探索26 – UEFI下观察汇编代码
图4 罪魁祸首找到了

让人困惑的是,并不是图2中语句bPixel=*tempFileImage++;调用了memset,而是图4中标红的这句话调用了。

我在调试的时候,将bPixel设为了0xC2。代码很好理解,将0xC2批量设置到目的地址中,所以memset是很好的选择。不过这造成了我的麻烦,我并没有引入Stdlib库,编译出错是必然。

Foxdisk开发中也遇到了类似的问题,必然32位的乘法(Foxdisk是在16位编译器上开发的),编译器会调用库函数来实现。不过Foxdisk是运行在无操作系统的环境下,运行的时候我到哪里去找这些库函数?我只能用汇编语言重写了32位的乘法以及其他四则运算。

问题找到,解决起来比较简单。把图4中红线部分的语句稍微修改一下,调用目前已包含库中的函数即可:

// while (–count >=0) *tempPcxImage++ = bPixel;

SetMem(tempPcxImage, count, bPixel);

tempPcxImage += count;

具体参照下百度云中提供的代码。

我一直很习惯通过汇编语言来找这些程序依赖问题的原因,今天终于可以在UEFI下使用这种方法了,对加快后面的开发非常有好处。

4 One More Thing

把工具链中用到的参数记录一下吧,方便后面使用(只针对Windows平台的工具链)。UEFI中的工具链截图:

UEFI开发探索26 – UEFI下观察汇编代码
图5 UEFI编译工具链

/nologo:取消显示启动版权标志

/arch:IA32:指定体系架构为IA32

/c:编译但不链接

/WX:将所有编译警告都视为错误

/GS-:缓冲区安全检查,打开磁开关,保证应用程序不出现安全漏洞

/W4:显示所有等级的警

/Gs32768:控制堆栈检查调用,启动堆栈探测前局部变量可以占用32768个字节

/D UNICODE:预处理符合定义,支持UNICODE字符

/O1b2:生成最小文件而优化代码,允许对标记为inline、__inline、_forceiline的内联展开

/GL:启用全程序优化

/FIAutoGen.h:预处理AutoGen.h文件

/EHs-c-:仅捕获同步C++结构化异常,并假定声明为extern “C”的函数从未引发异常

/GR-:启用运行时类型信息

/GF:消除重复的字符串

/Gy:启用函数级链接,允许编译器以打包函数的形式对各个函数进行打包

/Zi:生成完整的调试信息,包含在程序数据库PDB中,其中有供调试器使用的类型信息和符号化调试信息

/Gm:启用最小重新生成,确定是否重新编译包含已更改的源文件

/Gw:启用全程序全局数据优化

/FAs:生成带源文件的汇编清单文件

以上主要是cl.exe的参数,其他编译工具的参数就不列出来了。更多的参数可以参考这个网页: https://docs.microsoft.com/zh-cn/previous-versions/fwkeyyhe%28v%3dvs.120%29

1 total views, 1 views today


以上所述就是小编给大家介绍的《UEFI开发探索26 – UEFI下观察汇编代码》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Never Lost Again

Never Lost Again

[美] Bill Kilday / HarperBusiness / 2018-5-29 / USD 8.00

As enlightening as The Facebook Effect, Elon Musk, and Chaos Monkeys—the compelling, behind-the-scenes story of the creation of one of the most essential applications ever devised, and the rag-tag tea......一起来看看 《Never Lost Again》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具