用汇编语言对函数中的数组进行排序?

时间:2015-03-09 06:31:32

标签: assembly x86

使用选择排序算法实现一个函数(在汇编中),该函数按升序对给定的整数数组进行排序。函数的输入是arraySize和arrayOfIntegers。该函数将在排序时重新排列数组中的数字。我确定我能够计算第二个值中的最小值的索引(我已调试以检查)。但是,我不能将min和当前索引值交换。我读过类似的问题,但我似乎无法得到它 - 它已经过了3天而且我无法得到它。我对汇编语言非常陌生,并且非常感谢他们的帮助。谢谢,麻烦您了 我的交换从END_FOR_2开始:

void array_sort( int arrayOfIntegers[], int arraySize )
{
    int temp;

    __asm{
        push eax
        push ebx
        push ecx
        push edx
        push esi
        push edi

// BEGIN YOUR CODE HERE

// Note: You can safely use the 6 registers listed above as well
// as the variable temp in your code, if needed.
    mov esi, 0
    mov edi, 0
    mov ecx, 0
    mov eax, 0
    mov ebx, arrayOfIntegers
    mov edx, arraySize
    dec edx
FOR_1:
    cmp esi, edx
    jg END_FOR_1
    mov edi, esi
FOR_2:
        inc esi
        mov eax, esi
        dec esi
    WHILE_2:
        cmp eax, arraySize
        jge END_FOR_2
        IF_1:
            mov ecx, dword ptr [ebx + eax*4]
            cmp ecx, dword ptr [ebx + edi*4]
            jg END_IF_1
            mov edi, eax
        END_IF_1:
            inc eax
            jmp WHILE_2
END_FOR_2:
    mov eax, dword ptr[ebx + 4*edi]
    mov ecx, dword ptr[ebx + 4*esi]
    IF_2:
        cmp edi, esi
        je END_IF_2
            mov temp, ecx
            mov ecx, dword ptr[ebx + 4*edi]
            mov eax, temp
    END_IF_2:
        inc esi
        jmp FOR_1

END_FOR_1:

// END YOUR CODE HERE

   pop edi
   pop esi
   pop edx
   pop ecx
   pop ebx
   pop eax
}
}

1 个答案:

答案 0 :(得分:0)

如果代码中没有任何评论,那么任何人都需要做很多工作来弄清楚你使用每个寄存器的内容。

IF_2中的实际错误就像它一样。您将刚刚找到的最小值eax和下一个要排序的位置([ebx + 4*esi])的值加到ecx中。然后你有一些愚蠢的代码写入然后从temp读取,而不必写入数组中的任何一个位置。这应该有效:

# IF_2:
# cmp edi, esi  # more efficient to just unconditionally do stuff
# je END_IF_2
mov eax, dword ptr[ebx + 4*edi]  # or this value is already in ebp from the search loop
mov ecx, dword ptr[ebx + 4*esi]
mov dword ptr[ebx + 4*edi], ecx  # exchange values
mov dword ptr[ebx + 4*esi], eax
# END_IF_2:

其他一些显而易见的事情:

  • 通过xor将其归为自身,而不是使用即时数据的mov insn,将效果归零会更有效。
  • 要获取eax = esi + 1,请执行mov eax, esiinc eax。或lea eax, [1+esi]。不是inc / mov / dec

我认为你的WHILE_2会扫描数组其余部分中的最小元素。最好将当前最小值保留在寄存器中,而不是每次都使用dword ptr [ebx + edi*4]作为cmp的输入。所以你的循环可能是

    mov ebp, dword ptr [ebx + edi*4]  # ebp = current min
    WHILE_2:
    inc eax
    cmp eax, arraySize
    jge END_FOR_2
    mov ecx, [ebx + eax*4]
    cmp ebp, ecx
    jg WHILE_2  # go to next iteration
    # IF_1: if (arr[cur] < min) { minpos = cur; min=arr[cur]; }
        mov edi, eax  # new minpos
        mov ebp, ecx  # new minval
    END_IF_1:
    jmp WHILE_2

请注意,eax在与以前不同的地方递增,我使用了ebp。这允许重组在共同路径上放少一条指令(无条件jmp)。

如果你不能使用ebp(比如你需要使用帧指针进行编译),那么将不同的值溢出到内存中,并在循环后重新加载它。或者只写64位代码,因为它是2015年以及唯一不能在64位模式下运行的x86 CPU超过10年。 (甚至Atom CPU现在都支持64位)。但无论如何,如果你的寄存器用尽了,那么很少将一些常用的内容泄漏到内存中,而不是每次都通过紧密循环使用的值。

另外,我可能编写了循环来增加指针,而不是使用索引寻址模式。 minpos可以是指针而不是偏移量。然后,您不需要在ebx中保留基址,以及两个索引。