Bernard Aybouts - Blog - MiltonMarketing.com

FAQ: How to utilize the bubble sort on machine code/assembly language?

FAQ

Approx read time: 11.3 min.

Writing a bubble sort algorithm directly in machine language can be quite complex and varies significantly based on the specific architecture (e.g., x86, ARM) you’re targeting. Machine language is the lowest level of code, consisting of binary or hexadecimal instructions executed directly by a computer’s CPU.

Instead, it’s more common to write algorithms in a high-level programming language (such as Python, C, or Java) or even in assembly language, which is one step closer to machine language but still more readable than raw binary or hexadecimal codes. Assembly language is then translated into machine language via an assembler.

If you’re interested in implementing bubble sort in assembly language for educational purposes, I  provide an example in a more common assembly language, like x86 assembly, which you could then study or modify for your specific needs. Assembly language allows you to understand the mechanics of bubble sort at a low level without dealing with the direct binary encoding of machine language.

Bubble Sort in Assembly for x86 and ARM CPUs – How to utilize the bubble sort on machine code/assembly language?

x86 Assembly Example (Intel Architecture)

section .data
    array db 9, 2, 8, 3, 7, 4, 6, 1, 5 ; Example array
    len equ $ - array                 ; Length of the array

section .text
global _start

_start:
    mov ecx, len
    dec ecx
    outer_loop:
        push ecx
        mov ecx, len
        dec ecx
        inner_loop:
            mov al, [array + ecx]
            cmp al, [array + ecx - 1]
            jge skip
            xchg al, [array + ecx - 1]
            mov [array + ecx], al
            skip:
            loop inner_loop
        pop ecx
        loop outer_loop

    ; Exit (to Linux)
    mov eax, 1          ; syscall: exit
    xor ebx, ebx        ; status 0
    int 0x80

Let’s break down the x86 assembly code example I provided earlier, line by line. This explanation will give you insights into how assembly code operates on a low level, directly interfacing with the computer’s hardware. This code was designed to sort an array using the Bubble Sort algorithm.

x86 Assembly Code Explanation

assembly
section .data
  • Defines the data section, where initialized data is stored. This section is used for declaring constants or variables that do not change at runtime.
assembly
array db 9, 2, 8, 3, 7, 4, 6, 1, 5 ; Example array
  • Declares an array of bytes (db stands for ‘define byte’). This is our unsorted array which the Bubble Sort algorithm will sort.
assembly
len equ $ - array ; Length of the array
  • Calculates the length of the array by subtracting the start address of the array from the current location ($ symbol) in the data section.
assembly
section .text
  • Defines the text section, where the executable code is placed. This is the section for assembly instructions.
assembly
global _start
  • Makes the _start label globally visible, which is necessary for the linker to identify the entry point of the program. This is where execution begins.
assembly
_start:
  • Label marking the start of the program’s execution.
assembly
mov ecx, len
  • Moves the length of the array into the ECX register, which will be used as a counter for the outer loop.
assembly
dec ecx
  • Decrements ECX by 1 because the Bubble Sort algorithm needs to iterate one less than the number of elements in the array for each pass.
assembly
outer_loop:
  • Label for the beginning of the outer loop of the Bubble Sort algorithm.
assembly
push ecx
  • Pushes ECX onto the stack to save its current value for later use in the inner loop.
assembly
mov ecx, len
  • Re-initializes ECX with the length of the array for the inner loop.
assembly
dec ecx
  • Prepares ECX for the inner loop by decrementing it, ensuring the inner loop does not compare beyond the array’s bounds.
assembly
inner_loop:
  • Label for the beginning of the inner loop where the actual comparison and possible swap of elements occur.
assembly
mov al, [array + ecx]
  • Moves the byte at [array + ECX] into AL, the lower byte of the AX register. This instruction gets the current element for comparison.
assembly
cmp al, [array + ecx - 1]
  • Compares the current element (AL) with the previous element in the array. The CMP instruction sets flags based on the comparison.
assembly
jge skip
  • Jumps if greater or equal based on the comparison. If the current element is greater than or equal to the previous one, it skips the swap operation.
assembly
xchg al, [array + ecx - 1]
  • Exchanges the current element with the previous one if the current element is less than the previous one. This is the swap operation.
assembly
mov [array + ecx], al
  • Moves the value in AL back into the array at the current position, completing the swap if it occurred.
