C assembly implement bubble sort - c

I have to write a bubblesort in C with assembly implement.
My C code looks like :
#include <stdio.h>
extern int arraysort(int array[],int length);
int main () {
int array[]= {7,4,3,6,2,1};
int length = 6;
printf("Unsorted array: %d,%d,%d,%d,%d,%d\n",array[0],array[1],array[2],array[3],array[4],array[5]);
arraysort(array,length);
printf("Sorted array: %d,%d,%d,%d,%d,%d\n",array[0],array[1],array[2],array[3],array[4],array[5]);
return 0;
}
And my assembly code looks like:
.intel_syntax noprefix
.text
.global arraysort
arraysort: # int sortarray(int array[],int length)
#function prologue
push ebp
mov ebp, esp
# function prologue end
push ebx # save ebx for cdecl convection
# 1.argumentum [ebp + 4*2] this is the array
# 2.argumentum [ebp + 4*3] this is the length
mov ecx, [ebp + 12] #array length (6)
dec ecx #array length (5)
mov edx, 1 #variable j
mov esi, [ebp + 8] #array address
loop1:
cmp ecx, 0 # (int i =length; i> length;i--)
jg end
loop2:
mov eax, [esi + 4*ecx] #array[0]
mov ebx, [esi + 4*edx] #array[1]
cmp eax, ebx #if eax > ebx jump to csere
jg swap
dec ecx #i--
inc edx#j++
jz end
jmp loop2
swap:
mov [esi + 4*edx], eax #change the two elements
mov [esi + 4*ecx], ebx
jmp loop2
end:
pop ebx
mov esp, ebp
pop ebp
ret
I dont know what is the problem and I struggling whit this.
If I change in the first loop jg to jl i get infinity loop :/
Sorry for my english and my assembly coding skill but I'm learning this language still.
Please help me! Thank you

Here's the main problem:
mov ecx, [ebp + 12] #array length (6)
dec ecx #array length (5)
mov edx, 1 #variable j
mov esi, [ebp + 8] #array address
loop1:
cmp ecx, 0 # (int i =length; i> length;i--)
jg end
Focus on ecx there. You're basically saying if(--length > 0) goto end;, so you're skipping the entire meat of your function.
Now once you fix that, you'll start getting a segfault. Here's why:
dec ecx #i--
inc edx#j++
jz end
That's equivalent to --i; if(!++j) goto end;. As a result, your loop is going to run way more iterations than you want (until j overflows, but in practice it will segfault first). I'm guessing you meant to switch dec ecx and inc edx, so that the loop would end when i got to 0.
Anyway, with that fixed too, your code will return an updated array, but it will still be wrong. At this point, it's just because your bubble sort is wrong and not because of any assembly-related errors, so I'll stop here.

Related

Assembly segmentation fault ( array )

beginner in assembly here (IA-32 assembly). I keep getting a seg fault when compiling in gcc, I'm guessing its attempting to access forbidden memory, but I can't pin point it down. The task was to find the greatest common denominator of an array. I figured implementing this via an array with a side function gcd (returns the gcd of 2 numbers). Here is the code:
.intel_syntax noprefix
.text
.global GCD
GCD:
push edi
push esi
mov edi, [ebp + 12] # number of elements in the array
mov esi, [ebp + 8] #array address
mov eax, [esi] # place the first element of the array into eax
mov ecx, 1 # set the counter to 1
next_number: #accumulating the gcd of the entire array
cmp ecx, edi #if the counter reaches the max number of elements,
ja end #end the the loop
push [esi + 4*ecx] #calling the gcd function, pushing the numbers on the
push eax #stack, so gcd can pick them up
call gcd
add esp, 8
inc ecx #increment the counter
jmp next_number #next iteration
end:
pop esi
pop edi
leave
ret
And the gcd side function:
# The C algorithm for finding the gcd of 2 numbers implemented in IA-32
# while(y)
# {
# r = x % y;
# x = y;
# y = r;
# }
# return x;
.intel_syntax noprefix
.text
.global gcd
gcd:
enter 0,0
mov eax, [ebp + 8]
mov ecx, [ebp + 12]
loop:
cmp ecx, 0
je end
xor edx, edx
idiv ecx
mov eax, ecx
mov ecx, edx
jmp loop
end:
leave
ret

Shellsort: Write NASM code from C

