【发布时间】:2012-01-31 03:34:41
【问题描述】:
所以我在这里遇到了一个非常奇怪和具体的问题。我们将看似有效的代码放入链接器,然后链接器会犯一些错误,例如删除有效的 ptr 标签,而不是将其替换为值,而是放入 0。但也不是无处不在。它从一个相当随意的点开始。
所以,一些背景知识:我们有一种解释性语言,它通过将手动生成的程序集块(由类似内部编译器的应用程序)组合在一起并在需要时添加变量来转换为程序集。这是一个已经工作了大约 10 年甚至更长的系统,几乎是目前的形式,所以这个方法的有效性目前没有问题。使用 Microsoft 汇编程序(ml.exe 或 MASM)将此程序集组装成一个 obj 文件。
然后在一个单独的步骤中,使用 Microsoft 增量链接器将此 obj 文件与其他一些库(静态库和 dll 的导入库)链接以创建可执行文件。
以下是汇编程序在第一步创建 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 文件中的第一个是进入链接器的内容,第二个是来自链接器的内容。
据我所知,它在该位置崩溃是因为它试图取消引用 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”语句),这些位置存储为仍然有效的符号在他们通过链接器之后就可以了。
是否有可能是符号表或类似的东西在链接器内部过载,而它只是恢复为错误值或默认值?
【问题讨论】:
-
我通常建议在 Connect 上发帖,但使用这些旧工具毫无意义。专注于摆脱链接器警告。并更新您的工具。
-
哇,Visual C++ 5.0?我以为每个人都至少更新到了 Visual C++ 6... 你花在调试这个问题和写这个问题上的时间本来可以更好地用在使用最新版本的编译器编译你的代码,一个没有那么多错误的编译器。跨度>
-
伙计们,我知道它已经过时了,但我希望不是这样。升级是可能的,但前提是它可以解决问题,我刚刚使用 Visual Studio 2005、2008 和 2010 中的链接器进行了测试,我最终得到了具有完全相同问题的相同可执行文件。汇编程序仍然是旧版本,因为生成的程序集似乎完全相同,即。仍然正确。
-
什么改变使它停止工作?由于它似乎正确链接了文件的一部分,您是否尝试将 .obj 分解为多个 .obj 文件?
标签: visual-studio assembly linker x86