作者:Dmitril 2004.9.15
如何使用LIB文件转储动态链接库
有时理解应用程序连接到什么系统API是必要的。其他场合需要找到一个按次序的输出函数。这个序数可以为动态连接传给RLibrary::Lookup(色彩序数)。
Petran
Symbian为探测Symbian的内容提供一些工具。 举例来说,对Symbian E32版本,petran.exe(和SDK包含在一起) 通常在造创建转换PE时使用。但是petran也能用来转储E32文件的内容。 举例来说:
petran HelloWorld.app
将会打印E32头文件的内容, 打印转储2进制代码并打印输入功能列表, 举例来说:
............
从APPARC[10003a3d].DLL输入
3
6
27
71
............
从 EUSER[100039e5].DLL输入
3
809
828
858
1504
1582
1611
............
为较多的信息观察Symbian可执行文件格式。对petran C++作为Symbian OS C++ Build工具的一部分是可用的。你可以找一个下载 Symbian OS工具的连接。 petran的大限制是不能为输入函数打印名字,这是因为这些名字不在E32文件中出现。
DepTool
从相同的下载连接可以下到的另一个被称为 " DepTool"是可用的 。 它同样被讨论。不像 petran ,DepTool在Perl被写。大概可能如petran一样认为:检查E32 文件格式并打印文件输入和输出。(然而, 它不打印头文件和二进转储) DepTool有一种重要的额外好处: 它会尝试查找位LIB文件通讯到给定的E32 文件并且从中得出输出文件名。 这一个功能对DLL写入者是非常有价值的,但是它不会为 HelloWorld工作,因为它不是一个DLL并且也没有LIB文件。通过DepTool的DLL我没有找到得到EUSER.DLL输出名。写我自己的Perl工程,可能使用DepDb.pm(DepTool的启动),但下面有个更加简单的解释。
Binutils
为了计算出从EUSER.DLL输出口#3为什么(为例)我们需要检查 euser.lib入口库。对于Windows模拟器(在 Epoc32\ release\win\udeb 中) 这个任务是很容易的: 只需运行
dumpbin /exports %EPOCROOT%Epoc32\release\wins\udeb\euser.lib
看所有的输出。但是顺序依Symbian的版本而不同。因为它被建立使用角马工具,不幸地,dumpbin不能在Symbian的Epoc32\ release\armi\urel下使用,因为它是使用GNU工具创建的。我们需要使用在Symbian SDK中Epoc32\ gcc\bin下的二进制程式(binutils)。这里有很多对lib工作的效用。举例来说," ar"允许在档案库中列举目标文件就如提取文件一样。举例来说:
ar- t 的 %EPOCROOT% Epoc32\release\armi\urel\ euser.lib
打印目标文件列表:
............
ds00003.o
ds00001.o
ds00002.o
ds01621.o
............
一个比较详细的信息是由" nm" 提供, 举例来说:
nm --demangle %EPOCROOT%Epoc32\release\armi\urel\euser.lib
prints:
............
ds00003.o:
00000000 b .bss
00000000 d .data
00000000 ? .idata$4
00000000 ? .idata$5
00000000 ? .idata$6
00000000 ? .idata$7
00000000 t .text
00000000 ? CBase::__imp_newL(unsigned int)
U _head____EPOC32_RELEASE_ARMI_UREL_EUSER_LIB
00000000 ? _imp__newL__5CBaseUi
00000000 T CBase::newL(unsigned int)
.............
事实上,我们已经发现我们的问题答案。它出现在6.1版的"在LIB中匹配序数的输出口文件名"。这引证来自上面被提到的文件DepDb.pm 作为以上提及部分的注释。如果这是真实的, 那么ds00003.o 符合#3 ,并且它的名字是 "CBase::newL(unsigned int)"。这是从EUSER中通过HelloWorld的功能。(见上面)
DepDb.pm为提取序数提供了两个方法: ReadLib和ReadLibExtreme。 ReadLib调用 "nm —demangle lib-name" 并且依赖与文件名与序数匹配。ReadLibExtreme完成一个比较彻底的作业而且从输入口中读取序数。首先它使用"ar -p lib-file obj-file"从 LIB 中提取目标文件,然后调用"objdump -s -j .idata\$5 obj-file-name" 转储包含序数的.idata\$5。
在我发现DepTool 和 DepDb.pm 之前我发展了自己的输出转储。我的工具叫 "objdump —disassemble-all —demangle lib-file" 在存档中转储所有的目标文件, 然后为".text" 解析(有输出的功能如标示) 和".idata$5",包含了序数。 这是相同的转储"ds00003.o"对象,它包含了 CBase::newL:(unsigned int):
C:/DOCUME~1/INBUIL~1/LOCALS~1/Temp/d1000s_00003.o: 文件格式 epoc-pe-arm-little
片段的分解 .text:
00000000 <CBase::newL(unsigned int)>:
0: e59fc004 ldr r12, [pc, #4] ; c <CBase::newL(unsigned int)+0xc>
4: e59cc000 ldr r12, [r12]
8: e12fff1c bx r12
c: 00000000 andeq r0, r0, r0
片段的分解 .data:
片段的分解 .idata$7:
00000000 <.idata$7>:
0: 00000000 andeq r0, r0, r0
片段的分解 .idata$5:
00000000 <CBase::__imp_newL(unsigned int)>:
0: 80000003 andhi r0, r0, r3
片段的分解 .idata$4:
00000000 <.idata$4>:
0: 80000003 andhi r0, r0, r3
片段的分解.idata$6:
更多输入平台的信息请查找".idata$5"在 microsoft.com ".
这是我的 Perl源代码:
文件 1: epoc_exports.pl:
#目的: 读来来自标准的输入EPOC入口库的转储,
# 提取并转储序数: 成对的输出名字功能。
# 转储必须由"objdump --disassemble-all --demangle library_path.lib"创建
my $InSection = "";
my $Name = "";
while (<STDIN>) {
#print("$_\n");
if(($F1) = (m/Disassembly of section (\S+)\:/)) {
#Example: Disassembly of section .text:
#Example: Disassembly of section .idata$5:
$InSection = $F1;
}
elsif(($InSection eq ".text") && (($F1) = (m/00000000 \<(.+)\>\:/))) {
#Example: 00000000 <CBase::newL(unsigned int)>:
$Name = $F1;
}
elsif(($InSection eq '.idata$5') && (($F1) = (m/^\s+0\:\s+(\S+)/))) {
#Example: 0: 80000003 andhi r0, r0, r3
$Ordinal = hex($F1) & 0x7fffffff;
printf("%d(0x%x):%s\n", $Ordinal, $Ordinal, $Name);
}
}
文件 2: epoc_dump_and_export.pl:
#目的:在给定的目录中列举所有的 EPOC.lib文件并转储序数:成对命名#用法: perl epoc_dump_and_export.pl目录#路径上需要objdump的EPOC版本,File::Basename Perl module 和在相同路径中epoc_exports.pl作为当前文件。
use File::Basename;
$dir=shift(@ARGV);
$our_dir=dirname($0);
opendir(DIR, $dir) || die "can't opendir $dir: $!"; while($file = readdir(DIR)) {
if(index($file,".lib") > 0) {
$path = "$dir/$file";
print("$path\n");
system("objdump --disassemble-all --demangle $path | perl $our_dir/epoc_exports.pl > $file.exp");
}
}
closedir DIR;
用法: 转储一个单独的LIB文件:
objdump--反向组译- 所有的 -- demangle%EPOCROOT% Epoc32\ release\armi\urel\ euser.lib| perl epoc_exports.pl
这将会产生来自EUSER.DLL的一个所有输出的非常长的列表:
.............
3(0 x3):CBase::newL(不签署了 int)
1(0 x1):memset
2(0 x2):memcpy
1621(0 x655):TUidType::值机员[](int)const
1620(0 x654):TRegion::值机员[](int)const
1619(0 x653):CObjectIx::值机员[](int)
1618(0 x652):CObjectCon::值机员[](int)
.............
转储所有的 LIB 文件:
perl epoc_dump_and_export.pl%EPOCROOT% Epoc32\release\armi\ urel\
这将会在给定的目录中为每个 lib文件产生一个以lib.exp为扩展名的文件。
结论:理解输入、输出功能名和序数可以帮助我们调试和为应用程序除错,如装载库文件和动态地调用函数一样。 |