Assembly language with C++ - c++

I should write the program using C++ and Assembly. Program must count the average of the array.
The CPP file must take the data from the user and display the result.In the array must be the real numbers (with floating-point).
The ASM file must count the average of this array.
That is the .cpp file:
#include <iostream.h>
#define L 4
extern "C" float average(float* tab, int G);
int main()
{
float tab[L]={0};
cout<<"Enter array: \n";
for(int i=0; i<L; i++)
cin >> tab[i];
cout << "Average value of entered array = " << average(tab, L);
cout << "\nThe end of the programm\n";
return 0;
}
And here is my assembly code:
.386
.model SMALL,c
PUBLIC average
.stack 100h
.data
.code
average PROC
push ebp
mov ebp, esp
push esi
mov ecx, [ebp+12]
mov esi, [ebp+8]
finit ;coprocessor
fldz
sum:
fadd dword ptr [esi+ecx-4] ;ST(0)=ST(0)+ST(i)
loop sum ;retry sum while cx!=0
fidiv dword ptr [ebp+12] ;Division
pop esi ;End of the programm
pop ebp
mov eax, esi
ret 8
average ENDP
END
The result always is 2.422547e+198
Where I have the mistake? Thank you!

Since it's an array of floats each taking 4 bytes you should multiply the index by 4. Also note that C calling convention mandates that the caller will free the arguments, as such your "ret 8" is wrong.
The mov eax, esi at the end is irrelevant.

Related

Unexpected page fault when writing return value from assembly procedure

I am experimenting mixing assembly(x86) and C++.
I wrote a procedure in assembly and then called it from C++.
However, when writing the returned value to a local variable I get a write permission violation error.
#include <iostream>
// will return 1 if all ok and 0 if b is 0
extern "C" int integerMulDiv(int a, int b, int* prod, int* quo, int* rem);
int main() {
int a = 13, b = 4;
int p, q, r;
int res = integerMulDiv(a, b, &p, &q, &r);
std::cout << p << '\t' << q << '\t' << r << std::endl;
std::cout << res << std::endl << std::endl;
res = integerMulDiv(31, 0, &p, &q, &r);
std::cout << p << '\t' << q << '\t' << r << std::endl;
std::cout << res << std::endl << std::endl;
return 0;
}
The assembly procedure returns a few values through pointers and an int through RAX.
; Returns : 0 Error (division by 0)
; : 1 All ok
; *prod = a * b
; *quo = a / b
; *rem = a % b
integerMulDiv proc
push ebp
mov ebp, esp
push ebx ; save ebp and ebx
xor eax, eax
mov ecx, [ebp + 8] ; get a
mov edx, [ebp + 12] ; get b (the divisor)
or edx, edx ; check divisor
jz invalidDivizor
imul edx, ecx
mov ebx, [ebp + 16] ; get address of prod
mov [ebx], edx ; write prod
mov eax, ecx
cdq ; extend to edx
idiv dword ptr[ebx + 12]
mov ebx, [ebp + 20] ; get address of quo
mov [ebp], eax ; write quo
mov ebx, [ebp + 24] ; get address of rem
mov [ebp], edx ; write rem
mov eax, 1 ; set success
jmp returnFromProc
invalidDivizor:
mov eax, 0 ; set failed
returnFromProc:
pop ebx
pop ebp
ret ; restore and return
integerMulDiv endp
I get the error after the first call of integerMulDiv, when it tries to write the result in the res variable.
The disassembly looks like this:
int res = integerMulDiv(a, b, &p, &q, &r);
002D24BD lea eax,[r]
002D24C0 push eax
002D24C1 lea ecx,[q]
002D24C4 push ecx
002D24C5 lea edx,[p]
002D24C8 push edx
002D24C9 mov eax,dword ptr [b]
002D24CC push eax
002D24CD mov ecx,dword ptr [a]
002D24D0 push ecx
002D24D1 call _integerMulDiv (02D133Eh)
002D24D6 add esp,14h
002D24D9 mov dword ptr [res],eax <- The #PF happens here
Does anyone know what is happening and why?
The following section of code stands out to me.
idiv dword ptr[ebx + 12]
mov ebx, [ebp + 20] ; get address of quo
mov [ebp], eax ; write quo
mov ebx, [ebp + 24] ; get address of rem
mov [ebp], edx ; write rem
I am not sure you are wanting to divide by the contents of memory 12 bytes after the address of the product. Perhaps you meant [ebp + 12].
After that, you are loading addresses into ebx and then writing values to ebp.

Less aggressive loop optimization when using printf than cout

