Bubble sort defect using inline assembly code - sorting

I am making a bubble sort function in assembly code for my computer systems class.
My function looks like this
int sorter(int* list, int count, int opcode) {
__asm {
mov ebx, opcode ; opcode in ebx
push 0 ; outer count
mov ecx, 0 ; start ecx at 0 to start loop
mov esi, list ; set esi to list value/ starting address
jmp iloop ; jump to inner loop
oloop: //OUTER LOOP
push ecx ;
mov ecx, 0 ; put the 2nd value in the list in the inner loop count
iloop: // inner loop
mov edx, dword ptr[esi + 4 * ecx]; move first value in edx
mov eax, dword ptr[esi + 4 + 4 * ecx]; move next value in list to eax
cmp ebx, 2 ; compare opcode with 2
je dsnd ; if opcode is equal to 2 then we are using descending order
cmp eax, edx ; compare values at eax and edx
jg no_swap ; if value is greater eax(2nd value) then dont swap /ascending order
cont: //continue from descend
push edx ; push contents of edx to stack
pop dword ptr[esi + 4 + 4 * ecx]; pop the contents on stack to address of value in eax
push eax ; push value in eax to stack
pop dword ptr[esi + 4 * ecx]; pop value on stack to address of value previously in eax
no_swap: //no value swap
inc ecx ; increment inner count
cmp ecx, count ; compare inner loop count to acutal length
jne iloop ; if not equal jump back to inner loop
pop ecx ; get outer count
inc ecx ; to check for n-1 in outer loop
cmp ecx, count ; compare outer loop count to length
jne oloop ; if not equal jump back to outer loop
jmp done ;
dsnd:
cmp eax, edx ; compare values at eax and edx
jl no_swap ; if value is less then dont swap
jmp cont ; continue with loop
done:
}
Where opcode is either 1 for ascending sort or 2 for descending order,
list is a pointer to list of ints, and count is the number of ints in the list
For ascending sort, my program works fine, but with descending I have issues as shown in these test runs:
input 10 -20 5 12 30 -5 -22 55 52 0
Number of integer = 10
Ascend_or_Descend = 1
-22 -20 -5 0 5 10 12 30 52 55 # correct
input 48 -24 48 -24 10 100 -10 60 -256 10 -10 4096 -1024 60 10 -10
Number of integer = 16
Ascend_or_Descend = 1
-1024 -256 -24 -24 -10 -10 -10 10 10 10 48 48 60 60 100 4096 # correct
input 10 -20 5 12 30 -5 -22 55 52 0
Number of integer = 10
Ascend_or_Descend = 2
4283780 55 52 30 12 10 5 0 -5 -20 # incorrect
input 48 -24 48 -24 10 100 -10 60 -256 10 -10 4096 -1024 60 10 -10
Number of integer = 16
Ascend_or_Descend = 2
1500056 4096 100 60 60 48 48 10 10 10 -10 -10 -10 -24 -24 -256 # incorrect
It seems to take the lowest value and swaps it with an address. I am no expert with assembly.

Related

What is this assignment asking me to do, about summing the digits of a value 0425h?

I have this assembly problem where: Given the register AX=0425h. Write a program which adds the sum of digits of value 0425h and stores the sum in the same register AX.
I have no idea what to do in it. Can anyone help me solve this thing?
I tried to think of a solution and did not find anything :)
Given the register AX=0425h
The digits of this hexadecimal number are 0, 4, 2, and 5. The assignment wants you to sum these as in 0 + 4 + 2 + 5 = 11.
One possible solution is the following:
mov edx, eax ; -> DH=04h AL=25h
aam 16 ; 25h/16 -> AH=2 AL=5
add al, ah ; (5+2) -> AL=7
xchg al, dh ; -> DH=7 AL=04h
aam 16 ; 04h/16 -> AH=0 AL=4
add al, ah ; (4+0) -> AL=4
add al, dh ; (4+7) -> AL=11
cbw ; -> AX=11
The code works for any value AX=[0000h,FFFFh] producing AX=[0,60].
A solution that uses a loop and that can deal with any value EAX=[00000000h,FFFFFFFFh] producing EAX=[0,120]:
xor ecx, ecx ; TempResult = 0
More:
mov ebx, eax ; Copy to another temporary register where
and ebx, 15 ; we only keep the lowest digit
add ecx, ebx ; TempResult + LowestDigit
shr eax, 4 ; Shift the original digits to the right discarding the one(s) we already added to the TempResult
jnz More ; Only looping if more non-zero digits exist
mov eax, ecx ; EAX = TempResult

