Reputation: 1
Summary: We have an int variable and 4 double arrays in C, 2 of which hold input data and 2 of which we want to write output data to. We pass the variable and arrays to a function in an external .asm file, where the input data is used to determine output data and the output data is written to the output arrays.
Our problem is, that the output arrays remain seemingly untouched after the assembly routine finishes its work. We don't even know, if the routine reads the correct input data. Where did we go wrong?
We compile with the following commands
nasm -f elf32 -o calculation.o calculation.asm
gcc -m32 -o programm main.c calculation.o
If you need any more information, feel free to ask.
C code:
// before int main()
extern void calculate(int32_t counter, double radius[], double distance[], double paper[], double china[]) asm("calculate");
// in int main()
double radius[counter];
double distance[counter];
// [..] Write Input Data to radius & distance [...]
double paper[counter];
double china[counter];
for(int i = 0; i < counter; i++) {
paper[i] = 0;
china[i] = 0;
}
calculate(counter, radius, distance, paper, china);
// here we expect paper[] and china[] to contain output data
Our Assembly code currently only takes in the values, puts them into the FPU, then places them into the output array.
x86 Assembly (Intel Syntax) (I know, this code looks horrible, but we're beginners, so bear with us, please; Also I can't get syntax highlighting to work correctly for this one):
BITS 32
GLOBAL calculate
calculate:
SECTION .BSS
; declare all variables
pRadius: DD 0
pDistance: DD 0
pPaper: DD 0
pChina: DD 0
numItems: DD 0
counter: DD 0
; populate them
POP DWORD [numItems]
POP DWORD [pRadius]
POP DWORD [pDistance]
POP DWORD [pPaper]
POP DWORD [pChina]
SECTION .TEXT
PUSH EBX ; because of cdecl calling convention
JMP calcLoopCond
calcLoop:
; get input array element
MOV EBX, [counter]
MOV EAX, [pDistance]
; move it into fpu, then move it to output
FLD QWORD [EAX + EBX * 8]
MOV EAX, [pPaper]
FSTP QWORD [EAX + EBX * 8]
; same for the second one
MOV EAX, [pRadius]
FLD QWORD [EAX + EBX * 8]
MOV EAX, [pChina]
FSTP QWORD [EAX + EBX * 8]
INC EBX
MOV [counter], EBX
calcLoopCond:
MOV EAX, [counter]
MOV EBX, [numItems]
CMP EAX, EBX
JNZ calcLoop
POP EBX
RET
Upvotes: 0
Views: 359
Reputation: 1
Thanks to all your answers and comments and some heavy research, we managed to finally produce functioning code, which now properly uses stack frames and fulfills the cdecl calling convention:
BITS 32
GLOBAL calculate
SECTION .DATA
electricFieldConstant DQ 8.85e-12
permittivityPaper DQ 3.7
permittivityChina DQ 7.0
SECTION .TEXT
calculate:
PUSH EBP
MOV EBP, ESP
PUSH EBX
PUSH ESI
PUSH EDI
MOV ECX, 0 ; counter for loop
JMP calcLoopCond
calcLoop:
MOV EAX, [EBP + 12]
FLD QWORD [EAX + ECX * 8]
MOV EAX, [EBP + 20]
FSTP QWORD [EAX + ECX * 8]
MOV EAX, [EBP + 16]
FLD QWORD [EAX + ECX * 8]
MOV EAX, [EBP + 24]
FSTP QWORD [EAX + ECX * 8]
ADD ECX, 1 ; increase loop counter
calcLoopCond:
MOV EDX, [EBP + 8]
CMP ECX, EDX
JNZ calcLoop
POP EDI
POP ESI
POP EBX
MOV ESP, EBP
POP EBP
RET
Upvotes: 0
Reputation: 33757
There are a couple of problems in the assembler routine. The POP
instructions are emitted into the .bss
section, so they are never executed. In the sequence of POP
s, the return address (pushed by the caller) is not accounted for. Depending on the ABI, you must leave the arguments on the stack anyway. Because the POP
s are never executed, the loop exit condition always happens to be true.
And you really should not use global variables this way. Instead, create a stack frame and use that.
Upvotes: 2