1

我按升序对 HLA 汇编语言中的 3 个数字进行排序。我没有得到正确的答案。我在 HLA 中的逻辑有什么问题。例如,如果我输入 12、1、50,它应该排序为 1、12、50。相反,我得到以下结果:

Gimme X: 12
Gimme Y: 1
Gimme Z: 50
swapXandY swapXandZ swapYandZ After Sorting, X = 50, Y = 1, Z = 12

这是C++中的代码

#include <iostream>

void Sort(int &a, int &b, int &c){
    if(a>b){
        int tmp = a;
        a = b;
        b = tmp;
    }
    if(a>c){
        int tmp = a;
        a=c;
        c = tmp;
    }
    if(b>c){
        int tmp = b;
        b=c;
        c=tmp;
    }
    return;
}

这是我的 HLA 代码:

program SwapperProgram;
#include ("stdlib.hhf");

static
    iValue1 : int16;
    iValue2 : int16;
    iValue3 : int16;
//-------------------------------------------
procedure swapper (var x : int16; var y : int16; var z : int16); @nodisplay; @noframe;
static
    dReturnAddress : dword;
    iTemp : int16;
    
    dEDXRegister : dword := 0;                              // preserve EDX
    dECXRegister : dword := 0;                              // preserve ECX
    dEBXRegister : dword := 0;                              // preserve EBX
    dEAXRegister : dword := 0;                              // preserve EAX
    
begin swapper;
    mov (EAX, dEAXRegister);
    mov (EBX, dEBXRegister);
    mov (ECX, dECXRegister);
    mov (EDX, dEDXRegister);
    
    pop( dReturnAddress );                              // This is the return address
    
    pop (ECX);                                          // This is the address of z
    pop (EBX);                                          // This is the address of y
    pop (EAX);                                          // This is the address of x
    
    push (dEAXRegister);
    push (dEBXRegister);
    push (dECXRegister);
    push (dEDXRegister);

    cmp (EAX, EBX);                                     // if (x > y)
    jg swapXandY;                                       // swap x and y

    cmp (EAX, ECX);
    jg swapXandZ;

    cmp (EBX, ECX);
    jg swapYandZ;

    
swapXandY:
    stdout.put ("swapXandY ");
    mov ([EAX], EDX);                                   
    mov (DX, iTemp);
    
    mov ([EBX], EDX);
    mov (DX, [EAX]);                                    // *EAX = DX
    
    mov (iTemp, DX);
    mov (DX, [EBX]);
    
swapXandZ:
    stdout.put ("swapXandZ ");
    mov ([EAX], EDX);
    mov (DX, iTemp);
    
    mov ([ECX], EDX);
    mov (DX, [EAX]);
    
    mov (iTemp, DX);
    mov (DX, [ECX]);
    
swapYandZ:
    stdout.put ("swapYandZ ");
    mov ([EBX], EDX);
    mov (DX, iTemp);
    
    mov ([ECX], EDX);
    mov (DX, [EBX]);
    
    mov (iTemp, DX);
    mov (DX, [ECX]);
    jmp ExitSequence;
    
ExitSequence:
    pop (EDX);
    pop (ECX);
    pop (EBX);
    pop (EAX);
    push (dReturnAddress);
    ret();
end swapper;
//---------------------------------------------------------------------------------
begin SwapperProgram;
    stdout.put ("Gimme X: ");
    stdin.get (iValue1);
    stdout.put ("Gimme Y: ");
    stdin.get (iValue2);
    stdout.put ("Gimme Z: ");
    stdin.get (iValue3);
    
    lea( EAX, iValue1 );                                    // get address of iValue1
    push( EAX );
    
    lea( EAX, iValue2 );                                    // get address of iValue2
    push( EAX );
    
    lea( EAX, iValue3 );                                    // get address of iValue3
    push( EAX );
    
    
    call swapper;
    
    stdout.put ("After Sorting, X = ", iValue1);
    stdout.put (", Y = ", iValue2);
    stdout.put (", Z = ", iValue3);
    
