这个大会是干什么的?

逆向工程 拆卸 x86
2021-06-21 07:53:22

我一直在尝试找出部分 DOS 游戏的程序集,并且有一个操作不断被调用,它使用了所有 4 个寄存器。我可以看到每一行的作用,但我一生都无法弄清楚所有代码一起意味着做什么。

任何人都可以给我一些想法吗?

代码是:

seg000:3825 some_math_op_on_regs proc far; CODE XREF: sub_72C6+19FP
seg000:3825                              ; sub_72C6+1DDP ...
seg000:3825       cmp     cl, 10h
seg000:3828       jnb     short loc_383A ; Jump if CF=0
seg000:382A       mov     bx, dx         ; c register is < 16; move d to b
seg000:382C       shr     ax, cl         ; Shift a right by value in c (logical)
seg000:382E       sar     dx, cl         ; Shift d right by value in c (arithmetic)
seg000:3830       neg     cl             ; Negate c (2's complement)
seg000:3832       add     cl, 10h        ; Add 16 to c
seg000:3835       shl     bx, cl         ; Shift b left by value in c (logical)
seg000:3837       or      ax, bx         ; OR a and b, store result in a
seg000:3839       retf
seg000:383A ; --------------------------------------------------------------------
seg000:383A
seg000:383A loc_383A:                    ; CODE XREF: some_math_op_on_regs+3j
seg000:383A       sub     cl, 10h        ; c register is >= 16; subtract 16 from c
seg000:383D       xchg    ax, dx         ; Switch values in a and d
seg000:383E       cwd                    ; Convert word to doubleword
seg000:383F       sar     ax, cl         ; Shift a right by value in c (arithmetic)
seg000:3841       retf
seg000:3841 some_math_op_on_regs endp
2个回答

这看起来像一个 32 位右移编译器助手。在 16 位时代,32 位数字由一对寄存器表示,在本例中为ax:dx. 对16的检查是一种优化:如果移位超过16,则低寄存器值完全丢失,因此可以将其丢弃并替换为dx>>(shift-16),而作为cwd指令结果的高寄存器填充符号位这是来自 Borland C 运行时库的(轻微)注释的源代码,它似乎与您的匹配:

;[]-----------------------------------------------------------------[]
;|      H_LRSH.ASM -- long shift right                               |
;[]-----------------------------------------------------------------[]

;
;       C/C++ Run Time Library - Version 5.0
; 
;       Copyright (c) 1987, 1992 by Borland International
;       All Rights Reserved.
; 

        INCLUDE RULES.ASI

_TEXT   segment public byte 'CODE'
        assume  cs:_TEXT
        public  LXRSH@
        public  F_LXRSH@
        public  N_LXRSH@

N_LXRSH@:
        pop     bx                      ;fix up for far return
        push    cs
        push    bx
LXRSH@:
F_LXRSH@:
        cmp     cl,16
        jae     lsh@small
        mov     bx,dx                   ; save the high bits
        shr     ax,cl                   ; now shift each half
        sar     dx,cl
;
;                       We now have a hole in AX where the lower bits of
;                       DX should have been shifted.  So we must take our
;                       copy of DX and do a reverse shift to get the proper
;                       bits to be or'ed into AX.
;
        neg     cl
        add     cl,16
        shl     bx,cl
        or      ax,bx
        retf
lsh@small:
        sub     cl,16                   ; for shifts more than 15, do this
                                        ; short sequence.
        xchg    ax,dx                   ;
        cwd                             ; We have now done a shift by 16.
        sar     ax,cl                   ; Now shift the remainder.
        retf
_TEXT   ends
        end

它似乎是一个 32 位右移,其中提供了 32 位数字dx:ax,并且cl是要移位的位数。

如果假设cl超过 16 位,则右移 16 位以上只需要关心存储在 中dx的高 16 位,因为低 16 位无论如何都会移出。

所以这正是第二块所做的。如果cl大于 16,将dx(高 16 位)移入ax并将其转换为 32 位数字,减去 16,cl因为这是通过忽略低 16 位隐式完成的,然后将高部分(现在dx:ax归功于cwd)移动那个数字。

我没有试图理解上面的部分,但我的假设是它对于 16 位以下的移位宽度完全相同。

基本上,它是在 16 位架构中完成的 32 位右移。