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.
Related
I am creating a program which reads a list of integers seperated by a single space via console and printing the sum of all the integers. The main problem is extracting the integers from the string array into a signed integer array.
Some examples of input are "-20 30 5" (each integer is seperated by a single space) or " [space]-20 30 5 [space]" (there may be spaces between the beginning and the end of the list, but the numbers are still seperated by a single space)
Also, after printing the sum, the program returns to reading another input unless only the enter key is typed.
After writing the code and pressing the Debug button, I am getting these two following build errors:
A2005 symbol redefinition: InBuffer
A2111 conflicting parameter definition
I've checked the error messages and apparently both of them are related to the PROTO and PROC directives. But there seems to be no problems regarding the parameter definition.
Here is my code.
INCLUDE Irvine32.inc
ArrayGet PROTO, ; convert string array into int array
inBuffer: PTR BYTE,
inBufferN: DWORD,
intArray: PTR SDWORD
.data
BUF_SIZE EQU 256
inBuffer BYTE BUF_SIZE DUP(?) ; input buffer
inBufferN DWORD ? ; length of input
intArray SDWORD BUF_SIZE/2 DUP(?) ; integer array for storing converted string
intArrayN DWORD ? ; number of integers
prompt BYTE "Enter numbers(<ent> to exit) : ", 0
bye BYTE "Bye!", 0
.code
main PROC
L1:
mov esi, 0
mov edx, OFFSET prompt
call WriteString
mov edx, OFFSET inBuffer
mov ecx, BUF_SIZE
call ReadString
cmp inBuffer[0], 0ah
je L3 ; only typing <ent> ends the program
mov inBufferN, eax
mov ecx, inBufferN
SpaceCheck: ; calls procedure when it finds a number
cmp inBuffer[esi], 20h
jne L2
inc esi
loop SpaceCheck
jmp L1
L2:
INVOKE ArrayGet, ADDR inBuffer, inBufferN, ADDR intArray ; put inBuffer offset on edx, inBufferN on ecx
mov intArrayN, eax
mov ecx, intArrayN
mov eax, 0
mov esi, OFFSET intArray
Ladd: ; adding the integer array
add eax, [esi]
inc esi
loop Ladd
call WriteInt
call CRLF
jmp L1
L3:
mov edx, OFFSET bye
call WriteString
exit
main ENDP
; procedure definition
ArrayGet PROC USES edx ecx,
inBuffer : PTR BYTE,
inBufferN: DWORD,
intArray: PTR SDWORD
LOCAL ArrayNum: DWORD
mov ArrayNum, 0
mov ecx, inBufferN
sub ecx, esi ; ecx(loop count) from first char to the end
LOOP1:
lea edx, inBuffer
add edx, esi ; edx points the offset of first char
mov edi, esi ; save location of first char
LOOP2: ; check spaces between integers
cmp inBuffer[esi], 20h
je getNum
inc esi
loop LOOP2
jmp getNum ; jump to getNum if array ends with a number
getNum: ; converting char into int
push ecx
inc esi
cmp inBuffer[esi], 20h ; two spaces in a row is considered as no more numbers afterwards
je EndBuffer
dec esi
mov ecx, esi
sub ecx, edi ; length of single number in char
call ParseInteger32
mov edi, ArrayNum
mov intArray[edi], eax
inc ArrayNum
inc esi
pop ecx
loop LOOP1
jmp EndBuffer ; end procedure when loop is over
EndBuffer:
mov eax, ArrayNum
inc eax
ret
ArrayGet ENDP
END main
In case you have questions about my intentions in the code or about the form of the input, feel free to leave it at the comment section
[Solved]
My code should find the minimum value in an array.
In a procedure shown below, the assembly code compares 2 values in an dword array and jumps to setMin part when the second value is below the first. For some reason my program does not jump to setMin even when I can clearly see in the registers during debugging that it should jump.
In result - the min value that is printed out is completely off and I don't know where its from (but that's entirely a different issue).
Here is the code:
; Find the minimum value in the array
; in : arr of 10 dword values
; minIs = "Minimum value is "
; out : eax
;----------------------------------
mov esi, OFFSET arr ; arr adress
mov eax, [esi] ; current min is 1st value
mov ecx, 10 ; loop counter
Lcompare:
add esi, 4 ; next value
mov ebx, [esi]
cmp eax, ebx ; compare 2 values
jb setMin ; Jump if not Below to next
jmp next
setMin:
mov eax, [esi] ; sets new minimum value
next:
loop Lcompare
mov edx, OFFSET minIs
call WriteString ; "Minimum value is "
call WriteInt ; display min value
call Crlf
The arr input: 194, 102, 167, 157, 107, 140, 158, 148, 173, 194
The output:
Minimum value is +1701602643
I would really appreciate if someone could point out why the program does not enter setMin: after jb setMin but instead goes straight to next:.
And as a bonus could someone explain why I am getting that output instead of one of the values from the array?
The comments under the question pointed out my mistakes.
What was wrong:
iterating in the loop 10 times rather than 9. The extra iteration grabbed a string from "the future"
I was finding the maximum rather than the minimum. Switching to cmp ebx, eax solved that.
The FULL working corrected code:
INCLUDE Irvine32.inc
.data
arr dword 10 dup(0)
prompt byte "Select #: "
values byte "The values are: ", 0
comma byte ", ", 0
minIs byte "Minimum value is ", 0
.code
part3 PROC
; Find the minimum value in the array
; in : arr of 10 values
; minIs = "Minimum value is "
; out : eax
;----------------------------------
; use jump if below JB
mov esi, OFFSET arr ; arr adress
mov eax, [esi] ; current min is 1st value
mov ecx, 9 ; loop counter
Lcompare:
add esi, 4 ; next value
mov ebx, [esi]
cmp ebx, eax ; compare 2 values
jnl next ; Jump if not less to next
mov eax, [esi] ; sets new minimum value
next:
loop Lcompare
mov edx, OFFSET minIs
call WriteString ; "Minimum value is "
call WriteInt ; display min value
call Crlf
ret
part3 ENDP
main PROC
mov edx, OFFSET prompt
call WriteString
Call part3
main ENDP
END main
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?
I'm testing to see if an entered string is a palindrome by taking the string, moving it into a character array and comparing first and last elements of the char array to each other to test. I can get the first element of the array to find the second character easily, but to find the last acceptable value and decrement that, it doesn't find the next character in the array. So if the corrected/cleaned char array looks like:
['A']['B']['C']['D']['A']
ebx will go from 'A' -> 'B' but edi will not change from 'A' -> 'D'
Why will ebx change characters but edi only subtracts 1 from it's register value? What can I do to have edi change character value? Thanks!
C++ code: (just in case)
#include <iostream>
#include <cstring>
#include <sstream>
using namespace std;
extern"C"
{
char stringClean(char *, int);
char isPalindrome(char *, int);
}
int main()
{
int pal = 0;
const int SIZE = 30;
string candidate = "";
char strArray[SIZE] = { '\0' };
cout << "enter a string to be tested: ";
getline(cin, candidate);
int j = 0;
for (int i = 0; i < candidate.length(); i++) //getting rid of garbage before entering into array
{
if (candidate[i] <= 'Z' && candidate[i] >= 'A' || candidate[i] <= 'z' && candidate[i] >= 'a')
{
strArray[j] = candidate[i];
j++;
}
}
if (int pleaseWork = stringClean(strArray, SIZE) == 0)
pal = isPalindrome(strArray, SIZE);
if (pal == 1)
cout << "Your string is a palindrome!" << endl;
else
cout << "Your string is NOT a palindrome!" << endl;
system("pause");
return 0;
}
masm code:
.686
.model flat
.code
_isPalindrome PROC ; named _test because C automatically prepends an underscode, it is needed to interoperate
push ebp
mov ebp,esp ; stack pointer to ebp
mov ebx,[ebp+8] ; address of first array element
mov ecx,[ebp+12] ; number of elements in array
mov ebp,0
mov edx,0
mov eax,0
push edi ;save this
push ebx ;save this
mov edi, ebx ;make a copy of first element in array
add edi, 29 ;move SIZE-1 (30 - 1 = 29) elements down to, HOPEFULLY, the last element in array
mov bl, [ebx]
mov dl, [edi]
cmp dl, 0 ;checks if last element is null
je nextElement ;if null, find next
jne Comparison ;else, start comparing at Comparison:
nextElement:
dec edi ;finds next element
mov dl, [edi] ;move next element into lower edx
cmp dl, 0 ;checks if new element is mull
je nextElement ;if null, find next
jne Comparison ;else, start comparing at Comparison:
Comparison:
cmp bl,dl ;compares first element and last REAL element
je testNext ;jump to textNext: for further testing
mov eax,1 ;returns 1 (false) because the test failed
jne allDone ;jump to allDoneNo because it's not a palindrome
testNext:
dec edi ;finds last good element -1 --------THIS ISN'T DOING the right thing
inc ebx ;finds second element
cmp ebx, edi ;checks if elements are equal because that has tested all elements
je allDone
;mov bl,[ebx] ;move incremented ebx into bl
;mov dl,[edi] ;move decremented edi into dl
jmp Comparison ;compare newly acquired elements
allDone:
xor eax, eax
mov ebp, eax
pop edi
pop edx
pop ebp
ret
_isPalindrome ENDP
END
I haven't tested your code, but looking at it I noticed some possible problems.
Why will ebx change characters
It seems that way, but it's not what you tried to reach. You commented out the lines reading the characters from memory/the array after the initial phase (see below). So in fact, you did change the character in EBX, but not the way you expected (and supposedly wanted). With INC EBX you increased the char-value from 'A'(65dec) to 'B'(66dec). That 'B' is also the second char of the string is merely a coincidence. Try changing the string from ABCDA to ARRCD or something and you'd still get a 'B' on the second round. So EBX does indeed change.
...
;mov bl,[ebx] ;move incremented ebx into bl
;mov dl,[edi] ;move decremented edi into dl
jmp Comparison ;compare newly acquired elements
...
but edi only subtracts 1 from it's register value?
What can I do to have edi change character value?
Yes. That's what your code does and it's correct. Uncomment the above line containing [edi] and the char pointed at by EDI will be loaded into the lower byte of EDX = DL.
The problem with your code is that you are using EBX both as a pointer and (char)value. Loading the next char into EBX will destroy the pointer and your programm is likely to crash with ACCESS_VIOLATION in the next iteration or show random behaviour which would be hard to debug.
Separate pointers from values like you have done with EDI/EDX (EDI=pointer to char, EDX(DL)=char value.
Another problem is: your code will only work for strings with an odd length.
testNext:
dec edi ; !!!
inc ebx ; !!!
cmp ebx, edi ; checks if elements are equal because that has tested all elements
je allDone
So you are increasing and decreasing the (should be) pointers and then comparing them. Now consider this case of an even-length-string:
ABBA
^ ^ (EBX(first) and EDI(second))
=> dec both =>
ABBA
^^ (EBX(first) and EDI(second))
=> dec both =>
ABBA
^^ (EDI(first) and EBX(second))
=> dec both =>
ABBA
^ ^ (EDI(first) and EBX(second))
=> dec both =>
ABBA
^ ^ (EDI(first) and EBX(second))
...
=> Problem! Won't terminate, condition EBX=EDI will never be met*
Possible solution: Add an A(Above = Greater for unsigned values) to the jump
...
cmp ebx, edi
jae allDone
I'm having a really hard time with arrays in MASM. I don't understand how to put the value of a register into an index of an array. I can't seem to find where arr[i] is. What is it I'm missing or what do I have wrong?
Thanks for your time!
C++ code:
#include <iostream>
using namespace std;
extern"C"
{
char intToBinary(char *, int, int);
}
int main()
{
const int SIZE = 16;
char arr[SIZE] = { '/0' };
cout << "What integer do you want converted?" << endl;
cin >> decimal;
char value = intToBinary(arr, SIZE, decimal);
return 0;
}
Assembly code:
.686
.model flat
.code
_intToBinary PROC ; named _test because C automatically prepends an underscode, it is needed to interoperate
push ebp
mov ebp,esp ; stack pointer to ebp
mov ebx,[ebp+8] ; address of first array element
mov ecx,[ebp+12] ; number of elements in array
mov edx, 0 ;has to be 0 to check remainder
mov esi, 2 ;the new divisor
mov edi, 12
LoopMe:
add ebx, 4
xor edx, edx ;keep this 0 at all divisions
div esi ;divide eax by 2
inc ebx ;increment by 1
mov [ebp + edi], edx ;put edx into the next array index
add edi, 4 ;add 4 bytes to find next index
cmp ecx, ebx ;compare iterator to number of elements (16)
jg LoopMe
pop ebp ;return
ret
_intToBinary ENDP
END
In your C++ code
decimal is not defined.
'/0' is invalid character literal. Use \, not /, to write escape sequences in C++.
value isn't used.
Your code should be like this:
#include <iostream>
using namespace std;
extern"C"
{
char intToBinary(char *, int, int);
}
int main()
{
const int SIZE = 16;
char arr[SIZE] = { '\0' };
int decimal;
cout << "What integer do you want converted?" << endl;
cin >> decimal;
intToBinary(arr, SIZE, decimal);
for (int i = SIZE - 1; i >= 0; i--) cout << arr[i];
cout << endl;
return 0;
}
In your assembly code
You stored the "address of first array element" to ebx by mov ebx,[ebp+8], so the address of arr will be there.
Unfortunately, it is destroyed by add ebx, 4 and inc ebx.
"put edx into the next array index" No, [ebp + edi] isn't the next array index and it is destoying data on the stack. It is very bad.
Don't add 4 bytes to "find next index" if your size of char is 1 byte.
Your code should be like this (Sorry, this is nasm code because I am unfamiliar to masm):
bits 32
global _intToBinary
_intToBinary:
push ebp
mov ebp, esp ; stack pointer to ebp
push esi ; save this register before breaking in the code
push edi ; save this, too
push ebx ; save this, too
mov ebx, [ebp + 8] ; address of first array element
mov ecx, [ebp + 12] ; number of elements in array
mov eax, [ebp + 16] ; the number to convert
xor edi, edi ; the index of array to store
mov esi, 2 ; the new divisor
LoopMe:
xor edx, edx ; keep this 0 at all divisions
div esi ; divide eax by 2
add dl, 48 ; convert the number in dl to a character representing it
mov [ebx + edi], dl ; put dl into the next array index
inc edi ; add 1 byte to find next index
cmp ecx, edi ; compare iterator to number of elements
jg LoopMe
xor eax, eax ; return 0
pop ebx ; restore the saved register
pop edi ; restore this, too
pop esi ; restore this, too
mov esp, ebp ; restore stack pointer
pop ebp
ret
Note that this code will store the binary text in reversed order, so I wrote the C++ code to print them from back to front.
Also note that there are no terminating null character in arr, so do not do cout << arr;.
You have the address of the first array element in ebx, and edi is your loop counter. So mov [ebx + edi], edx would store edx into arr[edi].
Also note that your loop condition is wrong (your cmp is comparing the number of elements against the starting address of the array.)
Avoid div whenever possible. To divide by two, right-shift by one. div is very slow (like 10 to 30 times slower than a shift).
BTW, since you have a choice of which registers to use (out of the ones the ABI says you're allowed to clobber without saving/restoring), edi is used for a "destination" pointer by convention (i.e. when it doesn't cost any extra instructions), while esi is used as a "source" pointer.
Speaking of the ABI, you need to save/restore ebx in functions that use it, same as ebp. It keeps its value across function calls (because any ABI-compliant function you call preserves it). I forget which other registers are callee-saved in the 32bit ABI. You can check at the helpful links in https://stackoverflow.com/tags/x86/info. 32bit is obsolete; 64bit has a more efficient ABI, and includes SSE2 as part of the baseline.