end SwapperProgram;
//---------------------------------------------------------------------------------

我的代码哪里错了?我知道我错过了一个逻辑

4

1 回答 1

1

你的控制流程搞砸了。

我认为您需要了解的第一件事是机器代码中不存在标签,因此处理器看不到它们-它们不会停止执行或更改控制流-只有指令可以做到这一点。

除其他外,汇编器使用标签来计算机器代码指令(如分支)所需的数字偏移量。


让我们采用一种非常有条理的方法来翻译伪代码的控制流:

    int tmp;
    if ( a > b ) {
        tmp = a;
        a = b;
        b = tmp;
    }
    if ( a > c ) {
        tmp = a;
        a = c;
        c = tmp;
    }
    if ( b > c ) {
        tmp = b;
        b = c;
        c = tmp;
    }
    return;

将其翻译成 if-goto-label 程序集样式,但仍使用 C 语言,因此您可以真正阅读:

    int tmp;

    if ( a <= b ) goto if1Done;     // start of first if-statement
    tmp = a;                        // then part of first if
    a = b;
    b = tmp;
if1Done:                            // end of first if-statement

    if ( a <= c ) goto if2Done;     // start of second if-statement
    tmp = a;                        // then part of second if
    a = c;
    c = tmp;
if2Done:                            // end of second if-statement

    if ( b <= c ) goto if3Done;     // start of third if-statement
    tmp = b;                        // then part of third if
    b = c;
    c = tmp;
if3Done:                            // end of third if-statement

    return;                         // last statement

你能看到当第一个 if 语句完成时,它如何运行下一个 if 语句,无论第一个 if 语句是否触发/运行它的 then 部分。

这就是控制流在高级语言中的工作方式,如果使用这种有条不紊的按模式翻译方法进行复制,则控制流在汇编语言中的工作方式与在 C 语言中的工作方式相同。

我推荐上述有条不紊的方法,它基于控制语句模式匹配进行翻译,并保持汇编代码块与 C 代码块的顺序相同。在这种方法中,标签名称与控制结构有关,而不是与标签后面的代码的性质有关。

(即使处理器在机器代码中看不到标签,它们也是在汇编语言版本中翻译伪代码的关键部分。)

这种方法唯一真正的缺点是条件测试有时(这里总是)需要被反转/否定,因为我们告诉处理器何时跳过一个 then 部分,即向前跳到下一个语句 - 而不是何时执行then-part(就像我们在 C 中所做的那样)。


但是,在汇编中,我们有额外的选择,因为我们可以随心所欲地 goto,因此其他翻译也是可能的。例如,这里有一个。

    int tmp;

    if ( a > b ) goto if1Then; // start of first if-statement
if1Done:                       // end of first if-statement

    if ( a > c ) goto if2Then; // start of second if-statement
if2Done:                       // end of second if-statement

    if ( b > c ) goto if3Then; // start of third if-statement
if3Done:                       // end of third if-statement

    return;                    // last statement

// out of line then parts

if1Then:                       // start of then part of first if
    tmp = a;
    a = b;
    b = tmp;
    goto if1Done;              // end of then part of first if

if2Then:                       // start of then part of second if
    tmp = a;
    a = c;
    c = tmp;
    goto if2Done;              // end of then part of second if

if3Then:                       // start of then part of third if
    tmp = b;
    b = c;
    c = tmp;
    goto if3Done;              // end of then part of third if

这也是伪代码的控制流结构的有效翻译。(这里我还使用与控制流相关的标签名称,而不是与标签后执行的操作相关的标签名称。)

尽管这可行,但我通常不关心这种不合时宜的形式,尤其是在从伪代码翻译时,因为它将语句分解为彼此分离并分布在函数周围的部分。当然,一个优点是条件操作不必像我上面推荐的更有条理的模式匹配方法那样反转。

于 2021-08-15T15:15:48.950 回答