所以我在这里遇到了一个非常奇怪和具体的问题。我们将看似有效的代码放入链接器中,然后链接器出现了一些错误,比如删除一个有效的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'语句)存储为仍然有效的符号他们通过链接器后很好。
符号表或类似的东西是否有可能在链接器中过载,而它只是恢复为错误值或默认值?
答案 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和链接版本似乎是我们的最佳解决方案。
感谢您的帮助:)