Assembly safes and keys- why it won't work?

So we have like this safes challenge in assembly, you need to create safes and keys that will break them and end the infinite loop.
Here's an example for a safe:
loopy:
mov ax, [1900]
cmp ax,1234
jne loopy
and a key:
loopy2:
mov ax, 1234
mov [1900],ax
jmp loopy2
So I have a safe and a key, and I don't understand why it doesn't work:
here's my safe:
org 100h
mySafe:
mov dx,5
mov ax, [5768h]
mov bx,7
mov word [180h],2
mul word [180h]
mov [180h],bx
push ax
dec bx
mov cx,dx
mov ax,dx
loopy1:
add bx,ax
loop loopy1
dec bx
pop ax
add ax,bx
mul word [180h]
cmp ax,350
jne mySafe
And here's my key:
org 100h
loopy:
mov word [5768h],10
jmp loopy
ret
The right answer to break the loop should be 10 and it works when I put in on the safe, somehow with the key it doesn't work and I can't figure out why..
(the "word" is needed for nasm)
The value in dx used as the counter for the loop instruction comes from the first mul instruction.
This multiplication is just doubling the key, so dx is either 0 or 1 (an easy way to see this is to think of the multiplication as a left shift by one or by remembering that the sum of two n-bit numbers has at most n+1 bits)
If dx is zero, the whole loopy1 block does nothing (as dx also sets ax) and the value in ax at the end of the safe is 7*(5 +2k) where k is the key (see the commented code below).
It is then easy to see that 350 = 7*(5+2k) => 2k = 45 has no solution. Therefore no key for which dx is zero can unlock the safe.
A key has dx 0 iif its value is less than 32768 (again, this is easy to see when thinking of the multiplication as a left shift by one).
Corollary: 10 cannot be a solution.
safe:
mov dx,5
mov ax, [k] ;ax = k (key)
mov bx,7
mov word [aux],2
mul word [aux] ;dx = 0 ax = 2k
mov [aux],bx ;aux = 7
push ax ;ax = 2k
dec bx ;bx = 6
dec bx ;bx = 5
pop ax ;ax = 2k
add ax,bx ;ax = 5 + 2k
mul word [aux] ;ax = 7*(5 +2k)
cmp ax,350
ret
If there is a key that unlocks the safe then it must be greater or equal to 32768 so that dx is 1 after the first multiplication.
With this condition, the value in ax at the end of the safe can be written as 7*(6 + (2k & 0xffff)) => k & 0x7fff = 22.
Adding the condition stated at the very beginning of this section, the final value for k is 32768 + 22 = 32790 or 0x8016 in hex.
I've leaped quite a few logical steps in manipulating the equation and forming the result but, again, thinking of 2k as a shift may help visualize them.
Corollary: Due to the algebraic structure involved, this is the only solution.
safe:
mov dx,5
mov ax, [k] ;ax = k
mov bx,7
mov word [aux],2
mul word [aux] ;dx:ax = 2k
mov [aux],bx ;[aux] = 7
push ax ;dx = 1 ax = 2k & 0xffff
dec bx ;bx = 6
mov cx,dx ;cx = 1
mov ax,dx ;ax = 1
loopy1:
add bx,ax ;bx = 6 + 1
dec cx
jnz loopy1
dec bx ;bx = 6
pop ax ;ax = 2k & 0xffff
add ax,bx ;ax = 6 + (2k & 0xffff)
mul word [aux] ;ax = 7*(6 + (2k & 0xffff))
cmp ax,350
ret
Considering that you have a mov dx, 5 before the first multiplication, did you (or the author of the safe) forget that mul affects dx?
If you wrap the first mul in push dx / pop dx (or just move mov dx, 5 after it), you would get, at the end of the safe, a value in ax equals to 7*(30 +2k) which implies k = 10 indeed.

