Well... you could let main() guess, look to see what gcc made of it, and write a called function to suit. Guessing on both ends hasn't been working out well. :)
A compiler needs to know about "types" and stuff, since it has to make up the instructions. An assembler doesn't need to know, since we're telling it the instructions. But *somebody* has to know!
Easiest way is to bit-bucket the C and write the caller in asm, too. That way, there's no guessing. (if there's an error, it's in the assembly part :)
Many people hold a different opinion.
Best,
Frank
; nasm -f elf asmcallfloat64.asm
; link with previously assembled or compiled .o file
; ld -o asmcallfloat64 asmcallfloat64.o asmfloat64.o
; or ld -o asmcallfloat64 asmcallfloat64.o float64.o
global _start
extern float64val
section .data
a dq 63.0e3
hnl db "h", 10
hnl_len equ $ - hnl
word_10 dw 10 ; multiplier for the float-to-ascii routine
section .bss
numbuf resb 80
floatbuf resq 1
bcdbuf rest 1
section .text
_start:
; call our function with "&a"
push a
call float64val
add esp, 4
; result is top of FPU stack - store it
fst qword [floatbuf]
; print it in hex
mov eax, [floatbuf + 4]
call showeaxh
mov eax, [floatbuf]
call showeaxh
; print "h" and a newline
mov ecx, hnl
mov edx, hnl_len
call write_stdout
; result is still on top of FPU stack - convert to ascii
mov edi, numbuf ; buffer for string
mov ecx, 6 ; number of decimal places
call ftoa
; print it
mov ecx, numbuf
; zero-terminated string - we need length
or edx, byte -1
.getlen:
cmp byte [ecx + edx + 1], 1
inc edx
jnc .getlen
call write_stdout
; fudge another newline - skip the "h" :)
mov ecx, hnl + 1
mov edx, 1
call write_stdout
; exit
xor ebx, ebx ; no error (we claim)
mov eax, 1 ; __NR_exit
int 80h
;----------------------
;-----------------------------------------------------
; ftoa - converts floating point to string
;
; Based on some code "sponged" from a post to clax
; From: "Jim Morrison"
;
; Expects: Number to convert is on stack top - st(0)
; edi points to buffer to store string
; ecx = Decimal Places.
;-------------------------------------------------------------
ftoa:
push eax
push ecx
push edx
push edi
push esi
mov edx, ecx ; save a copy of dec places
; if no decimal (integer)
jcxz .f2a2 ; skip multiply by ten loop
.f2a1: ; else loop to "scale" number
fimul word [word_10]
loop .f2a1
.f2a2:
fbstp [bcdbuf] ; convert to bcd and store
mov esi, bcdbuf ; we'll pull digits from there
mov ecx, 9
.f2a3:
lodsb ; get a pair of digits
mov ah, al ; move a copy to ah
shr ah, 4 ; shift out low nibble, keeping high
and eax, 0F0Fh ; mask out the digits we want
add eax, 3030h ; convert 'em both to ascii
push eax
mov al, ah ; swap and store the other digit
push eax
loop .f2a3 ; until done
cmp byte [bcdbuf+9], 0 ; sign flag at bcdbuf + 9 ?
je .f2a6
mov al, '-' ; minus sign if we need it
stosb ; store it at front of our string
.f2a6:
mov ecx, 18
xor dh, dh
inc dl
.poploop:
pop eax
cmp al, '0'
jnz .store
or dh, dh
jnz .store
jmp short .nostore
.store:
stosb
inc dh
.nostore:
cmp cl, dl
jne .nopoint
or dh, dh ; if we haven't encountered a non-zero
jnz .nolz
mov al, '0' ; put a zero before the decimal point
stosb
.nolz:
mov al, '.' ; decimal point
stosb ; and store it
inc dh
.nopoint:
loop .poploop
mov al, 0
stosb
pop esi
pop edi
pop edx
pop ecx
pop eax
ret
;--------------------------------------------------
;---------------------------
write_stdout:
push ebx
mov ebx, 1
mov eax, 4
int 80h
pop ebx
ret
;----------------------------
;------------------------------
showeaxh:
push eax
push ebx
push ecx
push edx
sub esp, 10h
mov ecx, esp
xor edx, edx
mov ebx, eax
.top:
rol ebx, 4
mov al, bl
and al, 0Fh
cmp al, 0Ah
sbb al, 69h
das
mov [ecx + edx], al
inc edx
cmp edx, 8
jnz .top
mov ebx, 1
mov eax, 4
int 80h
add esp, 10h
pop edx
pop ecx
pop ebx
pop eax
ret
;------------------------------