1

I am sorting 3 numbers in HLA Assembly Language in Ascending order. I am not getting the right answer. What is wrong with my logic in HLA. For Example, if I enter 12, 1, 50, it should sorted 1, 12, 50. Instead,I am getting following result:

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

Here is the code in 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;
}

Here is my HLA code:

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;
//---------------------------------------------------------------------------------

Where in my code is wrong? I know I am missing a logic

Matt_Ag
  • 25
  • 5

1 Answers1

1

Your control flow is messed up.

The first thing I think you need to appreciate is that labels do not exist in machine code, so the processor doesn't see them — they don't stop execution or change control flow — only instructions do that.

Among other things, labels are used by the assembler to compute the numeric offsets needed in machine code instructions like branches.


Let's take a very methodical approach to translation of the control flow of your pseudo code:

    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;

Translating this into the if-goto-label style of assembly, but still in C so you can really read it:

    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

Can you see how when the first if-statement is completed, it runs the next if-statement, whether or not the first if-statement fires/runs its then part.

This is how the control flow works in high level language, and if replicated using this methodical translation-by-pattern approach, the control flow will work the same in assembly language as it does in C.

I recommend the above methodical approach, which translates based on control statement pattern matching, and, keeps the assembly code blocks in the same order as the C code blocks.  In this approach, the label names relate to the control structures, not to the nature of the code that comes after the label.

(Even though the labels are not seen by the processor in machine code, they are critical parts to translation of pseudo code in an assembly language version.)

The only real downside of this approach is that conditional tests sometimes (here always) need to be reversed/negated, since we tell the processor when to skip around a then-part, i.e. skip ahead to the next statement — rather than when to execute a then-part (as we do in C).


However, in assembly, we have additional choices, as we can gotos as we like, so other translations are possible.  For example, here's one.

    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

This is also a valid translation of the control flow structures of the pseudo code.  (Here I also use label names that relate to the control flow rather than to operations being performed after the label.)

Though this works, I generally don't care for this out of line form, especially when translating from pseudo code, since it breaks up statements into piece parts that are separated from each other and distributed around the function.  One advantage, of course, is that the conditional operations do not have to be reversed as they are with the more methodical pattern match approach I recommend above.

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • You can use the `jn...` conditional branch instructions to express the reverse of a condition. If your high-level `if` statement reads `if (a > b)` you can write a `cmp` and then `jna skiplabel` so that the Above condition indicates to enter the `if` body. – ecm Aug 20 '21 at 21:33