I am tasked at writing a program in C that uses external modules from from a .asm file. I do not have a background in assembly, mainly cpp. However, I managed to get so far into my program using a book by kip Irvine, YouTube videos, etc. All of my code works up to the c2f function, which is where I start having the problems. The entire code is attached in the two separate files, but a code snippet from the .asm file c2f: is below. Basically as soon as it gets to the mov ebx, 5 it calls a segmentation fault core dumped. I tried using the edx register and this causes a floating point core dumped in my terminal. I've literally exhausted all options and I ran across this forum by chance in my search for an answer. Can somebody please help me, rubber ducky hasn't helped.
c2f:
mov eax, [esp+4]
imul eax,9
add eax,160
mov ebx, 5
div ebx
ret
Edit: And I know it would be nice to just have the fix for this, but the why is what's driving me nuts. Even though this is just one assignment and the class is not over assembly, I would like to understand why. I know that when you divide by something the overflow goes into edx, but I don't know why it's causing the errors that it causes. Any help or suggestions is appreciated.
floats are returned in ST0 not in eax.
If floats are returned in STO, then how would the ret function work?
c2f:
mov eax, [esp+4]
imul eax,9
add eax,160
;mov ebx, 5
;div ebx
ret
Noticed the two lines commented out, if I type in 20 in the function, it returns 340. I know that the function is getting that far so the error is in mov ebx, 5 and div ebx.
It is NOT an IF, they do indeed return in ST0. Don't doubt what people here tells you unless you can present evidence.
So, what you have to do is convert the integer to float before the RET. Isn't it obvious?
If you don't want to do it, make the C function wait for an integer.
You get an exception with div ebx because edx is not zero. Use the cdq instruction:
c2f:
mov eax, [esp+4]
imul eax,9
add eax,160
mov ebx, 5
cdq
div ebx
retn 4
Btw which assember are you using? It's definitely not MASM 8)
Quote from: AW on April 29, 2019, 06:49:55 AM
It is NOT an IF, they do indeed return in ST0. Don't doubt what people here tells you unless you can present evidence.
So, what you have to do is convert the integer to float before the RET. Isn't it obvious?
If you don't want to do it, make the C function wait for an integer.
Ok first thing, I was only asking out of clarification because I was only handed a crappy little one liner that isn't blatantly obvious to somebody that hasn't seen this before this week. Second off, no reason to be such a prick about it. While some things may seem nontrivial to you, it may not be so to somebody that just got forced to learn an abundance of the language in a short amount of time. I simply was asking for clarification, I even posted the snippet with what I had commented out and what I had returned up until that point to further clarify where I had gotten. If that is how you react to a clarity question with an explanation of debugging I sincerely hope that you are not a supervisor anywhere because I would really hate to work for your company, or with you for that matter. While I appreciate your reply, I wasn't doubting what you were telling me, maybe the response came off as such, I don't know so I apologize if it did.
Quote from: jj2007 on April 29, 2019, 06:54:46 AM
You get an exception with div ebx because edx is not zero. Use the cdq instruction:
c2f:
mov eax, [esp+4]
imul eax,9
add eax,160
mov ebx, 5
cdq
div ebx
retn 4
Btw which assember are you using? It's definitely not MASM 8)
Thanks for the reply bud! I'll have to look up cdq. I thought it was MASM from what I had looked up. I am taking a systems programming class so I am doing all of this in a dual boot ubuntu system. I'm running straight off the terminal using makefile with my folder. We had been doing nothing but C programming up until this past week. I thought it was assembly for x86 processors :badgrin: oops! Honestly most of my assembly language experience is in MIPS.
I'm still getting a core dumped, but I'm looking into it. Thanks for pointing me in the right direction!
cdq sign-extends eax to edx: if eax is positive, edx will be set to zero, if eax is negative, edx will be -1.
Here are two variants of your code, both return the result in eax
and in ST(0):
c2f:
mov eax, [esp+4]
imul eax,9
add eax,160
mov ebx, 5
cdq
div ebx
push eax
fild dword ptr [esp]
pop eax
retn 4
c2fx:
fild dword ptr [esp+4]
push 9
fimul dword ptr [esp] ; mul 9
pop edx
push 160
fiadd dword ptr [esp] ; add 160
pop edx
push 5
fidiv dword ptr [esp] ; div 5
fist dword ptr [esp]
pop eax
retn 4
Quote from: RKC on April 29, 2019, 06:59:00 AMno reason to be such a prick about it.
José doesn't need a reason :P
Thank you! I'm actually at a tossup between this or MIPS. I'll admit it's rather nice not having to type a $ all the time hahaha! I found some good documentation on cdq but this helps a lot.
I see the problem, it's actually NASM, not sure if that makes a massive difference but the ptr will not work in it.
I attach a Visual Studio project with the asm converted to MASM.
The reason for the crash is not the CDQ, I am not using any CDQ, JJ is still learning the basics.
If you want float precision you will have to convert as I told you before. Otherwise the C will round it.
NASM is a free form assembly language.
Quote from: AW on April 29, 2019, 07:28:14 AM
I attach a Visual Studio project with the asm converted to MASM.
The reason for the crash is not the CDQ, I am not using any CDQ, JJ is still learning the basics.
If you want float precision you will have to convert as I told you before. Otherwise the C will round it.
NASM is a free form assembly language.
Thank you both, I really appreciate the time that y'all spent helping me. I've gotten past one barrier so far and onto another one in my own code. It is hard to know what C will and won't do with code sometimes, I noticed what you told me was exactly right and I appreciate it, just working on converting it now.
Quote from: AW on April 29, 2019, 07:28:14 AMThe reason for the crash is not the CDQ, I am not using any CDQ, JJ is still learning the basics.
I know I shouldn't feed the troll, but for RKC: Without the cdq, the code
will crash at the div, with exception C0000095 alias INTEGER_OVERFLOW. It may not crash if by accident edx is between 0 and 4. I've debugged the code, I know what I'm doing.
Btw, since temperatures can be negative, the correct way of dividing is using
idiv:
mov ebx, 5
cdq
idiv ebx
Explain how it will "crash". Do you know how DIV works?
DIV : Unsigned divide EDX:EAX by r/m32, with result stored in EAX ← Quotient, EDX ← Remainder.
What can happen is a wrong result but how will it crash? Probably you must make a proof in Basic. :badgrin:
When you are short of arguments, you start insulting people, José.
include \masm32\include\masm32rt.inc
.code
start:
mov eax, 610 ; e.g. in RKC's example for C=50: 50*9+160
mov edx, 5 ; any value except 0...4 will crash
mov ebx, 5
div ebx ; exception C0000095 alias INTEGER_OVERFLOW
inkey str$(eax)
exit
end start
You may google for "If the quotient is too large for the designated register" (with quotes).
Very good, it is the first time I have to concede to you! Time to open that bottle of champagne you have in the fridge for so long. :t
Actually is not yet time to open the bottle of champagne. Sorry for that. :(
I don't believe in good luck, so I revisited the code. In the call to "num" edx is zeroed before the return. In the "C" part, all that is done after the return is push eax and call cf2. So edx is 0 (zero) within cf2 (unless you enter an absurdly high value for Celsius that makes the multiplication result over a dword). In conclusion, again, the reason for the crash is not the overflow. :P
Sorry for this my troll friend.
Quote from: AW on April 29, 2019, 03:12:12 PMIn the call to "num" edx is zeroed before the return. In the "C" part, all that is done after the return is push eax and call cf2. So edx is 0 (zero)
Assuming that the C compiler leaves edx intact! Actually, I had not looked at the C code, and tested the asm code in isolation - my fault. So,
if the C compiler kindly does not touch edx before calling c2f,
then edx is still zero, and the cdq is not needed. Still, it would be very bad to rely on that behaviour (besides, mov edx, 0 is 5 bytes, cdq is only one). Furthermore, the
cdq with
idiv allows negative temperatures, the
mov edx, 0 doesn't.
Here is complete code for use with Pelles C and MASM:
#include <stdio.h>
#pragma comment(linker, "c2f.obj /subsystem:console" )
extern int num();
extern double c2f(int n);
int main() {
int number = num();
// __asm int 3;
double ret = c2f(number);
printf("c2f returned %f\n", ret);
_getch();
return 0;
}
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \Masm32\include\msvcrt.inc
includelib \Masm32\lib\msvcrt.lib
include \Masm32\include\Kernel32.inc
includelib \Masm32\lib\Kernel32.lib
.data
message db "The temperture in Fahrenheits: %d Reminder: %d", 10, 0
request db "Enter a temperature in Celsius: ", 0
celsius dd 0 ; 32-bits integer = 4 bytes
formatin db "%d", 0
txCrt db "msvcrt.dll", 0
txPrintf db "printf", 0
txScanf db "scanf", 0
.code
num proc C
; Ask for an integer
push offset request
invoke LoadLibrary, offset txCrt
invoke GetProcAddress, eax, offset txPrintf
call dword ptr eax ; crt_printf
add esp, 4 ; remove the parameter
push offset celsius ; address of integer1, where the input is going to be stored (second parameter)
push offset formatin ; arguments are right to left (first parameter)
invoke LoadLibrary, offset txCrt
invoke GetProcAddress, eax, offset txScanf
call dword ptr eax ; crt_printf
add esp, 8 ; remove the parameters
; Move the value under the address integer1 to EAX
; mov edx, 0 wrong
mov eax, celsius
ret
num endp
c2f proc C arg
mov eax, arg
imul eax,9
add eax,160
mov ebx, 5
; INT 3
cdq ; allow negative
idiv ebx ; temperatures
push eax
fild dword ptr [esp]
pop eax
ret
c2f endp
END
Stupid question:
how that c2f function was defined in that exercise ?
should c2f function return int or double, or both ?
If celsius is an integer, result is also truncated to decimal, so is the fpu needed in that asm function ?
with extern int c2f(int n); C compiler can convert int to double for printf.