Indexing array elements in Assembly - arrays

I'm having some trouble with arrays in NASM. I am trying to implement this pseudo code but am obtaining incorrect results.
For instance, when I send in 'abcdefgh' as byte_arr I should get 8 7 6 5 4 3 2 1. However, I actually receive: 5 4 3 2 1 1 1 1. Here's the code:
maxLyn(Z[0 . . n − 1], n, k) : returns integer
if k = n − 1
return 1
p ← 1
for i ← k+1 to n − 1
{
if Z[i−p] = Z[i]
if Z[i−p] > Z[i]
return p
else
p ← i+1−k
}
return p.
Rather than returning p, I wish to store it as a global variable which I can access in my other subroutines. Here is my attempt at coding it:
enter 0, 0 ; creates stack
pusha ; pushes current register values onto stack
mov eax, [ebp+16] ; kth index
mov ebx, [ebp+12] ; length
mov edi, [ebp+8] ; byte_arr
mov [len], ebx ; len = length
sub [len], dword 1 ; len = len - 1
mov ebx, [len] ; ebx contains len - 1
mov [k], eax ; k = epb+16
mov [p], dword 1 ; p = 1
mov [i], eax ; i = k
inc dword [i] ; i = k+1
mov ecx, [i] ; ecx = i
cmp [k], ebx ; checks if kth index is last element
je ENDFOR
FOR: cmp dword [i], ebx ; goes from ith index to len
ja ENDFOR
mov esi, [edi + ecx*1] ; esi = array[i]
mov [i_temp], esi ; store array[i] in variable
sub ecx, [p] ; ecx = i-p
mov edx, [edi + ecx*1] ; edx = array [i-p]
cmp edx, [i_temp]
je REPEAT ; array[i-p] = array[i]
ja ENDFOR ; array[i-p] > array[i]
mov eax, dword [i]
mov [p], eax ;p = i
inc dword [p] ;p = i + 1
mov eax, dword [p]
sub eax, [k] ;eax = p - k
mov [p], eax ;p = i+1-k
REPEAT:
inc dword [i] ; i = i + 1
mov ecx, [i] ; ecx = i + 1
jmp FOR
ENDFOR:
popa ; saves register values and pops them off
leave ; cleans up
ret ; returns to caller

mov esi, [edi + ecx*1] ; esi = array[i]
mov [i_temp], esi ; store array[i] in variable
sub ecx, [p] ; ecx = i-p
mov edx, [edi + ecx*1] ; edx = array [i-p]
cmp edx, [i_temp]
je REPEAT ; array[i-p] = array[i]
ja ENDFOR ; array[i-p] > array[i]
In these lines you read your array elements as dwords but you actually are using an array of bytes!
That's why the comparing fails. Change this cmp into:
cmp dl, byte ptr [i_temp]
Alternatively rework your code to use byte sized variables/registers where appropriate.

Related

How to deal with non-fixed size arrays?

