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

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

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

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

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

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

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下观察汇编代码》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Head First HTML5 Programming

Head First HTML5 Programming

Eric Freeman、Elisabeth Robson / O'Reilly Media / 2011-10-18 / USD 49.99

What can HTML5 do for you? If you're a web developer looking to use this new version of HTML, you might be wondering how much has really changed. Head First HTML5 Programming introduces the key featur......一起来看看 《Head First HTML5 Programming》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具