This question is a followup to this one:
Question on Undefined Behaviour (UB) and loop optimization
When using https://godbolt.org/ online compiler (g++ 7.2, x86_64) with -O2 setting, the loop condition gets optimized out when the loop contains std::cout but not with an identical loop using printf.
Any idea why? Both code versions are compiled with the C++ compiler. Both versions produce an UB warning, but no warning without -O2, even though the code is still in UB land.
FWIW, I also tried the MIPS g++ compiler, that one does not seem to optimize out the loop condition even with std::cout code version and -O2.
I can provide the compiler outputs if necessary, but the std::cout version is quite long.
#include <stdio.h>
int main()
{
for (int i = 0; i < 300; i++)
printf("%d %d", i, i*12345678);
}
/*#include <iostream>
int main()
{
for (int i = 0; i < 300; i++)
std::cout << i << " " << i * 12345678 << std::endl;
}*/
UPDATE: On suggestion from the comments, I removed the UB, then even the printf version removes the loop condition, instead jumping out of the loop when i is 11 (very unsurprising), see below:
#include <stdio.h>
int main()
{
for (int i = 0; i < 300; i++) {
printf("%d %d", i, i*123);
if (i * 123 > 1230) break;
}
}
// Generated assembly:
LC0:
.string "%d %d"
main:
push rbp
push rbx
xor edx, edx
xor esi, esi
mov edi, OFFSET FLAT:.LC0
xor eax, eax
sub rsp, 8
mov ebp, 123
xor ebx, ebx
call printf
.L2:
add ebx, 1
mov edx, ebp
xor eax, eax
mov esi, ebx
mov edi, OFFSET FLAT:.LC0
add ebp, 123
call printf
cmp ebx, 11
jne .L2
add rsp, 8
xor eax, eax
pop rbx
pop rbp
ret

When linking ASM to C++ file, there is an access violation

To give you context over the code, this is a dot product computation of two vectors using pointer arithmetic (looping with pointers as well). I have linked it in my main.cpp but for some reason, when the function is called (in this case, my ASM file), i get an access violation error. Here are the two files. Thank you for your help!
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <algorithm>
#include <iostream>
using namespace std;
extern "C" int dpp_pointerr(int *v, int *u, int n); //ASM FILE
void main(void) {
const int N = 10;
static int A[10];
static int B[10];
printf("Array A: ");
for (int i = 0; i < N; i++) { A[i] = rand() % 10; /*printf("%d ", A[i]); */ }
printf("\n\nArray B: ");
for (int j = 0; j < N; j++) { B[j] = rand() % 10;/* printf("%d ", B[j]);*/ }
printf("\n");
int result2 = dpp_pointerr(A, B, N);
printf("\nResult after POINTER dot product: %d\n", result2);
__int64 ctr1 = 0, ctr2 = 0, freq = 0;
int acc = 0, i = 0;
if (QueryPerformanceCounter((LARGE_INTEGER *)&ctr1) != 0) {
/****************CODE TO BE TIMED HERE**********************/
//int result3= dot_product_index(A, B, N);
int result2 = dpp_pointerr(A, B, N);
/**********************************************************/
QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
cout << "Start Value: " << ctr1 << endl;
cout << "End Value: " << ctr2 << endl;
QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
// freq is number of counts per second. It approximates the CPU frequency
printf("QueryPerformanceCounter minimum resolution: 1/%I64u Seconds.\n", freq);
printf("ctr2 - ctr1: %f counts.\n", ((ctr2 - ctr1) * 1.0 / 1.0));
cout << "65536 Increments by 1 computation time: " << ((ctr2 - ctr1) * 1.0 / freq) << " seconds\n";
}
else {
DWORD dwError = GetLastError();
printf("Error value = %d", dwError);
}
cout << endl;
cout << "Press ENTER to finish";
system("pause");
}
ASM FILE
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.11.25547.0
TITLE C:\Users\Patrick\source\repos\dot_product_legit\dot_product_legit\dpp_pointerr.cpp
.686P
.XMM
include listing.inc
.model flat, C
PUBLIC dpp_pointerr
_TEXT SEGMENT
_result$ = -32 ; size = 4
_B_beg$ = -20 ; size = 4
_A_beg$ = -8 ; size = 4
_v$ = 8 ; size = 4
_u$ = 12 ; size = 4
_n$ = 16 ; size = 4
?dpp_pointerr##YAHPAH0H#Z:
dpp_pointerr PROC ; dot_product_pointer, COMDAT
push ebp
mov ebp, esp
sub esp, 228 ; 000000e4H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-228]
mov ecx, 57 ; 00000039H
mov eax, -858993460 ; ccccccccH
rep stosd
mov DWORD PTR _result$[ebp], 0
; Line 11
; Line 2
push ebp
mov ebp, esp
sub esp, 228 ; 000000e4H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-228]
mov ecx, 57 ; 00000039H
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 5
mov eax, 4
imul ecx, eax, 0
add ecx, DWORD PTR _v$[ebp]
mov DWORD PTR _A_beg$[ebp], ecx
; Line 6
mov eax, 4
imul ecx, eax, 0
add ecx, DWORD PTR _u$[ebp]
mov DWORD PTR _B_beg$[ebp], ecx
; Line 8
mov DWORD PTR _result$[ebp], 0
; Line 11
mov eax, DWORD PTR _A_beg$[ebp]
mov ebx, DWORD PTR _B_beg$[ebp]
mov ecx, DWORD PTR _n$[ebp]
mov edi, DWORD PTR _v$[ebp]
lea edi, DWORD PTR [edi+ecx*4]
mov esi, DWORD PTR _u$[ebp]
lea esi, DWORD PTR [esi+ecx*4]
jmp SHORT $LN4#dot_produc
$LN2#dot_produc:
add eax, 4
add ebx, 4
$LN4#dot_produc:
cmp eax, edi
jae SHORT $LN3#dot_produc
cmp ebx, esi
jae SHORT $LN3#dot_produc
; Line 12
imul eax, ebx
add DWORD PTR _result$[ebp], eax
jmp SHORT $LN2#dot_produc
$LN3#dot_produc:
; Line 13
mov eax, DWORD PTR _result$[ebp]
; Line 14
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
dpp_pointerr ENDP ; dot_product_pointer
_TEXT ENDS
END