Today I'm working on arrays and addressing modes so I made this snippet to train myself. Everything is working fine (apparently) but I chose the easiest way using fixed size arrays. My question is about dynamic memory allocation. In my code, my arrays arrayand array2 have a fixed size (8 * 4(int)). If I wanted to extend them, or to speak with C concepts, make a realloc or something like depending on real time values for the size, may I have to implement system calls like sys_brk and mmapby myself in assembly
or is there an other option ? The other question deals with the part of my code used to reverse an array (label .reversing) I know they are faster solutions than mine so if you could give me some advices, it would be nice.
%define ARRAY_LEN 8
%macro print 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 0x80
%endmacro
%macro exit 0
xor ebx, ebx
mov eax, 1
int 0x80
%endmacro
section .bss
sumarrays resd 1
dynarray resd 256
section .rodata
highest equ 0x78
evensum equ 0x102
sumarray1 equ 0x1e6
sumarray2 equ 0x256
section .data
revarray times ARRAY_LEN dd 0
strok db "Good result !", 0xa, 0
lenstrok equ $ - strok
strerror db "Bad result !", 0xa, 0
lenerror equ $ - strerror
array dd 0x33, 0x21, 0x32, 0x78, 0x48, 0x77, 0x19, 0x10
array2 dd 0x12, 0x98, 0x65, 0x62, 0x4e, 0x3e, 0x1f, 0x3a
section .text
global sort
global sum
global _start
_start:
; sort array from highest value to lowest value
sub esp, 8
push ARRAY_LEN
push array
call sort
add esp, 8
and esp, 0xfffffff0
; copying array into some another ones : array -> revarray
mov esi, eax
mov edi, revarray
mov ecx, ARRAY_LEN
rep movsd
; now let's reverse the array
mov esi, revarray ;esi = address of array
mov ecx, ARRAY_LEN ;ecx = number of elements
lea edi, [esi + ecx * 4 - 4]
.reversing:
mov eax, [esi] ;eax = value at start
mov ebx, [edi] ;ebx = value at end
mov [edi], eax
mov [esi], ebx
add esi, 4 ;incrementing address of next item at start
sub edi, 4 ;incrementing address of next item at end
cmp esi, edi ;middle reached ?
jb .reversing ;no we continue
.reversed:
;after, we compute the sum of the elements in the array
mov esi, revarray ; address of array
mov edx, ARRAY_LEN ; num elem of array
sub esp, 8
call arraysum ; sum computation
add esp, 8
cmp eax, sumarray1 ; we check the result to be sure
jne .failure
; merging array2 with array
; esi = source address of first array
; edi = address of second array, the destination one
mov esi, array2
mov edi, array
sub esp, 8
call mergearrays
add esp, 8
; we compute the sum of the merged arrays into the new (old one in fact)
mov esi, array
mov ecx, ARRAY_LEN
add esp, 8
call arraysum
add esp, 8
cmp eax, 0x43c ; we check the result to be sure
jne .failure ; if not egal, exit
; compute the sum of even numbers only in the array
; set up edx to 0 at beginning of loop
; cmova edx, $value_even_number
mov esi, revarray
xor ebx, ebx
xor ecx, ecx
.iterate:
xor edx, edx ; setting up edx to 0
mov eax, [esi + ecx * 4]
test al, 1 ; CF == 0 ? so it's an even number
cmovz edx, eax ; we store the value of current element in edx
add ebx, edx ; so in case of odd number => add 0
inc ecx
cmp ecx, ARRAY_LEN ; end of array reached ?
jne .iterate ; no, we continue
cmp ebx, 0x102 ; check if result is good
je .success
jmp .failure
exit
.success:
print strok, lenstrok
exit
.failure:
print strerror, lenerror
exit
; ********************************************
; computes the sum of all elements of an array
; esi = address of the array
; edx = number of elements in array
; output : eax
; ********************************************
arraysum:
push ebx
xor ebx, ebx
xor ecx, ecx
.arraysum:
mov eax, [esi + ecx *4]
add ebx, eax
inc ecx
cmp ecx, edx
je .sumdone
jmp .arraysum
.sumdone:
mov eax, ebx
pop ebx
ret
; *********************************************
; procedure that sort array from highest to lowest value
; first arg = address of the array
; second arg = number of elements in a array
; return : eax, sorted array
; ********************************************
sort:
push ebp
mov ebp, esp
mov edx, [ebp + 12]
.loop1:
mov esi, [ebp + 8]
mov ecx, [ebp + 12]
.loop2:
mov eax, [esi]
mov ebx, [esi + 4]
cmp eax, ebx
jg .skip
mov [esi], ebx
mov [esi + 4], eax
.skip:
add esi, 4 ;perform loop checks
dec ecx
cmp ecx, 1
ja .loop2
dec edx
ja .loop1
mov eax,[ebp + 8] ; save result in eax
mov esp,ebp
pop ebp
ret
; ****************************************************
; function adding two arrays merging them
; esi = address of first array
; edi = address of second array (destination array)
; ****************************************************
mergearrays:
xor ecx, ecx
.merging:
mov eax, [esi + ecx * 4]
xadd [edi + ecx * 4], eax
inc ecx
cmp ecx, ARRAY_LEN
je .mergedone
jmp .merging
.mergedone:
ret

assembly - Issue with permutations generation

