上次开了个贴“请教一个.Net程序中PInvoke的问题”问了一个我遇到的奇怪现象。问题描述有点乱,所以重开一贴讲一下我的跟踪结果。
把问题简化一下:我发现LoadLibrary()对待DLL和EXE有不同的行为:加载EXE时不处理Base relocation。如果EXE输出的函数再调用其他函数,一定会出问题。因为CALL指令里的地址没有被重定位。
VC默认是不为EXE产生重定位表的,因为一般EXE都能加载到默认基址。强制产生重定位表的方法是在连接选项里添加“/FIXED:NO”。但即使建立了重定位表,LoadLibrary()仍然不为EXE处理重定位。所有CALL/JMP指令里的地址还是保持原状。
跟踪了一下LoadLibraryW()。环境:XP SP2, VS2005
加载DLL时:(为了看起来方便,去掉了一些无关行)0:000> wt -l1Tracing ntdll!LdrpMapDll to return address 7c916071 3 0 [ 0] ntdll!LdrpMapDll 19 0 [ 1] ntdll!_SEH_prolog 10 0 [ 1] ntdll!LdrpEnsureLoaderLockIsHeld 120 0 [ 1] ntdll!LdrpCheckForKnownDll 150 0 [ 1] ntdll!LdrpResolveDllName 30 0 [ 1] ntdll!RtlDosPathNameToNtPathName_U 78 0 [ 1] ntdll!LdrpCreateDllSection 27 0 [ 1] ntdll!RtlFreeHeap 1 0 [ 1] ntdll!ZwMapViewOfSection 3 0 [ 1] ntdll!NtMapViewOfSection 5 0 [ 1] ntdll!RtlImageNtHeader 22 0 [ 1] ntdll!RtlpImageNtHeader 23 0 [ 1] ntdll!RtlImageDirectoryEntryToData 31 0 [ 1] ntdll!LdrpAllocateDataTableEntry 13 0 [ 1] ntdll!LdrpFetchAddressOfEntryPoint 41 0 [ 1] ntdll!LdrpInsertMemoryTableEntry 20 0 [ 1] ntdll!LdrpSendDllLoadedNotifications 23 0 [ 1] ntdll!RtlImageDirectoryEntryToData 18 0 [ 1] ntdll!RtlEqualUnicodeString 18 0 [ 1] ntdll!RtlEqualUnicodeString 167 0 [ 1] ntdll!LdrpSetProtection 13 0 [ 1] ntdll!LdrRelocateImage 1 0 [ 1] ntdll!ZwMapViewOfSection 3 0 [ 1] ntdll!NtMapViewOfSection 199 0 [ 1] ntdll!LdrpSetProtection 23 0 [ 1] ntdll!LdrpValidateImageForMp 1 0 [ 1] ntdll!NtClose 3 0 [ 1] ntdll!ZwClose 9 0 [ 1] ntdll!_SEH_epilog 367 1071 [ 0] ntdll!LdrpMapDll
加载EXE时:0:000> wt -l1Tracing ntdll!LdrpMapDll to return address 7c916071 3 0 [ 0] ntdll!LdrpMapDll 19 0 [ 1] ntdll!_SEH_prolog 10 0 [ 1] ntdll!LdrpEnsureLoaderLockIsHeld 120 0 [ 1] ntdll!LdrpCheckForKnownDll 150 0 [ 1] ntdll!LdrpResolveDllName 30 0 [ 1] ntdll!RtlDosPathNameToNtPathName_U 78 0 [ 1] ntdll!LdrpCreateDllSection 27 0 [ 1] ntdll!RtlFreeHeap 1 0 [ 1] ntdll!ZwMapViewOfSection 3 0 [ 1] ntdll!NtMapViewOfSection 5 0 [ 1] ntdll!RtlImageNtHeader 22 0 [ 1] ntdll!RtlpImageNtHeader 23 0 [ 1] ntdll!RtlImageDirectoryEntryToData 31 0 [ 1] ntdll!LdrpAllocateDataTableEntry 13 0 [ 1] ntdll!LdrpFetchAddressOfEntryPoint 41 0 [ 1] ntdll!LdrpInsertMemoryTableEntry 20 0 [ 1] ntdll!LdrpSendDllLoadedNotifications 1 0 [ 1] ntdll!ZwMapViewOfSection 3 0 [ 1] ntdll!NtMapViewOfSection 1 0 [ 1] ntdll!NtClose 3 0 [ 1] ntdll!ZwClose 9 0 [ 1] ntdll!_SEH_epilog 310 610 [ 0] ntdll!LdrpMapDll
上面有颜色的行就是不同的部分。可以明显看到对EXE文件,LoadLibrary()没有进行基址重定位操作。不明白为什么会有这样的差异。肯定是我少做了什么步骤。到底还需要做什么才能正确调用EXE的导出函数呢?
请赐教。