Effective addressing in Real Mode - accessing array

I am working in real mode of x86 and say I need to access a element from the array people; the index of which is in the register BX.
MOV BX, 2
struc person
.name resb 11
.age resb 1
endstruc
people: times 10 db person_size
The effective addressing in real mode is limited to base + offset. So code like
mov [people + bx * person_size + person.age],byte 20
does not work; however the assembler can do the calculation if no BX register is used -
mov [people + 2 * person_size + person.age],byte 20
I can do multiplication or shift lefts a few times and make it work, but is there a way to do access any element in an array, without assuming that the size of the structure will remain the same in future?
Is there any other way than multiplying like below (cannot do shifts if the structure size changes, code will also change)?
push ax
mov ax, person_size
mul bx
mov bx, ax
pop ax
add bx, person.age
mov [people + bx], byte 20
The effective addressing in real mode is limited to base + offset.
Only on 8086 but not on x86-16 in general.
It's true that in Real Mode you can use Scaled Index addressing like in Fifoernik's answer, but in your program it won't help much since the Scale values are limited to either {1, 2, 4, or 8} and your structure has 12 bytes.
You must do the multiplication yourself especially since you want to leave it open what the size of the structure will be in future.
push ax
mov ax, person_size
mul bx
mov bx, ax
pop ax
add bx, person.age
mov [people + bx], byte 20
What the Real Mode on x86-16 does offer is an extra imul variant that simplifies your calculation:
imul bx, person_size
mov [people + bx + person.age], byte 20
There was no need to add person.age in a separate instruction. The assembler will add people and person.age to become a 16-bit offset.
Your version with the mul bx instruction also modified the DX register. you didn't preserve that one like you did with AX!
For a true 8086 your code was (almost) fine:
push ax
push dx
mov ax, person_size
mul bx
mov bx, ax
pop dx
pop ax
mov [people + bx + person.age], byte 20
One optimization would pad the 12-byte structure to 16 bytes.
struc person
.name resb 11
.age resb 1
.pad resb 4
endstruc
This replaces multiplication by simple shifting to the left in order to access the elements:
For x86-16 (array index in ebx):
shl ebx, 1
mov [people + ebx * 8 + person.age], byte 20
or for 8086 (array index in bx):
push cx
mov cl, 4
shl bx, cl
pop cx
mov [people + bx + person.age], byte 20
Another solution uses a lookup table to avoid multiplication and padding.
LUT dw 0, 12, 24, 36, 48, 60, 72, 84, 96, 108 ; 10 elements
...
shl bx, 1 ; Lookup table holds words
mov bx, [LUT + bx] ; Fetch array element's offset
mov [people + bx + person.age], byte 20

Counting letters and printing an array of numbers with windows api

I have an user input string, which was lowercased and all special characters removed target2 and I want to count how many times each letter appears on the string, and then print the array with 26 letters. However, it prints just a blank line. Is the error when I add to the array? when I print from the array, or both?
If I watch letterArray, it says 1 '\x1' What does that mean?
lettersArray byte 26 dup(0)
countingLetters proc
; clear esi and edi
mov esi, 0
mov edi, 0
charloop
mov al, target2[esi] ; Get a character from the string
cmp al, 97 ; Check if its not a letter
jb printloop ; If bellow, print
sub eax, 97 ; so that 'a' = 0, 'z' = 26.
mov dl, lettersArray[eax]
inc dl
mov lettersArray[eax], dl
inc esi
jmp charloop ; repeat
printloop:
mov bl, lettersArray[edx * type lettersArray]
add bl, 48
push edx
invoke WriteConsoleA, consoleOutHandle, ebx, 4, bytesWritten, 0
pop edx
inc edx
cmp edx, 25 ;Are we done?
ja done ;if yes
jmp printloop ; Repeat
done:
ret
countingLetters endp
This should count the appearances of each letter and print an array with 26 elements, i.e: 00102000000000[etc]