I'm trying to list all the permutations of the first N natural numbers (N <= 6) with MSVC Assembly 8086 inline. I can't change anything of the C program, I can only manage the assembly code.
So this is what I've done (and works with N <= 3), using the lexicographic algorithm:
#include <stdio.h>
int main() {
// Variabili
int N=4; // N <= 6
int Perm[4326]; // permutations array: the dimension is sufficient for N <= 6
int Num; // At the end it must contains the number of generated permutations
// Assembler block
__asm
{
XOR EAX, EAX ; Reset EAX (permutations counter)
MOV ECX, N ; Put N into ECX
CMP ECX, 1 ; Compare ECX and 1
JBE Piccolo ; If ECX <= 1 go to Piccolo (particular cases 1 and 0)
DEC ECX ; Decrement ECX (so ECX = N - 1)
MOV EAX, N ; Put N into EAX
MaxPerm:
MUL ECX ; Do EDX:EAX = EAX * ECX
LOOP MaxPerm ; Loop to find permutations number
MOV Num, EAX ; Move EAX (permutations number) into Num
MOV EAX, 1 ; Set EAX (permutations number) to 1
MOV EBX, 0 ; Reset EBX (EBX = 0)
MOV ECX, 1 ; Reset ECX
CicloIniziale:
DEC ECX ; Decrement ECX (to compare it with N)
CMP ECX, N ; Compare ECX and N
JE Permutazione ; If ECX == N the first permutation has been written, skip to the generation of the next ones
INC ECX ; Else increment ECX
MOV Perm[4*EBX], ECX ; Insert ECX into the Perm array
INC ECX ; Increment ECX
INC EBX ; Increment EBX
JMP CicloIniziale ; Continue the loop
Permutazione:
XOR EAX, EAX ; Local index
XOR EBX, EBX ; Previous permutation index
MOV ECX, N ; Current permutation index
MOV EDI, 1 ; Value of k
MOV ESI, 1 ; New position of k
CicloPermutazione:
CMP EAX, N ; Compare ECX and EAX
JE ResetPerm ; If the end of the permutation has been reached, go to ResetPerm
MOV EDX, Perm[4*EBX] ; Otherwise save the element of the previous permutation in position EBX in EDX
CMP EDX, EDI ; Compare EDX and EDI
JE ValoreUguale ; If they are equal, then go to ValoreUguale
CMP EAX, ESI ; Otherwise compare EBX and ESI
JE InserisciElSpostato ; If it's time to move the item, go to InserisciElSpostato
MOV Perm[4*ECX], EDX ; Returns the value of the previous permutation to the new permutation
ContinuaCiclo:
INC EBX ; Increment the previous permutation index
INC EAX ; Increment the local index
INC ECX ; Increment the new permutation index
JMP CicloPermutazione ; Continue the loop
InserisciElSpostato:
MOV Perm[4*ECX], EDI ; Put EDI in the new permutation
MOV EDX, N ; EDX = N
DEC EDX ; EDX -= 1
CMP ESI, EDX ; Compare ESI and EDX
JE ResettaK ; If ESI == EDX go to ResettaK
JMP ContinuaCiclo ; Continue the loop
ValoreUguale:
CMP EAX, 0 ; Confronta EAX e 0
JZ PrimaPos ; If EAX == 0 (first position) go to PrimaPos
MOV EDX, Perm[4*EBX+4] ; Else save the element into position EBX - 1
MOV Perm[4*ECX], EDX ; Insert EDX in the new permutation
JMP ContinuaCiclo ; Continue the loop
PrimaPos:
MOV EDX, Perm[4*EBX+4] ; Save into EDX the element in position ECX + 1
MOV Perm[4*ECX], EDX ; Insert EDX into the new permutation
JMP ContinuaCiclo ; Continue the loop
ResettaK:
XOR ESI, ESI ; Reset ESI
MOV EDI, Perm[4*EDI] ; EDI = Perm[EDI]
JMP ContinuaCiclo ; Continue the loop
ResettaKN:
CMP EDI, N ; Compare EDI and N
JNE ContinuaCiclo ; if EDI != N then continue the loop
JMP ResettaK ; Else go to ResettaK
ResetPerm:
MOV EAX, Num ; EAX = Num
MUL DWORD PTR N ; EAX *= N (Elements of number of all the permutations)
CMP EAX, ECX ; Compare EAX and ECX
JE Fine ; If EAX == ECX (permutations done) then finish the program
XOR EAX, EAX ; Otherwise reset EAX
INC ESI ; Increment k index
JMP CicloPermutazione ; Continue the loop
Piccolo: ; If N = 0 or N = 1, the only permutation that can exists is made by only 1 element
MOV Num, 1
MOV Perm[0], ECX
Fine:
}
// Print
{
int i,j,k;
printf("%d permutations of the first %d natural numbers\n", Num, N);
for (i=k=0;i<Num;i++)
{
for (j=0;j<N;j++)
{
printf("%3d",Perm[k++]);
}
printf("\n");
}
}
return 0;
}
The issue is that this program works only for N <= 3 and I didn't found the issue!
These are the outputs I get:
N = 3 and below works fine:
6 permutations of the first 3 natural numbers
1 2 3
2 1 3
2 3 1
3 2 1
3 1 2
1 3 2
N = 4 (the same with 5 and 6):
24 permutations of the first 4 natural numbers
1 2 3 4
2 1 3 4
2 3 1 4
2 3 4 1
3 2 4 1
3 4 2 1
3 4 1 2
4 3 1 2
4 1 3 2
4 1 2 3
1 4 2 3
1 2 4 3
1 2 3 4
1 3 3 4
1 3 2 4
1 3 4 2
1 4 4 2
1 4 3 2
1 4 2 3
1 2 2 3
1 2 4 3
1 2 3 4
1 3 3 4
1 3 2 4
As you can see after the last permutation of the first cycle the next ones are messed up...
Can you help me?
Thanks
You have written several lines where the code does not match the accompanying comment. If I were you I would suspect to find possible errors there.
CMP EAX, N ; Compare ECX and EAX
CMP EAX, ESI ; Otherwise compare EBX and ESI
MOV EDX, Perm[4*EBX+4] ; Else save the element into position EBX - 1
MOV EDX, Perm[4*EBX+4] ; Save into EDX the element in position ECX + 1
This would be the code that matches the comments:
cmp ecx, eax
cmp ebx, esi
mov edx, Perm[4*ebx - 4] ; 'save' == 'save into EDX' (*)
mov edx, Perm[4*ecx + 4]
I'm not saying that these will solve the problem because maybe your comments are wrong and your code is correct.
(*) Instead of the very confusing phrase "save into EDX", better write it as "load EDX with/from".
You have managed to write lots of redundant comments.
Below is a small portion of these:
MOV EAX, N ; Put N into EAX
MOV EBX, 0 ; Reset EBX (EBX = 0)
CMP ECX, 1 ; Compare ECX and 1
INC ECX ; Increment ECX
INC EBX ; Increment EBX
MOV EDX, N ; EDX = N
DEC EDX ; EDX -= 1
CMP ESI, EDX ; Compare ESI and EDX
JE ResettaK ; If ESI == EDX go to ResettaK
Do yourself a favor and stop writing these redundant comments. They make it much harder for anyone (including yourself) to (try to) understand the code.
A recent blog post deals with the subject of writing code comments: https://stackoverflow.blog/2021/07/05/best-practices-for-writing-code-comments/
In the end, I've managed to write a C program that does the job using the algorithm fo the next_permutation function of the C++ STD lib. Then, I've translated the C code into assembly with the help of Godbolt (online compiler).
So:
Write the C program using the next_permutation function: https://godbolt.org/z/7avGaWfha
Flatten all the functions in the main: https://godbolt.org/z/7z9MGWefK
Finally, with the great help of Godbolt, translate it to assembly

