Longest run of integers in an array in assembly x86 - arrays

I am having trouble finding the longest run of integers in an array in x86 assembly. I have an array I am passing in, and the size of the array, and I think I am on track with my logic, just can't figure out the last steps. Any help is appreciated. This is the code I have so far:
int Longest_Run(int nums[], int siz) {
//
int returnValue = 0;
int freq[101] = { 0 }; //if needed
int arr_length = 0;
arr_length = sizeof(nums) / sizeof(int); //WRONG
__asm {
//LONGEST RUN. Return value to caller :
MOV ECX, siz // arr_length //For looping
//LEA ESI, nums //ptr to array
mov ESI, nums //ptr to array
//LEA EDI, nums //ptr to array
MOV EBX, 0 //Frequency counter
MOV EAX, [ESI] //First array int in SI
L1:
CMP EAX, [ESI] //Compare 1st int with 1st int
JE L2
JMP L3
L4:
LOOP L1
JMP CLEAR
L2 : //If equal
INC EBX //Inc counter
ADD ESI, 4 //Inc to 2nd item in array
MOV EAX, [ESI] //Move 2nd item into AX
JMP L1
L3 :
PUSH EBX // Puts counter int on stack
MOV EBX, 0 // Clears BX to start over
ADD ESI, 4 //Inc to 3rd item in array
MOV EAX, [ESI] //Move 3rd item into AX
JMP L4
CLEAR:
POP EDX
MOV EDX, returnValue
//END
}
return returnValue;
}
Any ideas or guidance?

Related

Assembly Language code to find positive numbers in a Array of numbers

We can only edit bold part to find positive number from given array. This is what i have tried in visual basic and i am just getting result as zero, Can someone say where it got wrong?
int solution(const int arr[], size_t arr_size)
{
int result = 0;
__asm
{
**MOV eax, arr
MOV edx, eax
MOV ebx, 10
XOR ecx, ecx
LEA esi, size arr
NEXT2 :
MOV edi, esi
SHR edi, 10
JNC NEXT1
JMP NEXT3
NEXT1 : INC ecx
NEXT3 : INC SI
DEC ebx
JNZ NEXT2
MOV[result], ecx;**
}
return result;
}
int main()
{
int result;
int arr[] = { 0, -1, 2, -3, 4, -5, 6, -7, 8, -9 };
result = solution(arr, sizeof(arr) / sizeof(arr[0]));
printf("Grade 6 result = %d\n", result);
getchar();
return 0;
}
1) Here is a piece of code I use to get the size of an array:
mov ebx, 0 ; set ebx to zero to start checking at index 0
countloop:
inc ebx ;Increase ebx for next loop
cmp arr[ebx], '\0' ;compare arr at index [ebx] to end char '\0'
jne countloop ;if not equal, jump back and try for next index
mov arrlength, ebx ;if equal to '\0', load the value of ebx (actual length of the array) into the empty length variable
The reason why you look for '\0' is that the string is stored like a char array and the register only stores the first char, the loops to get the other until it get that 'end' characters. I believe other characters would get the loop to stop, not sure which one, but \0 does work
2) Then use the value stored in arrlength as the number of loops you will need to check your array and find positives.
MOV ecx, arrlength ; This sets the loop counter register (ECX) to the size of your array
MOV ebx, 0 ; Set this to 0 as we will use it again as index
MOV esi, 0 ; Same
compareLoop:
MOV eax, arr[ebx] ; load value of arr at index ebx
CMP eax, 0 ; sets flag, comparing eax to 0
JL lessThan ;JL --> jump if first operand lower than second operand
MOV newArr[esi], eax ;Put the value (which is >0, in a new array)
add esi, 4 ; To point to the next position
lessThan:
add ebx, 4 ; adding for to ebx so that now it has the index of next value in array
loop compareLoop ; until ecx = 0
I basically showed you how I would do it, I am far from a pro, and simply don't understand the way you proceeded.

sort the array and print the smallest number in inline assembly in visual studio

