arraysassemblymergex86-64att

Merging sorted arrays: I can't compare values from arrays


I have a question that asks me to merge two arrays with each value being an int, so 4 bytes long, into one array. The values in the arrays are in order from highest to lowest and so needs to be the new array.
The arrays end with 0 both, and so should the new one.

All 3 of the arrays I get by getting a label to memory, and then the new array needs to be saved in the address of the label mergedArray.

But, the values in the old arrays can appear more than once, while the new array needs to have each value once at most.

The code I wrote seems to work fine while the arrays don't have values appear more than once, but fail once any value appear more than once.

I tried to compare the value I have in the original array to the value I have in the new array, and then skip it if they are the same.

But after running some tests, it seems that adding, or removing that comparison makes no difference to the code.

Here's the code:

.global _start

.section .text
_start:
    mov $array1, %rax
    mov $array2, %rcx
    mov $mergedArray, %r8

    xor %r14,%r14
    
loopcheck: #checks if arrays are finished

    movl (%rax), %r9d 
    movl (%rcx), %r10d 
    movl (%r8), %r11d

    testl %r9d, %r9d
    jz rest_of_array2

    
    testl %r10d, %r10d
    jz rest_of_array1
    
loop: #the main loop
    cmp %r10d, %r9d 
    jg add_r9d
    jmp add_r10d
    

add_r9d: #add rax value
    cmp %r11d,%r9d
    jz remove_current_r9d
    
    mov %r9d, (%r8)

    lea 4(%r8), %r14
    mov %r14 , %r8
    

remove_current_r9d: #adv rax

    lea 4(%rax), %r14
    mov %r14, %rax
    jmp loopcheck

add_r10d: #add rcx value
    cmp %r11d, %r10d
    jz remove_current_r10d
    mov %r10d, (%r8)

    lea 4(%r8),%r14
    mov %r14, %r8

remove_current_r10d: #adv rcx
    lea 4(%rcx), %r14
    mov %r14, %rcx
    jmp loopcheck


rest_of_array2: #adding the rest of array 2 once array 1 is finished
    testl %r10d, %r10d
    jz end
    cmp %r10d,%r11d
    jz finish_loop2
    movl %r10d, (%r8)

    lea 4(%r8),%r14
    mov %r14, %r8

finish_loop2:
    lea 4(%rcx), %r14
    mov %r14 ,%rcx

    movl (%rcx), %r10d 
    movl (%r8), %r11d

    jmp rest_of_array2



rest_of_array1: #adding the rest of array 1 once array 2 is finished
    testl %r9d,%r9d
    jz end
    cmp %r9d,%r11d
    jz finish_loop1
    movl %r9d, (%r8)

    lea 4(%r8),%r14
    mov %r14, %r8

finish_loop1:
    lea 4(%rax),%r14
    mov %r14 ,%rax

    movl (%rax), %r9d 
    movl (%r8), %r11d

    jmp rest_of_array1


end: #ennd
    xor %r14,%r14
    mov %r14, (%r8)
    

Solution

  • I tried to compare the value I have in the original array to the value I have in the new array, and then skip it if they are the same.

    But after running some tests, it seems that adding, or removing that comparison makes no difference to the code.

    A logical error

    "the value I have in the new array" is not quite what you are using right now in your program! The (thrice-occurring) instruction movl (%r8), %r11d does read from the memory that is reserved for the destination array, but does so on a part of the array that hasn't been written to yet. In essence, the %R11D register continually gets assigned garbage, or if you're lucky, you get the zeroes that originally populated the .BSS section of the program.

    Follow these next steps precisely:


    end: #ennd
        xor %r14,%r14
        mov %r14, (%r8)
    

    array1 and array2 contain dwords and are terminated by a final 0 which also is a dword.
    So, instead of ending mergedArray with a qword 0, have it terminate with a dword 0.

    xor  %r14d, %r14d
    mov  %r14d, (%r8)