在 x86 程序集中使用宏查找 3 个数的最小值

Finding the Min of 3 Numbers with a Macro in x86 Assembly

我编写了一个简单的宏,用于查找三个数字中的最小值。在当前状态下,只有当第一个或第三个参数是最小值而不是第二个时,宏才会起作用。我的循环或比较有什么我没有发现的问题吗?或者我应该做些什么不同的事情?任何建议或意见表示赞赏。

findMin     MACRO   arg1, arg2, arg3
                
            mov eax, arg1 
            
            cmp eax, arg2         ; if eax is greater than arg2 swap
            jg swap1

            cmp eax, arg3         ; if eax is greater than arg3 swap
            jg swap2

            jmp endMac

            swap1: xchg eax, arg2
            swap2: xchg eax, arg3
            endMac:
          
            ENDM

用于查找 3 个数字的最小值的简化宏(最小值将在 EAX 寄存器中)

findMin    MACRO   arg1, arg2, arg3

           LOCAL L2, L3

           mov   eax, arg1
           
           cmp   eax, arg2
           jg    l2
           cmp   eax, arg3
           jg    l3
           jmp   endMac

           L2: xchg eax, arg2
               cmp  eax, arg3
               jg   L3
               jmp  endMac
           L3: xchg eax, arg3

           endMac:

           ENDM

MASM宏功能非常强大。您可以验证参数的类型,甚至可以进行条件汇编。结合自 Intel P6 系列处理器 以来可用的条件移动 CMOVcc,您可以将程序优化为

min MACRO arg1:REQ, arg2:REQ, arg3:REQ
  ; Returns result in EAX register 
  IF ((OPATTR (arg2)) AND 00000100b) or ((OPATTR (arg3)) AND 00000100b) 
    ECHO ### Function min: No constants allowed as arguments
  ELSEIF ((OPATTR (arg1)) AND 00000100b)
    ; Move constant to EAX if it's not EAX
    mov    eax, arg1  
  ELSEIF (SIZE TYPE arg1 NE 4)
    ECHO ### Function min: First parameter must be of DWORD type
  ELSEIF SIZE TYPE arg2 NE 4
    ECHO ### Function min: Second parameter must be of DWORD type
  ELSEIF SIZE TYPE arg3 NE 4
    ECHO ### Function min: Third parameter must be of DWORD type
  ELSEIFDIF <arg1>, <eax>
    ; Move first value to EAX if it's not EAX
    mov    eax, arg1  
  ENDIF
  cmp    eax, arg2    ; compare arg1 to arg2
  cmovg  eax, arg2    ; move arg2 to EAX if EAX is greater than arg2      
  cmp    eax, arg3    ; compare arg1 to arg3
  cmovg  eax, arg3    ; move arg3 to EAX if EAX is greater than arg3     
ENDM

在上面的 MACRO 中,OPATTR (arg1)) AND 00000100b 检查 arg1 是否是一个常量值。这很重要,因为 CMOVcc 指令不将常量作为参数。您可以扩展宏以使用条件汇编将常量移动到寄存器或临时变量,但这在上面的代码中没有实现。

SIZE TYPE arg1 NE 4 指令检查参数的大小是否为 4、寄存器或内存 - 防止 MOV 可能出现的错误。您可以扩展它以将 MOVZX/MOVSX 与进一步的条件装配一起使用。

IFDIF <arg1>, <eax> 检查第一个参数是否等于字符串“EAX”。这样做是为了避免在值已存在的情况下设置 EAX 寄存器。

发生的错误以 ### 开头的控制台回显到控制台,在组装时提供额外信息。

这个 MACRO 远未完成。它只处理一些可能的错误,可以扩展以实现更多的自动化。但恕我直言,它显示了一种值得考虑的方法。