I am trying to convert a C function to NASM in 32-bit.
Here is the C function
void shellsort (int *A, int n)
{
int gap, i, j, temp;
for (gap = n/2; gap > 0; gap /=2)
{
for (i= gap; i<n; i++)
{
for (j=i-gap; j>=0 && A[j] > A[j+gap]; j-=gap)
{
temp = A[j];
A[j] = A[j+gap]
A[j+gap] = temp;
}
}
}
}
Here is what I have done so far
%include "asm_io.inc"
SECTION .data
SECTION .bss
SECTION .text
extern printf
global sort
sort:
push ebp ;set up stack frame
mov ebp, esp
sub esp, 0x10 ;assign 16byte space for local variables
firstloop:
mov eax, [ebp+8] ;moves value of n into eax
mov edx, 0 ;prepares for division, remainder init
mov ecx, 2 ;divisor
div ecx ;division, store gap in eax
cmp eax, 0 ;compare if gap with zero
jle firstloopDone ;firstloopDone
firstloopDone:
div ecx
jmp done
secondloop:
mov ecx, eax ;copy value of gap into ecx, i=gap
cmp ecx, [ebp+8] ;compare i with 1st parameter n
jge secondloopDone ;jump to secondloop if greater-equal
inc ecx ;increment i
jmp thirdloop ;jump to thirdloop
secondloopDone:
inc ecx ;increment i
jmp firstloop ;jump to firstloop
thirdloop:
mov edx, ecx ;save i value
sub ecx, eax ;subtract gap from i and store in ecx
cmp ecx, 0 ;compare j with zero
jl thirdloopDone ;if not j>=0, then skip to end of loop
cmp [ebp+12+ecx], [ebp+12+ecx+eax] ;compare A[j] and A[j+gap]
jle thirdloopDone
sub ecx, eax ;subtract gap from j and store in ecx
jmp swap
thirdloopDone:
sub ecx, eax ;j-gap
jmp secondloop ;jump to second loop
swap:
mov edx, [ebp+12+ecx] ;copy A[j] to temp
mov [ebp+12+ecx], [ebp+12+ecx+eax] ;A[j]=A[j+gap]
mov [edp+12+ecx+eax], edx ;A[j+gap]= temp
jmp thirdloop
done:
leave ;destroy stack frame
ret
Needless to say, it doesn't work.
The error message says:
"error: beroset-p-603-invalid effective address"
at line 58 (thirdloop)
cmp [ebp+12+ecx], [ebp+12+ecx+eax]
and at line 71 (swap)
mov edx, [ebp+12+ecx]
I understand that this may be the wrong method. But from the nested loop in C code, I have too many variables to keep so I cant spare any of the registers.
Also, I suspect I may not have a proper understanding of the stack frame, which may show in my code.
Any help, or bug-discovery, would be greatly appreciated. Thanks.
You say you don't have enough registers to play with but you don't even use EBX, ESI, nor EDI. You made provisions for local variables yet you don't use any.
firstloop:
mov eax, [ebp+8] ;moves value of n into eax
mov edx, 0 ;prepares for division, remainder init
mov ecx, 2 ;divisor
div ecx ;division, store gap in eax
The previous code does not need the division. Simplify it with a shift operation. shr eax,1
The next code will always terminate. Use jle done
cmp eax, 0 ;compare if gap with zero
jle firstloopDone ;firstloopDone
firstloopDone:
div ecx
jmp done
Aren't parameters pushed from right to left?
mov ebx, [ebp+8] ;pointer to array A
firstloop:
mov eax, [ebp+12] ;number of elemnets n
You would typically have to code
swap:
mov edx, [ebx+ecx*4] ;TEMP=A[j]
add ecx,eax
xchg edx, [ebx+ecx*4] ;Swap A[j+gap] with TEMP
sub ecx, eax
mov [ebx+ecx*4], edx ;A[j]=TEMP
jmp thirdloop

Assembly language Array traversal

I'm new to assembly language and I'm having trouble with some basic programming problems and I was wondering if you guys could point me in the right direction.
I'm trying to write a function that traverses through an array and sums up the values of its elements. Given given a pointer int *array and some length x.
What I've been able to do so far is write the initial data and place the initial pointer which isn't much but its a start. How would I use a loop in assembly to traverse through the array?
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
MOV EBX, array
MOV ECX, x
mov eax, 2;
mov ebx, array;
lea edx, [ebx+eax*4];
You do not need to save all of those registers. If your function uses esi, edi, ebx, ebp, then you must save them in the prologue and restore them in the epilogue. MASM can do that for you with the keyword uses
SomeProcedure proc uses esi, edi, ebx Val1:DWORD, Val2:DWORD
ret
SomeProcedure endp
Here is one way you can do it:
.686
.model flat, stdcall
option casemap :none
include kernel32.inc
includelib kernel32.lib
.data
Array dd 1, 2, 3, 4, 5, 6, 7, 8, 9
Array_Size equ ($ - Array) / 4
.code
start:
push Array_Size - 1
push offset Array
call SumArray
; eax contains sum of array
; print it out here.
push 0
call ExitProcess
SumArray:
push esi ; need to preserve esi
mov esi, [esp + 8] ; address of array
mov ecx, [esp + 12] ; size of array - 1
xor eax, eax ; holds sum
xor edx, edx ; index
AddIt:
add eax, [esi + edx * 4]
inc edx
dec ecx
jns AddIt ; is ecx ! neg repeat loop
pop esi
ret
end start