Bubble Sort in NASM Ubuntu

I was asked to create a bubble sort program in NASM Ubuntu. Here's the code:
section .data
i db 0 ; Value to be incremented
question db 'Enter a number: ' ; Prompt
questionLen equ $-question
newLine db 10, 10, 0 ; New blank line
newLineLen equ $-newLine
section .bss
num resb 5 ; Array of size 5
counter resb 1 ; Value to be incremented
counter2 resb 1 ; Value to be incremented
temp resb 1
temp2 resb 1
section .text
global _start
_start:
mov esi, 0
getInput:
mov eax, 4
mov ebx, 1
mov ecx, question ; Prints the question
mov edx, questionLen
int 80h
add byte[i], 30h ; I'll retain this expression, since the program experienced an error
; when this expression is deleted
sub byte[i], 30h ; Converts the increment value to integer
mov eax, 3
mov ebx, 0
lea ecx, [num + esi] ; Element of the array
mov edx, 2
int 80h
inc esi
inc byte[i]
cmp byte[i], 5 ; As long as the array hasn't reached the size of 5,
jl getInput ; the program continues to ask input from the user
mov esi, 0
mov byte[i], 0
mov edi, 0 ; Index of the array
bubble_sort:
mov byte[counter], 0
mov byte[counter2], 0
begin_for_1:
mov al, 0
mov al, [counter] ; Acts as the outer for loop
cmp al, 5
jg printArray ; Prints the sorted list when the array size has reached 5
begin_for_2:
mov edi, [counter2] ; Acts as the inner for loop
cmp edi, 4
jg end_for_2
mov bl, 0 ; Acts as the if statement
mov cl, 0
mov bl, [num + edi]
mov cl, [num + edi + 1]
mov byte[temp], cl ; This is the same as if(a[j] > a[j + 1]){...}
cmp bl, [temp]
jg bubbleSortSwap
return:
inc edi ; Same as j++
jmp begin_for_2 ; Goes out of the inner for loop
end_for_2:
inc byte[counter] ; Same as i++
jmp begin_for_1 ; Goes out of the outer for loop
bubbleSortSwap:
mov [num + edi + 1], bl
mov [num + edi], cl ; The set of statements is the same as swap(&a[j], &a[j + 1]);
jmp return
printArray:
mov eax, 4
mov ebx, 1
mov ecx, [num + esi] ; Prints one element at a time
mov edx, 1
int 80h
inc esi
inc byte[i]
cmp byte[i], 5
jl printArray ; As long as the array size hasn't reached 5, printing continues
mov eax, 4
mov ebx, 1
mov ecx, newLine ; Displays a new blank line after the array
mov edx, newLineLen
int 80h
mov eax, 1 ; Exits the program
mov ebx, 0
int 80h
But the only problem is, it cannot print the rest of the iterations, because it only prints the 1st iteration like this:
Enter a number: 7
Enter a number: 1
Enter a number: 4
Enter a number: 3
Enter a number: 5
17435
What I want to output is the array input and the final output, from the 1st iteration up to the last.
Naw... he just needs some stuff sorted! :)
Doesn't print any output at all for me, as posted. Problem is you're putting "[contents]" in ecx - you want address - you do it right in the input routine.
You can get by with fewer variables - use esi and/or edi as both the "count" and the "index". If you use variables, make sure the size of the variable matches the size of the register you're moving it in/out of! ("mov edi, [counter2]" isn't doing what you want) Courage! If it wuz easy, everybody'd be doing it.
Best,
Frank

Resources