How to compare 2 arrays on assembly language (x86)?

3.6k views Asked by At
    .MODEL  SMALL
    .STACK  64
    .DATA

    LIST1 DB 1H,0ABH,2H,3AH,12H,0DAH
    LIST2 DB 3H,7H,0BCH,0A8H,0C2H,0DAH
    LIST3 DB 6 DUP (?)

    .CODE


MAIN    PROC    FAR
    MOV     AX, @data
    MOV DS, AX

    MOV CX,6H
    LEA SI,LIST1
    LEA BX,LIST2
    LEA DI,LIST3

A1: MOV AL,[SI]
    ADD AL,BX
    MOV [DI],AL
    INC SI
    INC BX
    INC DI
    LOOP    A1

I want to compare list1 & list2 and put the greater number in list3. How to do that?

2

There are 2 answers

2
lurker On

Here's an alternative A1 loop. I think your setup instructions are OK. I'm assuming Intel syntax on operand ordering for instructions.

A1:
    MOV   AL,[SI]     ; get the next byte from LIST1
    ADD   AH,[BX]     ; get the next byte from LIST2

    CMP   AL,AH       ; compare bytes from 1 & 2
    JGT   BIGGER2     ; jump if LIST1 byte > LIST2 byte

    MOV   [DI],AL     ; move LIST1 byte to LIST2
    JMP   NEXT

BIGGER2:
    MOV   [DI],AH     ; move LIST2 byte to LIST3

NEXT:
    INC   SI          ; point to next LIST1 byte
    INC   BX          ; point to next LIST2 byte
    INC   DI          ; point to next LIST3 byte
    LOOP  A1          ; go to the top for the next byte

In solving a problem like this, you can actually start by writing out the comments. If you were to take the comments above by themselves, they form the low level steps in English of what you want to do. Then you can translate those steps into the needed assembly language. You can then also optimize if needed.

[EDIT]

Note also that, as @Powerslave showed in his answer, you can shorten this a bit using the built-in x86 "string" instruction, cmpsb. That assumes source and destination lists are pointed to by si and di.

For addition, the following puts the SUM of LIST1 and LIST2 into LIST3. Note that you allocated bytes for LIST3 but when you sum LIST1 and LIST2 elements, you'll get an overflow if you keep them as bytes. So I will use words for the sum:

LIST3 DW 6 DUP (?)

...

    CLR   AH
A1:
    MOV   AL,[SI]     ; get the next byte from LIST1
    MOV   [DI],AX     ; move the value (byte) to LIST3
    MOV   AL,[BX]     ; get the value (byte) from LIST2
    ADD   [DI],AX     ; add the LIST2 value to LIST3 (word)
    INC   SI          ; point to next LIST1 byte
    INC   BX          ; point to next LIST2 byte
    ADD   DI,2        ; point to next LIST3 word
    LOOP  A1          ; go to the top for the next byte
0
Powerslave On

A solution would be

; ES == DS

lea si,[LIST1]
lea di,[LIST2]
lea bx,[LIST3]
mov cx,LENGTH_OF_LISTS

inspect_lists:
    cmpsb
    jg first_is_greater            ; Use JA instead for unsigned integers
    mov al,[byte ptr es:di + 0]
    jmp store_result

    first_is_greater:
    mov al,[byte ptr ds:si + 0]

    store_result:
    mov [byte ptr ds:bx + 0],al
    inc bx
loop inspect_lists

inspect_lists supposed to be your A1 loop.

cmpsb, in one step, does compare [DS:SI] with [ES:DI]
(essentially a virtual cmp [byte ptr ds:si],[byte ptr es:di]) and increments (or decrements if DF is 1) the SI and DI pointers so that you don't have to worry about them yourself.

You still need to adjust BX in order to iterate through LIST3.

The only thing to do besides that is to decide which value to store at [DS:BX]...