Intel 8086 Insertion Sort: Skipping numbers within the Array

So we're currently studying Intel 8086 Insertion Sort Code that our professor showed us. He wanted us to figure out why the code skips the 0th element within the array and the 3rd element in the array from a code that he had taken from the web.
; void isort(int *a, int n)
; sorts the first n elements of a
;
; Parameters
; a - pointer to the array
; n - number of elements to sorts
%define a [ebp + 8]
%define n [ebp + 12]
isort:
enter 0, 0
pusha
mov ecx, 1
for:
mov ebx, ecx
imul ebx, 4
add ebx, a
mov ebx, [ebx]
mov edx, ecx
dec edx
while:
cmp edx, 0
jl while_quit
mov eax, edx
imul eax, 4
add eax, a
cmp ebx, [eax]
jge while_quit
mov esi, [eax]
mov dword [eax + 4], esi
dec edx
jmp while
while_quit:
mov [eax], ebx
inc ecx
cmp ecx, n
jl for
popa
leave
ret
And the sample array was {5, 8, 12, 2, 1, 7}. This is more for understanding the 8086 language since we just started a couple days ago, and I was wondering if anyone could explain how and what might be going wrong.
Consider what the code will do when ECX is 1:
The while loop will be entered with EBX=8 and EDX=0.
The jl while_quit will not be taken, since EDX is 0.
EBX is compared to [EAX]. That is; 8 is compared to a[0], which is 5, so the jge while_quit is taken.
mov [eax], ebx stores 8 at a[0], so your array now contains {8,8,12,2,1,7}. Clearly not what you want, since you've lost one of the original elements.
Apart from the code's logical flaw, those imul instructions are completely unnecessary since you can use scaled indices on the x86. So the sorting code can be simplified to this (I've verified that it sorts the array correctly):
mov ecx, 1
for_:
; esi = &a[holePos]
lea esi,[a + ecx*4]
; valueToInsert = a[holePos]
mov ebx, [esi]
while_:
; Did we reach the beginning of the array?
cmp esi, OFFSET a
jle while_quit
; valueToInsert < a[holePos-1] ?
cmp ebx, [esi-4]
jge while_quit
; a[holePos] = a[holePos-1]
mov eax, [esi-4]
mov [esi], eax
; esi = &a[holePos-1]
sub esi,4
jmp while_
while_quit:
; a[holePos] = valueToInsert
mov [esi], ebx
inc ecx
cmp ecx, 6
jl for_
I'm using MASM syntax, but you get the idea.

declaring a string in assembly

I have this assembly code that computes some prime numbers:
#include <stdio.h>
int main() {
char format[] = "%d\t";
_asm{
mov ebx, 1000
mov ecx, 1
jmp start_while1
incrementare1:
add ecx, 1
start_while1:
cmp ecx, ebx
jge end_while1
mov edi, 2
mov esi, 0
jmp start_while2
incrementare2:
add edi, 1
start_while2:
cmp edi, ecx
jge end_while2
mov eax, ecx
xor edx, edx
div edi
test edx, edx
jnz incrementare2
mov esi, 1
end_while2:
test esi, esi
jnz incrementare1
push ecx
lea ecx, format
push ecx
call printf
pop ecx
pop ecx
jmp incrementare1
end_while1:
nop
}
return 0;
}
It works fine but I would like to also declare the 'format' string in asm, not in C code. I have tried adding something like format db "%d\t", 0 but it didn't work.
If all else fails there's always the ugly way:
format_minus_1:
mov ecx,0x00096425 ; '%', 'd', '\t', '\0' in little-endian format
lea ecx,format_minus_1 + 1 ; skip past the "mov ecx" opcode
push ecx
call printf
You cannot define objects inside the _asm block with those directives. The C declaration is allocating space on the stack for you so if you want to do something like that inside the _asm block you need to manipulate the stack pointer and initialize the memory yourself:
sub esp, 4
mov [esp], '%'
mov [esp + 1], 'd'
mov [esp + 2], '\t'
mov [esp + 3], '\0'
...
push ecx
push esp + 4
call printf
Note this is one way. Not necessarily the best way. The best way being let C do your memory management for you.

Resources