cmp instruction not making jge jump within InsertionSort

I am trying to write an iterative version of InsertionSort using MASM. After repeatedly getting unexpected errors, I tried running through the code line by line and watching in the debugger that it did what I expected. Sure enough, I the cmp instruction within my 'while loop' doesn't seem to be jumping every time it's supposed to:
; store tmp in edx
movzx edx, word ptr[ebx + esi * 2]; edx: tmp = A[i]
...
//blah blah
while_loop :
...
movzx eax, word ptr[ebx + 2 * edi]
cmp dx, ax
jge exit_while
For example, if I use the data given, after the first 'for loop' iteration, I get to the point where EDX=0000ABAB, and EAX=00003333. I reach the lines:
cmp dx, ax
jge exit_while
Since ABAB>3333, I'd expect it to jump to exit_while, yet it doesn't!
What is going on here??? I'm at a total loss.
.data
arr word 3333h, 1111h, 0ABABh, 1999h, 25Abh, 8649h, 0DEh, 99h
sizeArr dword lengthof arr
printmsg byte "The array is: [ ", 0
comma byte ", ", 0
endmsg byte " ]", 0
.code
main proc
call printArr
call crlf
push sizeArr
push offset arr
call insertionsort
call crlf
call printArr
call crlf
call exitprocess
main endp
insertionsort proc
push ebp
mov ebp, esp
_arr = 8
len = _arr + 4
mov ebx, [ebp + _arr]
mov ecx, [ebp + len]
dec ecx
mov esi, 1; store i in esi, with i=1 initially
; for (i = 1; i < SIZE; i++)
forloop:
; store tmp in edx
movzx edx, word ptr[ebx + esi * 2]; edx: tmp = A[i]
; store j in edi, where in initially j = i
mov edi, esi
;set j=i-1
dec edi
;while (j >= 0 && tmp<arr[j])
while_loop :
cmp edi, 0
jl exit_while
movzx eax, word ptr[ebx + 2 * edi]
; cmp dx, [ebx + 2 * edi]
cmp dx, ax
jge exit_while
; A[j] = A[j-1]
push word ptr [ebx+2*edi]
pop word ptr [ebx+2*edi+2]
; j = j - 1
dec edi
jmp while_loop
exit_while:
push dx
pop word ptr[ebx + 2*edi+2]
; mov[ebx + edi], dx; A[j] = tmp
inc esi; i = i + 1
loop forloop
finished:
mov esp, ebp
pop ebp
ret 8
insertionsort endp
printArr proc
push ebp
mov ebp, esp
mov ebx, offset sizeArr
mov ecx, [ebx]
mov esi, offset arr
mov edx, offset printmsg
call writestring
mov edx, offset comma
loop1 :
movzx eax, word ptr [esi]
call writeHex
call writestring
add esi, 2
loop loop1
mov edx, offset endmsg
call writestring
mov esp, ebp
pop ebp
ret
printArr endp
jge is the version for signed values - as such, a word with the value ABAB is negative - hence the comparison result you see.
Try jae (jump if above or equal) instead - the unsigned equivalent.

