跟踪MASM的NCR组装程序

时间:2016-05-30 18:24:15

标签: assembly masm x86-16

当我们的讲师解释时,我错过了会议..

我知道NCR的公式

  

NCR = N! /(R!*(N-R)!)

我没有关注 NCR PROC ,因为没有找到因子,并且那里正在进行一些令人毛骨悚然的递归工作。非常感谢帮助。

print macro str
    lea dx,msg
    mov ah,09h
    int 21h
endm

.model small
.data
    n dw 15
    r dw 6
    ncr dw 1
    msg db "The NCR is : ","$"
.code
     start: mov ax,@data
            mov ds,ax

            mov bx,n
            mov cx,r
            inc bx
            call ncr1
            print msg          
            mov ax,ncr
            call display

            mov ah,4ch
            int 21h

          ncr1 proc
                cmp cx,00      
                  je l1
                push cx         
                dec cx
                call ncr1        
                mov ax,bx       
                pop cx          
                sub ax,cx       
                mul ncr         
                div cx          
                mov ncr,ax      
              l1 : ret
          ncr1 endp

          display proc
                aam
                add ax,3030h
                mov bx,ax
                mov dl,bh
                mov ah,02h
                int 21h
                mov dl,bl
                mov ah,02h
                int 21h                
             ret
      display endp

end start                

1 个答案:

答案 0 :(得分:3)

好的,我在显示如何分析汇编程序代码块时看到了一些重用值,所以就是这样。

我们在这里处理一个子程序,这是一段应该相对自治的代码。

首先,让我们确定它对程序的原始影响:它的输入,输出和对ncr1 proc cmp cx,00 # <-- cx je l1 push cx dec cx call ncr1 mov ax,bx # <--bx pop cx sub ax,cx mul ncr # <--ncr div cx mov ncr,ax l1 : ret ncr1 endp 的影响 - 即它的调用约定签名

它使用哪些不是由它设置的实体?

ncr1 proc
    cmp cx,00
      je l1
    push cx      # cx->local_stack[-2]
    dec cx       # -->cx? (overridden)
    call ncr1
    mov ax,bx
    pop cx       # local_stack[-2]->cx => cx restored
                 # (the next step is actually needed to deduce push/pop
                 # correspondence so they should be done in parallel)
    sub ax,cx
    mul ncr      # -->ax,dx
    div cx
    mov ncr,ax   # -->ncr
  l1 : ret
ncr1 endp

它修改了哪些实体,之后没有恢复?

sp

仅标记实体的最后更改(因为它们优先于早期更改)。

它对sp有任何净影响吗? (数字是相对于返回地址的当前ncr1 proc cmp cx,00 je l1 push cx #-2 dec cx call ncr1 #delta is same as self mov ax,bx pop cx #0 sub ax,cx mul ncr div cx mov ncr,ax l1 : ret #without an argument, only cleans the return address ncr1 endp

0

它没有(所以&#34;与self&#34相同;为0),ret在所有情况下ncr1 (cx,bx,ncr) -> ax,dx,ncr 确认它正确处理本地堆栈。 / p>

结论,它的签名是:

ax

dxncr1 proc --initially: bx=N, cx=R (metavariables) cmp cx,00 # if R==0: je l1 # ret (ax,dx,ncr unchanged) push cx #[-2]=R dec cx #cx=R-1 call ncr1 #ncr1(N,R-1) -> ax,dx,ncr(probably the result) mov ax,bx #ax=N pop cx #cx=[-2]=R sub ax,cx #ax=N-R mul ncr #dx:ax=(N-R)*ncr = (N-R)*ncr1(N,R-1) div cx #ax=[(N-R)*ncr1(N,R-1)]/R mov ncr,ax #ncr=[(N-R)*ncr1(N,R-1)]/R l1 : ret ncr1 endp # -> ax,dx,ncr(the result, now we're sure) 可能尚未使用(但它们仍为volatile)。 调用约定为custom pure register,其中包含一个硬编码的输入/输出参数。

现在,剩下的就是跟踪每个实体在任何时间持有的物理 - 然后是概念 - 值:

(N,R) -> [(N-R)*ncr1(N,R-1)]/R

以下是:该过程计算N=bx其中R=cxncr,结果为(N-R)(已变异)。

看起来可疑:(N+1-R)根据comment62556150在规范公式中为n=N-1。如果我们替换(n+1,R) -> [(n+1-R)*ncr(n+1,R-1)]/R,它将变为:nCr(n-1,r)看起来没问题(第一个参数永远不会改变)...所以该过程实际上计算n+1

传递n的选择必须是因为n+1仅作为{{1}}进入公式,因此,我们会在每次增加时保存周期。