skip:
  • Label for skipping the swap operation if the current element is in the correct order relative to the previous element.
loop inner_loop
  • Decrements ECX and loops back to the inner_loop label if ECX is not zero. This continues the inner loop until all elements for this pass are compared.
assembly
pop ecx
  • Pops the saved value of ECX off the stack to restore it for the next pass of the outer loop.
assembly
loop outer_loop
  • Decrements ECX and loops back to the outer_loop label if ECX is not zero. This continues the outer loop until the array is sorted.
assembly
mov eax, 1 ; syscall: exit
xor ebx, ebx ; status 0
int 0x80
  • Exits the program. This sequence of instructions performs a system call to exit the program. mov eax, 1 sets up the system call number for exit. xor ebx, ebx sets the exit status to 0, indicating success. int 0x80 triggers the system call.

This code provides a basic illustration of sorting an array using the Bubble Sort algorithm in x86 assembly language, showcasing direct manipulation of memory and registers to perform sorting operations.



ARM Assembly Example – How to utilize the bubble sort on machine code/assembly language?

    .section .data
array:  .byte 9, 2, 8, 3, 7, 4, 6, 1, 5
len = . - array

    .section .text
    .globl _start

_start:
    ldr r4, =len
    subs r4, r4, #1
outer_loop:
    push 
    ldr r4, =len
    subs r4, r4, #1
inner_loop:
    ldrb r2, [r0, r4]
    subs r3, r4, #1
    ldrb r1, [r0, r3]
    cmp r2, r1
    strhs r1, [r0, r4]
    strhs r2, [r0, r3]
    subs r4, r4, #1
    bne inner_loop
    pop 
    subs r4, r4, #1
    bne outer_loop

    /* Exit (to Linux) */
    mov r0, #0
    ldr r7, =1
    swi 0

Let’s break down the ARM assembly code example provided earlier, line by line. This explanation will help you understand how this assembly code operates, specifically targeting the ARM architecture and using the Bubble Sort algorithm to sort an array.

ARM Assembly Code Explanation

assembly
.section .data
  • Defines the data section where initialized data, such as constants and arrays, are stored. This is used for declaring data that the program will use.
assembly
array: .byte 9, 2, 8, 3, 7, 4, 6, 1, 5
  • Declares an array with the .byte directive, initializing it with a series of numbers. This is the array that will be sorted.
assembly
len = . - array
  • Calculates the length of the array by subtracting the starting address of the array from the current location (denoted by .). This provides the size of the array for loop control.
assembly
.section .text
  • Defines the text section, where the executable code resides. This section contains the assembly instructions that make up the program.
assembly
.globl _start
  • Specifies the global label _start, indicating the entry point of the program. This is where execution begins when the program is run.
assembly
_start:
  • Marks the beginning of the executable code. This label is essential as it is where execution starts.
assembly
ldr r4, =len
  • Loads the length of the array into register r4. The ldr instruction is used here to load the address or value into a register. In this case, it’s loading the size of the array for loop control.
assembly
subs r4, r4, #1
  • Subtracts 1 from the value in r4. The subs instruction subtracts the second and third operands (here, r4 and 1), stores the result in the first operand (r4), and updates the condition flags based on the result.
assembly
outer_loop:
  • Label for the beginning of the outer loop of the Bubble Sort algorithm.
assembly
push
  • Pushes the value of r4 onto the stack. This saves the current counter value so it can be restored later, allowing for nested looping.
assembly
ldr r4, =len
subs r4, r4, #1
  • Re-initializes r4 for the inner loop, similar to the previous initialization but repeated to ensure the inner loop has the correct starting value.
assembly
inner_loop:
  • Label for the beginning of the inner loop, where the comparison and potential swapping of array elements happen.
assembly
ldrb r2, [r0, r4]
  • Loads a byte from the array into r2. The ldrb instruction loads a single byte from the address calculated by adding r0 (which should hold the base address of the array) and r4 into register r2.
assembly
subs r3, r4, #1
  • Calculates the address of the previous element by subtracting 1 from r4 and storing the result in r3.
assembly
ldrb r1, [r0, r3]
  • Loads the previous byte (element) into r1 for comparison with the current element (r2).
assembly
cmp r2, r1
  • Compares the values in r2 and r1. The cmp instruction compares two registers and sets the condition flags accordingly without storing the result.
