链接器用无效代码替换有效代码

时间:2012-01-31 03:34:42

标签: visual-studio assembly linker x86

所以我在这里遇到了一个非常奇怪和具体的问题。我们将看似有效的代码放入链接器中,然后链接器出现了一些错误,比如删除一个有效的ptr标签,而不是用一个值替换它,而是放入0。但也不是到处都是。它始于一个非常随意的点。

所以,一些背景知识:我们有一种解释型语言,通过将手工生成的程序块(通过内部编译器类应用程序)放在一起并在需要时添加变量,将其转换为程序集。这个系统已经工作了大约10年,如果不是更长时间,几乎是目前的形式,所以这种方法的有效性目前还没有问题。使用Microsoft Assembler(ml.exe或MASM)将此程序集组装到obj文件中。

然后在单独的步骤中,使用Microsoft Incremental Linker和其他一些库(dll的静态和导入库)链接此obj文件以创建可执行文件。

以下是汇编程序在第一步创建obj文件时输出的汇编(.asm)文件的一部分:

call _c_rt_strcmp               
mov di, 1                   
mov ebp, esp                
cmp ax, 0                   
je sym2148                  
dec di                      
sym2148: mov [ebp+6], di        
add esp, 6                  
mov     ebx, dword ptr [_smfv1_ptr]     
add     ebx, 0bb49h     
pop ax
mov byte ptr [ebx],al
mov     ebx, dword ptr [_smfv1_ptr]     
add     ebx, 012656h        
push        ebx                     
mov eax, OFFSET sym2151
push eax
call _c_rt_strcmp               
mov di, 1                   
mov ebp, esp                
cmp ax, 0                   
je sym2152                  
dec di                      
sym2152: mov [ebp+6], di        
add esp, 6                  
mov     ebx, dword ptr [_smfv1_ptr]     
add     ebx, 0bb32h     
pop ax
mov byte ptr [ebx],al
mov     ebx, dword ptr [_smfv1_ptr]     
add     ebx, 012656h        
push        ebx                     
mov eax, OFFSET sym2155
push eax
call _c_rt_strcmp               
mov di, 1                   
mov ebp, esp                
cmp ax, 0                   
je sym2156                  
dec di                      
sym2156: mov [ebp+6], di        
add esp, 6                  
mov     ebx, dword ptr [_smfv1_ptr]     
add     ebx, 0bb4ah     
pop ax
mov byte ptr [ebx],al
mov     ebx, dword ptr [_smfv1_ptr]     
add     ebx, 0126bbh        
push        ebx                     
mov eax, OFFSET sym2159
push eax
call _c_rt_strcmp

据我所知,这是正确的,也是有道理的。我相信生成它的代码会进行字符串比较,然后根据字符串比较的结果存储一个值,并且它是20-30的一部分,所以在我发布的第一个位之前有10个左右的组,在我发布的最后一点之后大约15-20。

下面是崩溃位置的反汇编视图,Visual C ++ 5.0(旧的我知道,但遗传系统很遗憾)显示可执行文件崩溃时:

004093D2   call        00629570
004093D7   mov         di,1
004093DB   mov         ebp,esp
004093DD   cmp         ax,0
004093E1   je          004093E5
004093E3   dec         di
004093E5   mov         word ptr [ebp+6],di
004093E9   add         esp,6
004093EC   mov         ebx,dword ptr ds:[64174Ch]
004093F2   add         ebx,0BB49h
004093F8   pop         ax
004093FA   mov         byte ptr [ebx],al
004093FC   mov         ebx,dword ptr ds:[64174Ch]
00409402   add         ebx,12656h
00409408   push        ebx
00409409   mov         eax,0
0040940E   push        eax
0040940F   call        00409414
00409414   mov         di,1
00409418   mov         ebp,esp
0040941A   cmp         ax,0
0040941E   je          00409422
00409420   dec         di
00409422   mov         word ptr [ebp+6],di
00409426   add         esp,6
00409429   mov         ebx,dword ptr ds:[0]
0040942F   add         ebx,0BB32h
00409435   pop         ax
00409437   mov         byte ptr [ebx],al
00409439   mov         ebx,dword ptr ds:[0]
0040943F   add         ebx,12656h
00409445   push        ebx
00409446   mov         eax,0
0040944B   push        eax
0040944C   call        00409451
00409451   mov         di,1
00409455   mov         ebp,esp
00409457   cmp         ax,0
0040945B   je          0040945F
0040945D   dec         di
0040945F   mov         word ptr [ebp+6],di
00409463   add         esp,6
00409466   mov         ebx,dword ptr ds:[0]
0040946C   add         ebx,0BB4Ah
00409472   pop         ax
00409474   mov         byte ptr [ebx],al
00409476   mov         ebx,dword ptr ds:[0]
0040947C   add         ebx,126BBh
00409482   push        ebx
00409483   mov         eax,0
00409488   push        eax
00409489   call        0040948E

实际的崩溃位置是0x00409429。

两位代码匹配,因为它们是相同的代码段,除了.asm文件中的第一个是进入链接器的内容,第二个是链接器中出现的内容。 / p>

从我所看到的,它在该位置崩溃,因为它试图取消引用0的地址,对吗?所以当然会失败。另外,如果你看一下0x004093D2,0x0040940F,0x0040944C和0x00409489的不同函数调用,只有第一个有效,其他函数只是在它们之后直接进行函数调用!这个破碎的代码将继续用于该文件中定义的下一个15-20个相似代码段。

如果查看函数调用的相应行和两个部分中的错误指针,您会看到.asm文件中的所有内容看起来都是正确的,但是不知何故链接器在编译exe时会破坏它们,并且在一个非常具体的位置,因为在文件中先前有类似的代码块正确构造。

我们确实收到了一些形式的链接器警告:“LINK:警告LNK4049:本地定义的符号”_smfv1_ptr“已导入”。但即使它正在工作,我们也会得到同样的警告。

使用的汇编程序是ml.exe版本6.11,链接器是link.exe版本5.10.7303,它们都是Visual C ++ 5.0的版本。由于汇编代码似乎是正确的,我将尝试使用Visual Studio 2005,2008和2010中的链接器,看看是否有任何变化。

我无法想象是什么会造成这种错误,我想也许这些符号变得混乱了,但是有跳转到位置(对于小'if'语句)存储为仍然有效的符号他们通过链接器后很好。

符号表或类似的东西是否有可能在链接器中过载,而它只是恢复为错误值或默认值?

2 个答案:

答案 0 :(得分:1)

调用以下地址是未解析的符号引用的明确标志(如果您注意到.obj文件中的所有调用都作为E8 00 00 00 00发出,则有意义)。对于某些数据引用,您也有零(sym2151,对_smfv1_ptr,sym2159的一些引用)。奇怪的是,第一次调用_c_rt_strcmp确实得到了解决。我建议打开你能找到的所有警告/调试/详细开关,并生成各种列表和地图文件。也许会跳出来。

答案 1 :(得分:0)

好的,最终的结果似乎是它是masm汇编程序“ml.exe”的Visual C ++版本的一个错误(大惊喜,嗯?)

因此,转移到Visual Studio 2005中提供的masm和链接版本似乎是我们的最佳解决方案。

感谢您的帮助:)