I write the following code to read some numbers ranging from -15 to 15 from the user and the user may define how many numbers to enter. Then I bubble sort the array to get the smallest number. (Bubble sort because I will need to print other information) However, the code is not working. Here is my code.
// oops.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
char message0[] = "How many numbers do you want to enter? \n";
char message1[] = "Enter the current reading: \n";
char message2[] = "Error!\n";
char message3[] = "The smallest number is: \n";
char format1[] = "%d";
char format2[] = "%s";;
int myarray[10000];
int No;
int counter;
int *p;
p = myarray - 1;
_asm{
lea eax, message0
push eax
call printf
add esp, 4
//read how many numbers the user would like to input
lea eax,counter
push eax
lea eax, format1
push eax
call scanf_s
add esp,8
mov No, 1
mov ecx, counter
mov ebx, 0
//read user's input
Input: push ecx
push No
lea eax, message1
push eax
call printf
add esp, 8
lea eax, myarray[ebx]
push eax
lea eax, format1
push eax
call scanf_s
add esp,8
//judge if the number is in the range of -15 to 15
JudgeInput: mov eax, myarray[ebx]
cmp eax,-15
jl Illegal
cmp eax,15
jle Legal
Illegal: lea eax,message2
push eax
call printf
add esp,4
pop ecx
jmp Input
Legal: add ebx,4
inc No
pop ecx
loop Input
//bubble sort
mov esi, p
mov ecx, counter
outer : mov edx, ecx
inner : cmp edx, ecx
jz exchangeNo
mov eax, [esi + ecx * 4]
mov ebx, [esi + edx * 4]
cmp eax, ebx
jnb exchangeNo
mov[esi + ecx * 4], ebx
mov[esi + edx * 4], eax
exchangeNo :
dec edx
jnz inner
loop outer
finish:
smallest: //print the smallest number
mov ebx,0
lea eax,message3
push eax
lea eax, format2
push eax
call printf
mov eax,0
lea ebx,myarray
sub ebx,4
add ebx,No
lea eax, [ebx]
push eax
lea eax,format1
call printf
add esp,16
}
return 0;
}
It would not return the smallest number. Sometimes it returns strange characters. I get really confusing. Additionally, when I enter negative numbers, the bubble sort seems not working well.
I have solved the problem. Here is my updated code:
int _tmain(int argc, _TCHAR* argv[])
{
char message0[] = "How many numbers do you want to enter? \n";
char message1[] = "Enter the current reading: \n";
char message2[] = "Error!\n";
char message3[] = "\nThe smallest number is: ";
char format1[] = "%d";
char format2[] = "%s";;
int myarray[10000];
int No;
int counter;
int *p;
p = myarray - 1;
_asm{
lea eax, message0
push eax
call printf
add esp, 4
lea eax,counter
push eax
lea eax, format1
push eax
call scanf_s
add esp,8
//get the user's input into the array
mov No, 1
mov ecx, counter
mov ebx, 0
Input:
push ecx
push No
lea eax, message1
push eax
call printf
add esp, 8
lea eax, myarray[ebx]
push eax
lea eax, format1
push eax
call scanf_s
add esp,8
//judge if the input is between -15 and 15
JudgeInput:
mov eax, myarray[ebx]
cmp eax,-15
jl Illegal
cmp eax,15
jle Legal
//if not, print out error message
Illegal:
lea eax,message2
push eax
call printf
add esp,4
pop ecx
jmp Input
//if yes, loop again
Legal:
add ebx,4
inc No
pop ecx
loop Input
//bubble sort
mov esi, p
mov ecx, counter
//the outer loop
outer : mov edx, ecx
//the inner loop
inner : cmp edx, ecx
je exchangeNo
mov eax, [esi + ecx * 4]
mov ebx, [esi + edx * 4]
cmp eax, ebx
jge exchangeNo
mov[esi + ecx * 4], ebx
mov[esi + edx * 4], eax
exchangeNo :
dec edx
jge inner
loop outer
finish:
//find out the smallest number
smallest :
lea eax, message3
push eax
lea eax, format2
push eax
call printf
lea ebx, myarray
mov eax, [ebx]
push eax
lea eax, format1
push eax
call printf
add esp, 16
}
}

