为何1989年Borland TDSTRIP.EXE函数末尾是RETF 4?替换为RETF才正常
TDSTRIP.EXE路径规范化函数的调用约定疑问
我正在反汇编1989年Borland推出的TDSTRIP.EXE工具(该工具用于从可执行文件中提取Turbo Debugger调试信息),过程中遇到一个路径规范化函数。
函数基本信息
我给这个函数定义的签名是:
extern "C" void far maybe_lib_sub_103FC(char far* dest, const char far* src);
能确定它不是__cdecl调用约定——因为函数会自行清理栈空间,且调用方完全没有做栈调整操作。
测试中的异常现象
我把该函数的反汇编代码做了二进制等价重汇编,在Borland C++ 5.02的DOS小内存模型测试程序里调用时,只有将函数末尾的retf 4替换成retf,代码才能按预期运行。
这让我很困惑:传入的是两个far指针,总共占8字节栈空间,为什么函数要清理4字节?而且函数里也看不到需要栈空间的局部变量,这部分清理的到底是什么?
调用代码反汇编
cmp word ptr [si+2], 0 jz short loc_13478 ; ---- ; calling starts push ds push word ptr [si+2] ; src push ss lea ax, [bp+s1] push ax call maybe_lib_sub_103FC ; after call no sp adjust ; ---- lea ax, [bp+var_52] push ax lea ax, [bp+s1] push ax ; s1 call _strcmp
目标函数反汇编
seg000:03FC _maybe_lib_sub_103FC proc far ; CODE XREF: MAYBE_MAIN_sub_133D6+61P seg000:03FC ; MAYBE_MAIN_sub_133D6+7BP seg000:03FC seg000:03FC arg_0 = dword ptr 6 seg000:03FC arg_4 = dword ptr 0Ah seg000:03FC seg000:03FC 55 push bp seg000:03FD 8B EC mov bp, sp seg000:03FF 1E push ds seg000:0400 56 push si seg000:0401 57 push di seg000:0402 FC cld seg000:0403 C4 7E 0A les di, [bp+arg_4] seg000:0406 32 C0 xor al, al seg000:0408 B9 FF FF mov cx, 0FFFFh seg000:040B F2 AE repne scasb seg000:040D F7 D1 not cx seg000:040F 49 dec cx seg000:0410 C5 76 0A lds si, [bp+arg_4] seg000:0413 03 CE add cx, si seg000:0415 C4 7E 06 les di, [bp+arg_0] seg000:0418 AD lodsw seg000:0419 3B F1 cmp si, cx seg000:041B 77 11 ja short loc_1042E seg000:041D 80 FC 3A cmp ah, ':' seg000:0420 75 0C jnz short loc_1042E seg000:0422 3C 61 cmp al, 61h ; 'a' seg000:0424 72 12 jb short loc_10438 seg000:0426 3C 7A cmp al, 7Ah ; 'z' seg000:0428 77 0E ja short loc_10438 seg000:042A 2C 20 sub al, 20h ; ' ' seg000:042C EB 0A jmp short loc_10438 seg000:042E ; --------------------------------------------------------------------------- seg000:042E seg000:042E loc_1042E: ; CODE XREF: maybe_lib_sub_103FC+1Fj seg000:042E ; maybe_lib_sub_103FC+24j seg000:042E 4E dec si seg000:042F 4E dec si seg000:0430 B4 19 mov ah, 19h seg000:0432 CD 21 int 21h ; DOS - GET DEFAULT DISK NUMBER seg000:0434 04 41 add al, 41h ; 'A' seg000:0436 B4 3A mov ah, 3Ah ; ':' seg000:0438 seg000:0438 loc_10438: ; CODE XREF: maybe_lib_sub_103FC+28j seg000:0438 ; maybe_lib_sub_103FC+2Cj ... seg000:0438 AB stosw seg000:0439 3B F1 cmp si, cx seg000:043B 74 05 jz short loc_10442 seg000:043D 80 3C 5C cmp byte ptr [si], 5Ch ; '\' seg000:0440 74 28 jz short loc_1046A seg000:0442 seg000:0442 loc_10442: ; CODE XREF: maybe_lib_sub_103FC+3Fj seg000:0442 2C 40 sub al, 40h ; '@' seg000:0444 8A D0 mov dl, al seg000:0446 B0 5C mov al, 5Ch ; '\' seg000:0448 AA stosb seg000:0449 56 push si seg000:044A 1E push ds seg000:044B B4 47 mov ah, 47h ; 'G' seg000:044D 8B F7 mov si, di seg000:044F 06 push es seg000:0450 1F pop ds seg000:0451 CD 21 int 21h ; DOS - 2+ - GET CURRENT DIRECTORY seg000:0451 ; DL = drive (0=default, 1=A, etc.) seg000:0451 ; DS:SI points to 64-byte buffer area seg000:0453 1F pop ds seg000:0454 5E pop si seg000:0455 72 13 jb short loc_1046A seg000:0457 26 80 3D 00 cmp byte ptr es:[di], 0 seg000:045B 74 0D jz short loc_1046A seg000:045D 51 push cx seg000:045E B9 FF FF mov cx, 0FFFFh seg000:0461 32 C0 xor al, al seg000:0463 F2 AE repne scasb seg000:0465 4F dec di seg000:0466 B0 5C mov al, 5Ch ; '\' seg000:0468 AA stosb seg000:0469 59 pop cx seg000:046A seg000:046A loc_1046A: ; CODE XREF: maybe_lib_sub_103FC+44j seg000:046A ; maybe_lib_sub_103FC+59j ... seg000:046A 2B CE sub cx, si seg000:046C F3 A4 rep movsb seg000:046E 32 C0 xor al, al seg000:0470 AA stosb seg000:0471 C5 76 06 lds si, [bp+arg_0] seg000:0474 46 inc si seg000:0475 8B FE mov di, si seg000:0477 seg000:0477 loc_10477: ; CODE XREF: maybe_lib_sub_103FC+8Fj seg000:0477 AC lodsb seg000:0478 0A C0 or al, al seg000:047A 74 11 jz short loc_1048D seg000:047C 3C 5C cmp al, 5Ch ; '\' seg000:047E 74 0D jz short loc_1048D seg000:0480 3C 61 cmp al, 61h ; 'a' seg000:0482 72 06 jb short loc_1048A seg000:0484 3C 7A cmp al, 7Ah ; 'z' seg000:0486 77 02 ja short loc_1048A seg000:0488 2C 20 sub al, 20h ; ' ' seg000:048A seg000:048A loc_1048A: ; CODE XREF: maybe_lib_sub_103FC+86j seg000:048A ; maybe_lib_sub_103FC+8Aj ... seg000:048A AA stosb seg000:048B EB EA jmp short loc_10477 seg000:048D ; --------------------------------------------------------------------------- seg000:048D seg000:048D loc_1048D: ; CODE XREF: maybe_lib_sub_103FC+7Ej seg000:048D ; maybe_lib_sub_103FC+82j seg000:048D 81 7D FE 5C 2E cmp word ptr [di-2], 2E5Ch seg000:0492 75 04 jnz short loc_10498 seg000:0494 4F dec di seg000:0495 4F dec di seg000:0496 EB 1C jmp short loc_104B4 seg000:0498 ; --------------------------------------------------------------------------- seg000:0498 seg000:0498 loc_10498: ; CODE XREF: maybe_lib_sub_103FC+96j seg000:0498 81 7D FE 2E 2E cmp word ptr [di-2], 2E2Eh seg000:049D 75 15 jnz short loc_104B4 seg000:049F 80 7D FD 5C cmp byte ptr [di-3], 5Ch ; '\' seg000:04A3 75 0F jnz short loc_104B4 seg000:04A5 83 EF 03 sub di, 3 seg000:04A8 80 7D FF 3A cmp byte ptr [di-1], 3Ah ; ':' seg000:04AC 74 06 jz short loc_104B4 seg000:04AE seg000:04AE loc_104AE: ; CODE XREF: maybe_lib_sub_103FC+B6j seg000:04AE 4F dec di seg000:04AF 80 3D 5C cmp byte ptr [di], 5Ch ; '\' seg000:04B2 75 FA jnz short loc_104AE seg000:04B4 seg000:04B4 loc_104B4: ; CODE XREF: maybe_lib_sub_103FC+9Aj seg000:04B4 ; maybe_lib_sub_103FC+A1j ... seg000:04B4 0A C0 or al, al seg000:04B6 75 D2 jnz short loc_1048A seg000:04B8 80 7D FF 3A cmp byte ptr [di-1], 3Ah ; ':' seg000:04BC 75 03 jnz short loc_104C1 seg000:04BE B0 5C mov al, 5Ch ; '\' seg000:04C0 AA stosb seg000:04C1 seg000:04C1 loc_104C1: ; CODE XREF: maybe_lib_sub_103FC+C0j seg000:04C1 32 C0 xor al, al seg000:04C3 AA stosb seg000:04C4 5F pop di seg000:04C5 5E pop si seg000:04C6 1F pop ds seg000:04C7 5D pop bp seg000:04C8 CA 04 00 retf 4 seg000:04C8 _maybe_lib_sub_103FC endp
疑问总结
从函数对bp和sp的使用方式来看,它像是用C语言编写后编译生成的,但会不会是手写汇编时错误实现了retf指令?
内容的提问来源于stack exchange,提问作者llm
相关产品推荐
相关产品推荐