Optmization for quicksort in x86 32-bit assembly

I'm trying to learn some basic x86 32-bit assembly programming. So in pursuing this I decided to implement quicksort in assembly (sorting only integers). First I made a C-version of the sorting function and then I made an assembly version.
However, when comparing my assembly version with the my C-version (compiled with gcc on Debian), the C-version performs more then 10 times faster on a array of 10000 integers.
So my question is if anybody can give some feedback on obvious optimizations that can be made on my quick sort assembly routine. It's purely for educational purposes and I'm not expecting to beat the compiler makers in terms of producing high speed code but I'm interested in knowing if I'm making any obvious mistakes that hampers speed.
The C-version:
void myqsort(int* elems, int sidx, int eidx)
{
if (sidx < eidx)
{
int pivot = elems[eidx];
int i = sidx;
for (int j = sidx; j < eidx; j++)
{
if (elems[j] <= pivot)
{
swap(&elems[i], &elems[j]);
i = i + 1;
}
}
swap(&elems[i], &elems[eidx]);
myqsort(elems, sidx, i - 1);
myqsort(elems, i + 1, eidx);
}
}
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
Assembly version (NASM):
;
; void asm_quick_sort(int* elems, int startindex, int endindex)
; Params:
; elems - pointer to elements to sort - [ebp + 0x8]
; sid - start index of items - [ebp + 0xC]
; eid - end index of items - [ebp + 0x10]
asm_quick_sort:
push ebp
mov ebp, esp
push edi
push esi
push ebx
mov eax, dword [ebp + 0xC] ; store start index, = i
mov ebx, dword [ebp + 0x10] ; store end index
mov esi, dword [ebp + 0x8] ; store pointer to first element in esi
cmp eax, ebx
jnl qsort_done
mov ecx, eax ; ecx = j, = sid
mov edx, dword [esi + (0x4 * ebx)] ; pivot element, elems[eid], edx = pivot
qsort_part_loop:
; for j = sid; j < eid; j++
cmp ecx, ebx ; if ecx < end index
jnb qsort_end_part
; if elems[j] <= pivot
cmp edx, dword [esi + (0x4*ecx)]
jb qsort_cont_loop
; do swap, elems[i], elems[j]
push edx ; save pivot for now
mov edx, dword [esi + (0x4*ecx)] ; edx = elems[j]
mov edi, dword [esi + (0x4*eax)] ; edi = elems[i]
mov dword [esi + (0x4*eax)], edx ; elems[i] = elems[j]
mov dword [esi + (0x4*ecx)], edi ; elems[j] = elems[i]
pop edx ; restore pivot
; i++
add eax, 0x1
qsort_cont_loop:
add ecx, 0x1
jmp qsort_part_loop
qsort_end_part:
; do swap, elems[i], elems[eid]
mov edx, dword [esi + (0x4*eax)] ; edx = elems[i]
mov edi, dword [esi + (0x4*ebx)] ; edi = elems[eid]
mov dword [esi + (0x4*ebx)], edx ; elems[eidx] = elems[i]
mov dword [esi + (0x4*eax)], edi ; elems[i] = elems[eidx]
; qsort(elems, sid, i - 1)
; qsort(elems, i + 1, eid)
sub eax, 0x1
push eax
push dword [ebp + 0xC] ; push start idx
push dword [ebp + 0x8] ; push elems vector
call asm_quick_sort
add esp, 0x8
pop eax
add eax, 0x1
push dword [ebp + 0x10] ; push end idx
push eax
push dword [ebp + 0x8] ; push elems vector
call asm_quick_sort
add esp, 0xC
qsort_done:
pop ebx
pop esi
pop edi
mov esp, ebp
pop ebp
ret
I call the assembly routine from C and I use clock() for timing the routines.
EDIT
The difference in performance is no longer an issue after correcting the bugs pointed out by my fellow stackoverflowers.
You have an error in your assembly sort implementation, and speed comparisons are useless until you resolve it. The problem is the recursive call:
myqsort(elems, sidx, i - 1);
Seeing as it is not necessarily the case that i is not sidx, this might pass a value less than sidx to the function, including -1 if sidx is 0. This is handled in your C implementation:
if (sidx < eidx)
But in your assembly version:
cmp eax, ebx
jae qsort_done
That's an unsigned comparison branch instruction! You should be using jge. I see a segfault due to this problem. When fixed, the performance of both implementations appears to be roughly the same according to my quick tests (compiling with -O3). I used the following test driver:
#include <stdlib.h>
#include <stdio.h>
void myqsort(int * elems, int sidx, int eidx);
#define SIZE 100000
int main(int argc, char **argv)
{
int * elems = malloc(SIZE * sizeof(int));
for (int j = 0; j < 1000; j++) {
for (int i = 0; i < SIZE; i++) {
elems[i] = rand();
}
myqsort(elems, 0, SIZE - 1);
}
return 0;
}
With the C version, run-time was approx 5.854 seconds.
With the assembly version, it was 5.829 seconds (i.e. slightly faster).
You can optimize the swapping of elements using only 1 additional register EDI and without the need for pushing and popping the pivot value in EDX:
mov edi, dword [esi + (0x4*eax)] ; edi = elems[i]
xchg dword [esi + (0x4*ecx)], edi ; elems[j] = edi, edi = elems[j]
mov dword [esi + (0x4*eax)], edi ; elems[i] = edi
The second swap can also be shortened:
mov edi, dword [esi + (0x4*ebx)] ; edi = elems[eid]
xchg dword [esi + (0x4*eax)], edi ; elems[i] = edi, edi = elems[i]
mov dword [esi + (0x4*ebx)], edi ; elems[eid] = edi
You can safely remove the mov esp, ebp from your epilog code because it is redundant. If those 3 pop's went well you already know that the stackpointer has the correct value.
qsort_done:
pop ebx
pop esi
pop edi
mov esp, ebp <-- This is useless!
pop ebp
ret

