【问题标题】:Sorting a list through a procedure in flat assembly通过平面装配中的过程对列表进行排序
【发布时间】:2020-12-16 10:21:06
【问题描述】:

我对 fasm 还很陌生,而且我最近才开始学习程序。我的问题是我有一个 proc,我希望它以某种方式对我的列表进行排序。但是当我运行我的代码时,它似乎只是从内存中对一些随机数进行排序。我不太清楚为什么会这样,我将不胜感激。 代码如下:

format PE gui 5.0
include 'D:\Flat Assembler\INCLUDE\win32a.inc'
entry start

section '.data' data readable writable
    mas1 dw 2, -3, 1, -1, 3, -2, 5, -5, -4, 4

    N = ($ - mas1) / 2
    numStr db N dup('%d  '), 0

    strStr db '%s', 0
    undefStr db 'undefined', 0
    buff db 50 dup(?)
    Caption db 'Result', 0


section '.code' code readable executable
start:

stdcall bubble, mas1

cinvoke wsprintf, buff, numStr
invoke MessageBox, 0, buff, Caption, MB_OK + MB_ICONINFORMATION
invoke ExitProcess, 0


proc bubble, mas:word
    mov ecx, 0
    mov ebx, 0

    outerLoop:
            cmp ecx, 10
            je done
            mov ebx, 2

    innerLoop:
            mov eax, 0
            mov edx, 0

            cmp [mas+ebx], 0 ;if(mas[j] > 0)
            jge continue     ;continue

            mov ax, [mas+ebx-2]

            cmp ax, [mas+ebx]
            jle continue
                mov dx, [mas+ebx]
                mov [mas+ebx-2], dx
                mov [mas+ebx], ax

            continue:
            cmp ebx, 18 ;10
            je innerDone
            add ebx, 2 ;inc ebx
            jmp innerLoop

    innerDone:
            inc ecx
            jmp outerLoop

    done:
    mov ecx, 0
    mov ebx, 0
    mov ebx, 18
    mov ecx, N
    print:
           mov eax, 0
           mov ax, [mas+ebx]
           cwde
           push eax
           sub ebx, 2
           loop print

    ret
    endp

section '.idata' import data readable writeable
    library kernel32,'KERNEL32.DLL',\
            user32,'USER32.DLL'

    include 'D:\Flat Assembler\INCLUDE\API\kernel32.inc'
    include 'D:\Flat Assembler\INCLUDE\API\user32.inc'

【问题讨论】:

    标签: sorting assembly x86 proc fasm


    【解决方案1】:

    错误 1

    stdcall bubble, mas1
    ...
    proc bubble, mas:word
    

    参数mas1是一个地址,作为一个双字被压入堆栈。因此,您不应将参数 mas 限制为一个单词。
    您的 bubble 程序需要的是数组的完整地址。你可以通过mov esi, [mas] 得到这个,FASM 会像你写mov esi, [ebp+8] 一样进行编码。当使用标准序言 push ebp mov ebp, esp 时,EBP+8 是第一个参数(在您的程序中也是唯一的参数)所在的位置。

    错误 2

    在您的 bubble 过程中,您将生成的数组推送到堆栈中,希望 wsprintf 从那里使用它,但是一旦 bubble 过程执行其 ret指令,结尾代码以及 ret 指令本身将开始吃掉你的数组甚至返回到内存中的错误地址!
    如果你要返回一个数组通过堆栈,然后将其存储在返回地址和参数之上。这就是为什么我在下面的程序中写道:

    sub esp, N*4                  ; Space for N dwords on the stack
    stdcall bubble, mas1
    

    错误 3

    cmp [mas+ebx], 0 ;if(mas[j] > 0)
    jge continue     ;continue
    

    您的 BubbleSort 错误,因为您不允许比较正数!
    此外,您进行了太多迭代,这些迭代也持续了太长时间。


    我在 FASM 1.71.22 上测试了以下程序不要忘记更改路径!

    format PE gui 5.0
    include 'C:\FASM\INCLUDE\win32a.inc'
    entry start
    
    section '.data' data readable writable
        mas1 dw 2, -3, 1, -1, 3, -2, 5, -5, -4, 4
        N = ($ - mas1) / 2
    
        numStr db N-1 dup('%d, '), '%d', 0
        ;strStr db '%s', 0
        ;undefStr db 'undefined', 0
        buff db 50 dup(?)
        Caption db 'Result', 0
    
    
    section '.code' code readable executable
    start:
    
    sub esp, N*4                  ; Space for N dwords on the stack
    stdcall bubble, mas1
    
    cinvoke wsprintf, buff, numStr
    invoke MessageBox, 0, buff, Caption, MB_OK + MB_ICONINFORMATION
    invoke ExitProcess, 0
    
    
    proc bubble uses ebx esi, mas
    
        mov   esi, [mas]          ; Address of the array
        mov   ecx, (N-1)*2        ; Offset to the last item; Max (N-1) compares
    
      outerLoop:
        xor   ebx, ebx
    
      innerLoop:
        mov   ax, [esi+ebx]
        mov   dx, [esi+ebx+2]
        cmp   ax, dx
        jle   continue
        mov   [esi+ebx+2], ax
        mov   [esi+ebx], dx
      continue:
        add   ebx, 2
        cmp   ebx, ecx
        jb    innerLoop
    
        sub   ecx, 2
        jnz   outerLoop
    
        mov   ebx, (N-1)*2
      toStack:
        movsx eax, word [esi+ebx]
        mov   [ebp+12+ebx*2], eax
        sub   ebx, 2
        jnb   toStack
    
        ret
        endp
    
    section '.idata' import data readable writeable
        library kernel32,'KERNEL32.DLL',\
                user32,'USER32.DLL'
    
        include 'C:\FASM\INCLUDE\API\kernel32.inc'
        include 'C:\FASM\INCLUDE\API\user32.inc'
    

    重访错误 2

    如果您的 bubble 过程没有修改原始数组,IMO 通过堆栈返回结果数组会更有意义。
    但是在您当前的代码中,您这样做了,所以...
    一旦你从 bubble 过程中敲击了 toStack sn-p,你就可以简单地(在从 bubble 过程返回之后)推动 word-sized将数组元素作为双字放入堆栈,然后使用wsprintf。

      ...
    
    start:
      stdcall bubble, mas1
      mov   ebx, (N-1)*2
    toStack:
      movsx eax, word [mas1+ebx]
      push  eax
      sub   ebx, 2
      jnb   toStack
      cinvoke wsprintf, buff, numStr
    
      ...
    
      sub   ecx, 2
      jnz   outerLoop
      ; See no more toStack here!
      ret
    endp
    
      ...
    

    【讨论】:

    • 这很有帮助,谢谢。然而,我的冒泡程序并没有“错误”。它需要跳过所有正数,这样它们就不会被排序。那是故意的。否则,很好的回应,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2020-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-09
    • 2012-06-13
    • 1970-01-01
    相关资源
    最近更新 更多