这个 x86 汇编冒泡排序程序有啥问题?

Posted

技术标签:

【中文标题】这个 x86 汇编冒泡排序程序有啥问题?【英文标题】:What is wrong with this x86 assembly bubble sort program?这个 x86 汇编冒泡排序程序有什么问题? 【发布时间】:2019-05-30 16:26:21 【问题描述】:

我需要弄清楚为什么在这个程序中什么都没有交换。该程序从一个单独的 C 程序中获取一个包含 4,5,1,3,2 的整数数组,并将其返回排序后。

我尝试修改了一些跳转命令,但没有任何效果。

.global myarray

.data
myarray:
    lea (%rdi),%r8      #load array to register
    mov %rsi,%r12       #load array size to register
    mov $0,%r10             #initialize index
sort:
    mov (%r8, %r10, 8), %rax    #store array[i] in rax
    inc %r10            #i++
    mov (%r8, %r10, 8), %rdx    #store array[i+1] in rdx
    cmp %rax, %rdx      #see if rdx is less than rax
    jle swap            #if rdx < rax, swap them
swap:
    cmp %r12, %r10      #check if still in array bounds
    je  check           #if we are at the end, check if sorted
    dec %r10            #i--
    mov %rdx, (%r8, %r10, 8)    #move array[i+1] into array[i]
    inc %r10            #i++
    mov %rax, (%r8, %r10, 8)    #move array[i] into array[i+1]
    jmp     check
check:
    mov $0, %r14        #temporary index in r14
    mov (%r8, %r10, 8), %eax    #temporarily store array[i] in eax
    inc %r14            #i++            
    mov (%r8, %r10, 8), %ebx    #temporarily store array[i+1] in ebx
    cmp %eax, %ebx      #check if ebx is less than eax
    jle sort            #if ebx < eax, swap
    cmp %r12, %r14      #check if still in array bounds
    ret

预期结果是返回的数组排序; 1,2,3,4,5

【问题讨论】:

dec/inc r10 围绕内存引用作为寻址模式的一部分的位移会更简单:-8(%r8, %r10, 8)。简化代码的局部小部分可以使调试时更容易看到全局,而不会迷失在混乱中。 (使用 GDB 或任何其他调试器来单步执行您的代码。) 【参考方案1】:
mov %rsi,%r12           #load array size to register
mov $0,%r10             #initialize index

在包含 5 个元素的数组中,您只能比较 4 对。减少%r12 会很方便。同时,当数组只有 1 个元素时,您将有一条出路:

mov %rsi,%r12             #load array size to register
dec %r12
jz  NothingToDo
mov $0,%r10               #initialize index
cmp %rax, %rdx          #see if rdx is less than rax
jle swap                #if rdx < rax, swap them
swap:

如果 LessOrEqual 跳转到 swap,否则代码在 swap 中通过。这毫无意义!

下面是使最大数字冒泡到顶部的代码。

sort:
    mov (%r8, %r10, 8), %rax    #store array[i] in rax
    inc %r10                    #i++
    mov (%r8, %r10, 8), %rdx    #store array[i+1] in rdx
    cmp %rdx, %rax
    jle NoSwap
    dec %r10                    #i--
    mov %rdx, (%r8, %r10, 8)    #move array[i+1] into array[i]
    inc %r10                    #i++
    mov %rax, (%r8, %r10, 8)    #move array[i] into array[i+1]
NoSwap:
    cmp %r12, %r10              #check if still in array bounds
    jb  sort

此内部循环代码必须重复多次,但每次您降低%r12 中的限制。 (*)

jmp     check
check:

这也是个没用的jmp

check:
mov $0, %r14        #temporary index in r14
mov (%r8, %r10, 8), %eax    #temporarily store array[i] in eax
inc %r14            #i++            
mov (%r8, %r10, 8), %ebx    #temporarily store array[i+1] in ebx
cmp %eax, %ebx      #check if ebx is less than eax
jle sort            #if ebx < eax, swap
cmp %r12, %r14      #check if still in array bounds

而且这部分代码无法挽救。这里发生的事情令人无法理解。


(*)

    mov     %rdi,%r8
    mov     %rsi,%r12
    dec     %r12
    jz      NothingToDo
OuterLoop:
    mov     $0,%r10
    ...
    dec     %r12
    jnz     OuterLoop
NothingToDo:
    ret

【讨论】:

以上是关于这个 x86 汇编冒泡排序程序有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

有啥算法是相邻交换排序的(除了冒泡以外)

冒泡排序有啥用? [关闭]

冒泡排序

汇编实现排序——冒泡排序

组装 - 用于排序字符串的冒泡排序

汇编冒泡排序,数组题