Working on Array inside Struct , with Assembly

Im trying to check the even numbers from an array inside a struct, but i dont think i wrote something right. When debugging, (i.e. count = 3 v[] = {1,2,4}), after it reaches " cmp eax,[ebp+12] and je outt; " , it goes to outt: and thats it.
s is supposed to keep the sum of all even numbers, eax inside int suma(test *) is index for array, and edx keeps the sum before moving it in s
what am i doing wrong?
#include "stdafx.h"
#include <iostream>
using namespace std;
struct test {
int v[10];
short count;
};
test a;
int s = 6;
int suma(test *)
{
_asm {
mov eax, 0; // i for counting inside array
mov edx, 0; // sum of even elements
mov ebx, [ebp + 8]; // array v adress
loop:
cmp eax, [ebp + 12];
je outt;
mov ecx, [ebx + 4 * eax];
inc eax;
mov edi, ecx
and ecx, 1;
cmp ecx, 1;
je loop;
add edx, edi;
jmp loop;
outt:
mov eax, edx;
}
return s;
}
int main()
{
cin >> a.count;
for (int i = 0; i < a.count; i++)
cin >> a.v[i];
_asm {
LEA eax, a
push eax;
call suma;
add esp, 4;
mov s, eax;
}
cout << s;
return 0;
}

Passing arguments from c++ to assembly in cout

I'm writing simple mix of c++ and nasm assembly atm and dont understand why the results are different inside and outside of the "cout". Maybe this is some kind of exception however I would like to know the difference.Thanks for any help.
C++ PART
#include <iostream>
#include <cstring>
using namespace std;
extern "C" unsigned int quot (unsigned int, unsigned int);
extern "C" unsigned int remainder (unsigned int, unsigned int);
int main()
{
unsigned int i=0, j=0, k=0;
cout << "Numbers 'x y'" << endl;
cin >> i >> j;
k = quot(i,j);
cout<< "Result: " <<k;
k = remainder(i,j);
cout <<" r. "<< k <<endl;
cout << "Result: "<<quot(i,j)<<" r. "<<remainder(i,j)<<endl;
return 0;
}
NASM
quot and reminder functions are almost the same. the only difference is commented in the code
section .data
section .text
global quot
quot:
; intro
push ebp
mov ebp,esp
xor edx, edx
mov eax, [ebp+8]
mov ebx,[ebp+12]
div ebx
; DIFFERENCE: in remainder we have additionaly
; mov eax, edx
mov esp,ebp
pop ebp
ret
RESULTS
For 12 5 input we expect Result: 2 r. 2 but we obtain.
Result: 2 r. 2
Result: 2 r. 5
You have to preserve value of ebx in your asm functions (see http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl). Violating the calling convention may result in various range of errors, from subtle to crashes.
Use ecx instead of ebx, or try div dword ptr [ebp+12].