assembly intel x86 call function with local variables

I'm having an issue with a binary search implementation. Note, I do not want to modify this c code, I'm trying to translate it to assembly. Here's my c code:
int binary_search_c(int n, int list[], int low, int high) {
int middle;
if (low > high)
return -1;
middle = (low + high)/2;
if (n == list[middle])
return middle;
if (n < list[middle]) {
high = middle - 1;
} else {
low = middle + 1;
}
return binary_search_c(n, list, low, high);
}
And here is my binary search in assembly. I've commented NEW with things I've added for the first time, so possible problem areas, though I'm pretty sure my problem lies in bin.
;* int binary_search(int n, int list[], int low, int high); *
;*****************************************************************************
%define n [ebp+8]
%define list [ebp+12]
%define low [ebp+16]
%define high [ebp+20]
binary_search:
push ebp
mov ebp, esp
sub esp, 4 ;one local var |
%define middle [ebp-4] ; define local var as middle | NEW
mov eax, low ; pull low into register
cmp eax, high ; compare low to high low > high
jle less; ; if less than or greater, go to less
mov eax, -1 ; move -1 into eax for return
jmp return; ; call return/end function
less: ;if low is not > high
mov eax, low ;move middle into register
add eax, high ;high+low
mov ebx, 2 ;move 2 into ebx for div
xor edx, edx ;clear edx |
xor eax, eax
div ebx ; div eax, by 2 =>(low+high)/2 | NEW
mov middle, eax ;move (low+high)/2 into middle
mov eax, n ; move middle into eax
mov edi, list ; move list into edi for list call
mov edx, middle ; move middle into edx as list index |
lea esi, [edi+edx*4] ; grab list[middle] |
mov ebx, [esi] ; move list[middle] into register| NEW
cmp eax, ebx ; compare n and list[middle]
jne notE; ; if not equal (n ==list[middle]
mov eax, middle ;move middle into eax for return
jmp return; ;call return/end function
notE: ;if n !=list[middle]
mov eax, n ;move eax into n
mov edi, list ; move list into edi to access list
mov ebx, middle ; move middle into ebx as index |
lea esi, [edi+ebx*4] ; grab list[middle] |
mov ebx, [esi] ;move list[middle] into ebx |NEW
cmp eax, ebx ; compare n and list[middle]
jge .else; ; if greater than or equal n < list[middle]
mov eax, middle ;move middle into eax for return
sub eax, 1 ;middle-1
mov ebx, high ; put high into ebx for replacement
mov ebx, eax ; high = middle-1
jmp bin; ;jump to next part[not return]
.else: ;if n >= list[middle]
mov eax, middle ;move middle into eax to add 1
add eax, 1 ; middle+1
mov ebx, low ;move low into ebx for change in low
mov ebx, eax ;low = middle+1
bin: ; final return
mov eax, high ; move high into eax for push
push eax ; push high
mov ebx, low ;low into ebx
push ebx ; push low
mov ecx, list ; list for push
push ecx ;push list
mov edx, n ;n for push
push edx ;push n |
call binary_search ; call search |
add esp, 16 ; add 16=>(4*4) to stack for reset | NEW
return: ;end function
leave
ret
So after chopping my code up while trying to find the error, I'm getting a seg fault when trying to run anything using bin
I think I may be doing something wrong with the addition to the stack with add esp, 16 though I'm not sure as it's the first time I've called a function with so many arguments and with a local variable at hand.
I'll gladly take any optimization to my code, I'm just weary about the things labeled NEW, and I need to figure out what I'm doing wrong in bin that throws a fault, any help would be greatly appreciated.
mov eax, low ;move middle into register
add eax, high ;high+low
mov ebx, 2 ;move 2 into ebx for div
xor edx, edx ;clear edx |
xor eax, eax ;clear eax |
div ebx ; div eax, by 2 =>(low+high)/2 | NEW
In this code you're trying to calculate the middle but you don't really do that because you zero the EAX register right before the division!
Please remove the xor eax, eax instruction.
mov ebx, high ; put high into ebx for replacement
mov ebx, eax ; high = middle-1
jmp bin
This is a further problem:
You want to setup for the lower partition, but you don't actually store the new high index!
This will do it:
mov high, eax ; high = middle-1
jmp bin
The same applies to the low index.
Just an update on the working code, with a div by 2 instead of a shift, inefficient, by functional. In case anyone else needs it, here:
;* int binary_search(int n, int list[], int low, int high); *
;*****************************************************************************
%define n [ebp+8]
%define list [ebp+12]
%define low [ebp+16]
%define high [ebp+20]
binary_search:
push ebp
mov ebp, esp
sub esp, 4 ;one local var
%define middle [ebp-4] ; define local var as middle
mov eax, low ; pull low into register
cmp eax, high ; compare low to high low > high
jle less; ; if less than or greater, go to less
mov eax, -1 ; move -1 into eax for return
jmp return; ; call return/end function
less: ;if low is not > high
mov eax, low ;move middle into register
add eax, high ;high+low
mov ebx, 2 ;move 2 into ebx for div
xor edx, edx ;clear edx
div ebx ; div eax, by 2 =>(low+high)/2
mov middle, eax ;move (low+high)/2 into middle
mov eax, n ; move middle into eax
mov edi, list ; move list into edi for list call
mov edx, middle ; move middle into edx as list index
lea esi, [edi+edx*4] ; grab list[middle]
mov ebx, [esi] ; move list[middle] into register
cmp eax, ebx ; compare n and list[middle]
jne notE; ; if not equal (n ==list[middle]
mov eax, middle ;move middle into eax for return
jmp return; ;call return/end function
notE: ;if n !=list[middle]
mov eax, n ;move eax into n
mov edi, list ; move list into edi to access list
mov ebx, middle ; move middle into ebx as index
lea esi, [edi+ebx*4] ; grab list[middle]
mov ebx, [esi] ;move list[middle] into ebx
cmp eax, ebx ; compare n and list[middle]
jge .else; ; if greater than or equal n < list[middle]
mov eax, middle ;move middle into eax for return
sub eax, 1 ;middle-1
mov high, eax
jmp bin; ;jump to next part[not return]
.else: ;if n >= list[middle]
mov eax, middle ;move middle into eax to add 1
add eax, 1 ; middle+1
;move low into ebx for change in low
mov low, eax ;low = middle+1
bin: ; final return
mov eax, high ; move high into eax for push
push eax ; push high
mov ebx, low ;low into ebx
push ebx ; push low
mov ecx, list ; list for push
push ecx ;push list
mov edx, n ;n for push
push edx ;push n
call binary_search ; call search
add esp, 16 ; add 16=>(4*4) to stack for reset
return: ;end function
leave
ret
Thank you to #Fifoernik for his answer

Assembly, Loop with unsigned char vector

I don't understand what happens in this Loop written in assembly language with 32-bit registers. This is the code:
void main() {
unsigned char Vet[100];
unsigned short int Mat = 8805;
unsigned short Ris;
__asm {
MOV AX, Mat
MOV BYTE PTR Vet[10], AL
MOV BYTE PTR Vet[13], 99
MOV BYTE PTR Vet[16], AH
LEA ESI, Vet
ADD ESI, 9
XOR EBX, EBX
MOV ECX, 3
L1: XOR BL, [ESI + 1]
ADD ESI, 3
LOOP L1
MOV Ris, BX
}
printf("\nRis: %d\n\n", Ris);
}
L1 set BL=65h the first time because BL starts by 0. Ok.
The second time i suppose to have 65h XOR 99h, because ESI=Vect[9+3+1].
So i expect FCh as result in BL, but compiler returns 06h!
I made test with a simple XOR between 65h and 99h, and is like i thought: FCh. The problem maybe in the Vet index, but where?
it's 99, not 99h. 65h xor 99 = 6.

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

Resources