assembly
strhs r1, [r0, r4] strhs r2, [r0, r3]
  • Conditionally swaps the elements if r2 (current element) is higher than r1 (previous element). strhs (store halfword if higher or same) instructions conditionally execute based on the result of the last comparison, swapping the elements if necessary.
assembly
subs r4, r4, #1
  • Decrements the loop counter (r4) to move through the array.
assembly
bne inner_loop
  • Branches to inner_loop if not equal to zero. The bne instruction causes the program to loop back to the inner_loop label if the zero flag is not set, indicating that there are more elements to process.
assembly
pop
  • Pops the saved value of r4 off the stack. This restores the outer loop counter from the stack, preparing for the next iteration of the outer loop.
assembly
subs r4, r4, #1
bne outer_loop
  • Continues the outer loop if not completed. The loop counter is decremented, and if it’s not zero, the program branches back to outer_loop.
assembly
mov r0, #0
ldr r7, =1
swi 0
  • Exits the program. This sets up for a system call to exit the program. mov r0, #0 sets the exit status to 0 (success), ldr r7, =1 loads the system call number for exit into r7, and swi 0 invokes the system call interrupt.

This breakdown explains the ARM assembly code’s operation for sorting an array using the Bubble Sort algorithm, demonstrating the direct hardware manipulation characteristic of assembly language programming.

Compiling and running assembly code involves several steps, largely dependent on the specific CPU architecture (e.g., x86 or ARM) and the operating system you’re using. Here’s a general overview of how this process works:

1. Writing the Code

First, you write your assembly code in a text editor and save it with an appropriate extension (e.g., .asm for NASM).

2. Compiling the Code

Assembly code is typically assembled (rather than compiled in the traditional sense) into machine code using an assembler like NASM (Netwide Assembler) for x86 architecture or GAS (GNU Assembler) for ARM. The assembler translates your assembly language instructions into machine code.

  • For x86 using NASM:
    nasm -f elf64 yourcode.asm -o yourcode.o

    This command generates an object file (yourcode.o). The -f elf64 option tells NASM to output in the ELF 64-bit format, suitable for x86-64 Linux systems.

  • For ARM: The process is similar, but you’d use an assembler that supports ARM instructions, possibly using a cross-assembler if you’re compiling on a non-ARM machine.

3. Linking

After assembling, you need to link the object file(s) to create an executable. This step involves resolving addresses for any external references and libraries your code might use (though, in many assembly programs, external references are minimal).

  • Using ld (the GNU linker):
    ld yourcode.o -o yourcode

    This creates an executable file from your object file.

4. Running the Executable

Once you have your executable, you can run it directly from the terminal in Linux:

./yourcode

How Does It Work Internally?

  • Loading: When you execute the program, the operating system loads it into memory.
  • Execution: The CPU reads the machine code instructions from the entry point specified in the executable file. For assembly programs, this often directly corresponds to the start of your _start label or equivalent.
  • Instruction Processing: The CPU executes each instruction sequentially unless instructed otherwise by control flow instructions (e.g., jumps, calls). The instructions perform operations such as moving data between registers, performing arithmetic operations, or interacting with memory.
  • System Calls: For operations like input/output or exiting the program, your assembly code makes system calls to the operating system kernel.
  • Termination: Once the program reaches its termination point (often a system call to exit), control is returned to the operating system, and the program’s memory is freed.

The direct nature of assembly language programming allows for precise control over the hardware but requires a detailed understanding of the CPU architecture and the operating system’s conventions for things like system calls.

Leave A Comment


About the Author: Bernard Aybout (Virii8)

Avatar of Bernard Aybout (Virii8)
I am a dedicated technology enthusiast with over 45 years of life experience, passionate about computers, AI, emerging technologies, and their real-world impact. As the founder of my personal blog, MiltonMarketing.com, I explore how AI, health tech, engineering, finance, and other advanced fields leverage innovation—not as a replacement for human expertise, but as a tool to enhance it. My focus is on bridging the gap between cutting-edge technology and practical applications, ensuring ethical, responsible, and transformative use across industries. MiltonMarketing.com is more than just a tech blog—it's a growing platform for expert insights. We welcome qualified writers and industry professionals from IT, AI, healthcare, engineering, HVAC, automotive, finance, and beyond to contribute their knowledge. If you have expertise to share in how AI and technology shape industries while complementing human skills, join us in driving meaningful conversations about the future of innovation. 🚀