Traversing and averaging elements in an array MASM

I am in a x86 masm class, and we have a project coming up that I do not understand. The TA and Professor are pretty much useless, I've been trying to get into contact with them for a week and no answer and no office hours. Anyways, I am supposed to calculate the average number of days per month over the span of 15 years. (2000-2015) We are also supposed to factor in leap year.
I wrote the program in C beforehand, and here is my code:
main()
{
double sum=0;
int dpm[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
int i=0;
int j=0;
int months=0;
while(j<16)
{
while(i<12)
{
if(j==0 || j==4 || j==8 || j==12)
{
dpm[1]=29;
}
sum+=dpm[i];
dpm[1]=28;
months++;
i++;
}
j++;
}
printf("%.2f",sum/months);
}
(I realize using a for-loop would be best here, however while loops are easier to do in asm, so I used a while loop)
I don't understand assembly too well, but here is what I have so far:
.DATA
sum DWORD 0
months DWORD 0
dpm DWORD 31,28,31,30,31,30,31,31,30,31,30,31
elm DWORD 12
i WORD 0
j WORD 0
.CODE
main
mov eax, sum ; move sum to eax
lea esi, dpm ; move array to ebx
mov ecx, elm ; move no of elements to ecx
mov ax, j ; move j to ax
mov bx, i ; move i to bx
outterLoop:
cmp 15, ax ; compare 15 to i
jle innerloop ; jump to inner loop if it is less
innerLoop:
cmp 11, bx ; compare 11 to j
jle checkLeap ; jump to checkleap if it is less
inc ax ; incremement j
checkLeap:
cmp 0, bx ; if j is 0
je leap ; go to leap year function
cmp 4, bx
je leap
cmp 8, bx
je leap
cmp 12, bx
je leap
jne updates ; if not, go to updates fn
leap:
add esi, 4 ; go to second element in array "february"
mov 29, esi ; make feb 29 instead of 28
updates:
add eax, [esi] ; add element to sum
add esi, 4 ; increment array
; inc months
mov ; here I would make second element of array 28
inc bx ; increment i
I do not know if I am on the right track, and would like guidance, advice. Thank you
When comparing with an immediate value you need to put the number last. (Correct it 7 times)
cmp ax, 15 ; compare 15 to i
To change the length of february in the list use
mov dword [esi], 29 ; make feb 29 instead of 28
Same thing to reset it
mov dword [esi], 28 ; here I would make second element of array 28
Since you have put your j index in the AX register you need to place the sum in a register different from EAX. Remember that AX is just the low 16 bits of EAX.
The next code needs an additional jump. Now it ALWAYS performs innerLoop
cmp ax,15 ; compare 15 to i
jle innerloop ; jump to inner loop if it is less
innerLoop:
this code is working and giving correct output in edx register.
comment below if you want me to add comments to this code.
i implemented your logic with necessary changes, the thing is you are implementing that incorrectly
Include irvine32.inc
.data
; (31==1Fh)(30==1Eh)(28==1Ch)(29==1Dh)
dpm dword 1Fh,1Ch,1Fh,1Eh,1Fh,1Eh,1Fh,1Fh,1Eh,1Fh,1Eh,1Fh
countj dword ?
temp dword ?
temp1 dword ?
.code
Main Proc
; [instr] [destor opp1] [addtio instr] [source orOpp2] ;comment
mov ecx, 15 ;intializing to max value of j
mov esi, offset dpm ;storing offset of dpm to esi
mov edx, 0 ;intializing sum to 0
mov ebx, 0 ;intializing counter to 0
mov eax, 0 ;intializing counter to 0
loopj: ;loop of j
mov countj, ecx ;storing count of j
mov ecx, 12 ;intializing to max value of i
loopi: ;loop of i
inc ebx
mov eax, countj
;start of if statement:
cmp eax, 1 ;jump if j is 1
je IfJConTrueStart
cmp eax, 5 ;jump if j is 5
je IfJConTrueStart
cmp eax, 9 ;jump if j is 9
je IfJConTrueStart
cmp eax, 13 ;jump if j is 13
je IfJConTrueStart
;29
JConMid:
call dumpregs
mov temp1, edx
mov eax, ecx
mov temp, type dpm
mul temp
add esi, eax
sub esi, temp
call dumpregs
mov edx, temp1
add edx, [esi]
call dumpregs
sub esi, eax
add esi, temp
call dumpregs
JConEnd:
loop loopi
mov ecx, countj
loop loopj
jmp skipIfJConTrue
IfJConTrueStart:
cmp ecx, 2
je IfJConTrueMid
jmp JConMid
IfJConTrueMid:
add edx, 1Dh
jmp JConEnd
skipIfJConTrue:
call dumpregs
Exit
Main endp
End main

Resources