1

The task is: Check if the second row of a two-dimensional array is sorted in descending order. I need to do this using assembly masm. Here is the code:

.686
.model flat, stdcall
option casemap:none

include C:\masm32\include\windows.inc
include C:\masm32\include\user32.inc
include C:\masm32\include\kernel32.inc
include C:\masm32\include\masm32.inc
includelib C:\masm32\lib\user32.lib
includelib C:\masm32\lib\kernel32.lib
includeLib C:\masm32\lib\masm32.lib

.data
    sConsoleTitle BYTE "Task", 0
    task BYTE "Check if the second row of a two-dimensional array is sorted in descending order", 0Dh, 0Ah, 0
    Arr     DWORD   4, 6, 2, 8
    RowSize = ($ - Arr)
            DWORD    9, 4, 2, 1
            DWORD    7, 3, 5, 1
            DWORD    6, 8, 1, 7
    resultText BYTE "Result: "
    row BYTE 4
    col BYTE 4
    i BYTE 0
    j BYTE 0
    exitText BYTE "Print enter to exit....", 0Dh, 0Ah, 0
    pos BYTE "Yes", 0Dh, 0Ah, 0
    negative BYTE "No", 0Dh, 0Ah, 0
    resultStr BYTE 16 DUP(' ')
    buffer BYTE 20 DUP(?), 0
    clrt BYTE 0Ah, 0Dh, 0
    tab BYTE "  ", 0
    sum DWORD 0

.code
start:
invoke SetConsoleTitle, offset sConsoleTitle
invoke StdOut, offset task

; Show array
xor ecx, ecx
mov cl, row
mov esi, 0
loop_row_1:
    push ecx
    xor ecx, ecx
    mov cl, col
    mov ebx, 0
loop_col_1:
    mov eax, Arr[esi][ebx]
    push ebx
    push ecx
    push esi
    invoke ltoa, eax, ADDR buffer
    invoke StdOut, ADDR buffer
    invoke StdOut, ADDR tab
    pop esi
    pop ecx
    pop ebx
    add ebx, TYPE Arr

    loop loop_col_1
    invoke StdOut, ADDR clrt

    add esi, RowSize

    pop ecx
    loop loop_row_1

; Check
mov esi,1
xor ecx, ecx
mov cl, col
mov ebx, 0
mov j, 0
loop_col_2:
    mov eax, Arr[esi][ebx]
    cmp eax, 0
    jle no
    add ebx, TYPE Arr
    loop loop_col_2
    invoke StdOut, ADDR clrt
yes:
    invoke StdOut, ADDR resultText
    invoke StdOut, ADDR pos
    jmp exit
no:
    invoke StdOut, ADDR resultText
    invoke StdOut, ADDR negative
exit:
    invoke StdIn, ADDR buffer, lengthof buffer
end start

Why did I always get the possitive answer, by the way I got it always, also when I change the value of esi register to another value (this register is responsible for which string is will be checked). I have no idea what I am doing wrong. (Actually maybe I do something worng with registers, but I have an example which is almost the same as my task and I wrote the code like in this example, but the problem is still on)

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
woolMe
  • 47
  • 6
  • 1
    `Arr[esi][ebx]` is just `[Arr + esi + ebx]`; it doesn't magically scale by the row width (because x86 addressing modes can only scale one register, and only by a shift count of 0..3). Just like it doesn't scale by the DWORD element width (because that's not what that syntax means in MASM. It's not C); that's why you had to use `add ebx, TYPE Arr` instead of `inc ebx` See [Referencing the contents of a memory location. (x86 addressing modes)](https://stackoverflow.com/q/34058101). Use a debugger to look at regs to check the data you're loading into EAX isn't partial overlap of 2 elements. – Peter Cordes Apr 21 '23 at 06:16
  • 1
    Also, `cmp eax, 0` / `jle no` just checks for non-positive elements; it doesn't compare against the previous element to check for sorted order. – Peter Cordes Apr 21 '23 at 06:21
  • Also, `mov j, 0` is useless. Addressing modes need values in registers, so as you've seen, it's not useful to have `j BYTE 0` in static storage. Storing/reloading to that would just make your code more complicated that using a register with a byte offset. e.g. `mov esi, OFFSET Arr + 16` should be the start of the 2nd row. – Peter Cordes Apr 21 '23 at 06:22

1 Answers1

1

You have your 2D-matrix in row-order. Therefore the elements of the row that you need to inspect will be adjacent to each other and will have been stored in consecutive dwords in memory. All you will need is a simple pointer to the start of the concerned row. With row numbering starting at 0, the formule is:

RowAddress = ArrayAddress + Row * RowSize

mov  ebx, OFFSET Arr + 1 * RowSize    ; Row = 1 for the second row

The task of finding out if this row is sorted in descending order translates to writing a loop that compares every 2 adjacent dwords for as long as the first value is greater or equal to the second and for as long as comparisons can be made because if you got 4 columns in the array the most pair-wise comparisons that are possible is 3.

    mov   ebx, OFFSET Arr + RowSize  ; Start of 2nd row
    movzx ecx, col
    dec   ecx                        ; Number of required comparisons
More:
    mov   eax, [ebx]
    cmp   eax, [ebx + 4]
    jl    No
    add   ebx, 4
    dec   ecx
    jnz   More
Yes:

An alternative that uses one register less and that stops as soon as the pointer reaches the last element of the row:

    mov   ebx, OFFSET Arr + RowSize  ; Start of 2nd row
More:
    mov   eax, [ebx]
    cmp   eax, [ebx + 4]
    jl    No
    add   ebx, 4
    cmp   ebx, OFFSET Arr + RowSize + RowSize - 4 ; Address last element of 2nd row
    jb    More
Yes:

Another alternative that avoids reading the same datum twice:

    mov   ebx, OFFSET Arr + RowSize  ; Start of 2nd row
    mov   edx, [ebx]
More:
    add   ebx, 4
    mov   eax, edx
    mov   edx, [ebx]
    cmp   eax, edx
    jl    No
    cmp   ebx, OFFSET Arr + RowSize + RowSize - 4 ; Address last element of 2nd row
    jb    More
Yes:
Sep Roland
  • 33,889
  • 7
  • 43
  • 76