2

I am trying to implement bubble sort in assembly. Here is my code. I keep getting segmentation fault. I have a function down below. I have been trying to figure this out but I couldn't find a compiler for x86 and I have been checking with my code to check what is wrong but to no avail.

here is my function code:

bubble:
    push ebp
    mov ebp, esp

    push ecx
    push edx
    push edi
    push esi
    push ebx
    push eax
    
   
    mov eax, 0
    mov ecx, [ebp+12] ; number of elements in the array
    mov edx, [ebp+8]; address of array
    mov edi, 0
    mov esi, 0
    dec ecx; n - 1

    mov esi, 1

    sortOuter:
        cmp esi, 0
        jg sort

        sort:

        mov esi, 0 ;count

        check:
        cmp edi, ecx ; i < n - 1
        jl sortInner

        sortInner:
            mov ebx, [edx+edi*4] ; mov array[i+1] to ebx
            cmp [edx], ebx   ; cmp array[i] to array[i+1]
            jle noswap

            swap:
                mov eax, ebx ; mov array[i+1] to eax
                mov ebx, [edx] ; mov array[i] to array[i+1]
                mov [edx], eax ; mov array[i+1] to array[i]
                
                inc esi ; count++

            noswap:

            inc edi ; i++
            jmp check
    
        
        jmp sortOuter

    done:


    call print_nl


    pop ebx
    pop esi
    pop edi
    pop edx
    pop ecx

    
    mov esp, ebp
    pop ebp
    ret
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
Rheagar
  • 31
  • 4
  • On which instruction? What values were in registers when it crashed inside your debugger? (See https://stackoverflow.com/tags/x86/info for asm GDB tips). If you want to look at compiler output for asm examples, https://godbolt.org/ has compilers for many languages including C, targeting your choice of x86, ARM, RISC-V, and some others, see [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116) for tips on using it to make asm that's interesting to look at. e.g. for 32-bit code, `gcc -m32 -Og` – Peter Cordes Nov 18 '22 at 10:02
  • I think you have a misunderstanding of how conditional jumps work. When you do `jg sort`, if the "greater" condition is true, the jump is taken and execution continues at the instruction marked by the `sort:` label, which is `cmp esi, 0`. If the condition is false, the jump is not taken and execution continues with the instruction immediately after the jump, which is **also** `cmp esi, 0`. The fact that this instruction happens to be marked with a label does not alter that latter behavior in any way. So `jg sort` does not actually change execution at all. – Nate Eldredge Nov 19 '22 at 02:59
  • You seem to be thinking that assembly is a block-structured language, and that conditional jumps are an exact replacement for `if/then/else` structures. They are not. You can *use* them to execute code conditionally, but one of the branches will always be the code immediately after the conditional jump. – Nate Eldredge Nov 19 '22 at 03:01
  • (This seems to be a common beginner mistake. I wonder if we have a canonical duplicate question for it.) – Nate Eldredge Nov 19 '22 at 03:01
  • 1
    I also note that you are indenting bits of code as if they are blocks. That will only confuse you. Execution in x86 assembly is either straight-line or "goto", nothing else. – Nate Eldredge Nov 19 '22 at 03:03
  • 1
    @NateEldredge: We have [Code executes condition wrong?](https://stackoverflow.com/q/32872539) in https://stackoverflow.com/tags/x86/info. I find it in the tag wiki with a search for "fall through" when I'm looking for it. It's also right below the FAQ links for [What if there is no return statement in a CALLed block of code in assembly programs](https://stackoverflow.com/q/41205054) where my answer spends more time on the idea of fall-through and the CPU always executing the next instruction in memory regardless of labels, although Mike's answer on the first does make that point succinctly. – Peter Cordes Nov 19 '22 at 03:51

1 Answers1

2

The segmentation error comes from the infinite loop that you have created with

check:
  cmp edi, ecx ; i < n - 1
  jl sortInner

  sortInner:

If EDI is less than ECX you jump to sortInner, but if it isn't you fall-through into sortInner. No matter, you always end up running the code at sortInner and because the memory addresses that the code uses keep growing, at some point you will be trying to read memory that you don't have access to, hence the segmentation error.

Now if you were to correct this, then there's a second infinite loop waiting.

sortOuter:
  cmp esi, 0
  jg sort

  sort:

Other errors include:

  • Resetting ESI instead of EDI at the start of the inner loop
  • Not swapping elements at all but always writing the smallest value in the first array element
  • Forgetting to restore the register EAX

This is a working BubbleSort. Don't just copy it, but find out how it functions!

In an array with N elements we have to do N-1 comparisons at most (to have the greatest value bubble towards the rear).
Because the InnerLoop uses a counter that gets initialized from the ever decreasing OuterLoop counter, with each iteration of the OuterLoop the portion of the array that is processed in the InnerLoop gets smaller. The portion of the array that we then no longer process contains the greatest elements that have bubbled towards the end of the array, hence the name BubbleSort.
Provisions have been made for an empty array or an array that has but 1 element. Always include some code for the special cases!

bubble:
  push ebp
  mov  ebp, esp
  push ...

  mov  ecx, [ebp + 12] ; Number of elements in the array
  sub  ecx, 1          ; First time we do n = N-1
  jbe  Done            ; Array is empty or has but 1 element

OuterLoop:
  mov  edx, ecx        ; Current value of the OuterLoop counter (n)
  mov  esi, [ebp + 8]  ; Address of array
InnerLoop:
  mov  eax, [esi]
  mov  ebx, [esi + 4]
  cmp  eax, ebx
  jng  NoSwap
  mov  [esi], ebx
  mov  [esi + 4], eax
NoSwap:
  add  esi, 4
  dec  edx
  jnz  InnerLoop
  dec  ecx                ; Next times we do n = n-1
  jnz  OuterLoop

Done:
  pop  ...
  pop  ebp
  ret
Sep Roland
  • 33,889
  • 7
  • 43
  • 76