【问题标题】:Insertion sort not functioning - 32bit assembly插入排序不起作用 - 32 位程序集
【发布时间】:2015-01-23 11:16:53
【问题描述】:

我正在尝试使用 NASM 在 linux 的 32 位程序集中实现插入排序,但出现了问题。 代码如下:

section .rodata
MSG:    DB  "welcome to sortMe, please sort me",10,0
S1: DB  "%d",10,0 ; 10 = '\n' , 0 = '\0' 

section .data

array   DD 5,1,7,3,4,9,12,8,10,2,6,11   ; unsorted array
len DB 12   

section .text
    align 16
    global main
    extern printf

main:
    push MSG    ; print welcome message
    call printf
    add esp,4   ; clean the stack 

    call printArray ;print the unsorted array

    ;parameters
    ;push len
    ;push array
    mov eax, len
    mov ebx, array
    push eax
    push ebx

    call myInsertionSort
    call printArray

    mov eax, 1  ;exit system call
    int 0x80

printArray:
    push ebp    ;save old frame pointer
    mov ebp,esp ;create new frame on stack
    pusha       ;save registers

    mov eax,0
    mov ebx,0
    mov edi,0

    mov esi,0   ;array index
    mov bl, byte [len]
    add edi,ebx ; edi = array size

print_loop:
    cmp esi,edi
    je print_end
    push dword [array+4*esi]
    push S1
    call printf
    add esp, 8  ;clean the stack
    inc esi
    jmp  print_loop
print_end:
    popa        ;restore registers
    mov esp,ebp ;clean the stack frame
    pop ebp     ;return to old stack frame
    ret

myInsertionSort:
    push ebp
    mov ebp, esp
    push ebx
    push esi
    push edi
    mov ecx, [ebp+12]
    movzx ecx, byte [ecx]   ;put len in ecx, our loop variable
    mov eax, 4 ; size of one spot in array, one byte
    mov ebx, 0
    mov esi, [ebp+8] ; the array
    loop loop_1
    loop_1:
        cmp eax, ecx ; if we're done
        jge done_1 ; then done with loop
        push ecx ; we save len, because loop command decrements ecx
        mov ecx, [esi+eax] ; ecx now array[i]
        mov ebx, eax
        shr ebx, 2 ; number of times for inner loop
        loop_2:
            cmp ebx, 0 ; we don't use loop to not affect ecx so we use ebx and compare it manually with 0
            jl done_2
            cmp [esi+ebx], ecx ;we see if array[ebx] os ecx so we can exit the loop
            jle done_2
            lea edx, [esi+ebx]
            push dword [edx] ; pushing our array[ebx]
            add edx, eax
            pop dword [edx] ; poping the last one
            dec ebx ; decrementing the loop iterator
            jmp loop_2 ; looping again
        done_2:
            mov [esi+ebx+1], ecx
            inc eax ; incrementing iterator
            pop ecx ; len of array to compare now to eax and see if we're done
            jmp loop_1
    done_1:
        pop edi
        pop esi
        pop ebx
        pop ebp ; we pop them in opposite to how we pushed
        ret

程序的输出是:

welcome to sortMe, please sort me
5
1
7
3
4
9
12
8
10
2
6
11

到现在都是未排序的数组,然后程序输出:

327681
1280
0
5
4
9
12
8
10
2
6
11

任何线索为什么会发生?哪里有问题?我经历了gdb,但不清楚为什么数组如下。是分拣问题还是印刷问题?

【问题讨论】:

  • 您需要在print_loop 中将指针增加4,因为这是一个双字的大小。实际上,出于同样的原因,在您的代码中最好使用push dword [array+4*esi]
  • @Jester 谢谢!但是现在输出很奇怪,它没有排序(?)
  • 您的评论说print the unsorted array,确实这就是您正在做的事情......那么您为什么希望它被排序? :)
  • @Jester 实际上我确实再次打印了数组,我在这里再次修改了代码以便它适合。输出也更新了。
  • 您在排序中至少有与打印中相同的问题,您没有按 4 缩放。除此之外,使用 gdb 单步执行您的代码,看看它在哪里偏离了您的意图。

标签: assembly 32-bit insertion-sort


【解决方案1】:

在你 call myInsertionSort 之后,你仍然需要使用 add esp,8 清理堆栈!
exit 系统调用 也使用 EBX。

是排序问题还是打印问题?打印工作正常,但您可以稍微清理一下代码。
不需要经典的 prolog/epilog,清除 EAX 也没用。 在 printArray 中将 pusha/popa 更改为 pushad/popad

我认为 myInsertionSort 的代码有点无法挽救。这是我的插入排序版本:

myInsertionSort:
 pushad                  ;This uses 32 bytes on the stack
 mov     ebp,esp
 mov     ebx,[ebp+32+4]  ;Address of array
 mov     ecx,[ebp+32+8]  ;Address of len
 movzx   ecx,byte [ecx]  ;len
 sub     ecx,1
 jbe     .exit           ;Nothing to sort
 xor     edi,edi         ;Index of candidate
.start:
 inc     edi 
 mov     eax,[ebx+edi*4] ;Value of candidate
 xor     esi,esi         ;Index within the underlying elements
.find:
 cmp     [ebx+esi*4],eax
 jg      .insert
 add     esi,1
 cmp     esi,edi
 jb      .find
 jmps    .next           ;No insertion needed
.insert:
 xchg    [ebx+esi*4],eax
 add     esi,1
 cmp     esi,edi
 jb      .insert
 mov     [ebx+esi*4],eax
.next:
 cmp     edi,ecx
 jb      .start
.exit:
 popad
 ret

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多