%define SYS_read 0 %define SYS_write 1 %define SYS_poll 7 %define SYS_exit 60 %define FD_stdin 0 %define FD_stdout 1 %define FD_stderr 2 %define POLLIN 1 section .text global _start _start: prompt_weight: mov rax,SYS_write mov rdi,FD_stdout mov rsi,weight_prompt_text mov rdx,weight_prompt_length syscall call read_float cmp rax,0 jne good_weight call clear_stdin jmp prompt_weight good_weight: ; convert weight to kg divss xmm0,[lb_kg_scale] movq r15,xmm0 ; weight prompt_height: mov rax,SYS_write mov rdi,FD_stdout mov rsi,height_prompt_text mov rdx,height_prompt_length syscall call read_float cmp rax,0 jne good_height call clear_stdin jmp prompt_height good_height: ; convert height to cm mulss xmm0,[inch_cm_scale] movq r14,xmm0 ; height ; print metric weight mov rax,SYS_write mov rdi,FD_stdout mov rsi,weight_notice_pre_text mov rdx,weight_notice_pre_length syscall movq xmm0,r15 mov rdi,3 call print_float mov rax,SYS_write mov rdi,FD_stdout mov rsi,weight_notice_post_text mov rdx,weight_notice_post_length syscall ; print metric height mov rax,SYS_write mov rdi,FD_stdout mov rsi,height_notice_pre_text mov rdx,height_notice_pre_length syscall movq xmm0,r14 mov rdi,3 call print_float mov rax,SYS_write mov rdi,FD_stdout mov rsi,height_notice_post_text mov rdx,height_notice_post_length syscall ; calculate bmi (kg/(m^2)) movq xmm1,r14 ; height divss xmm1,[_100f] ; cm to m mulss xmm1,xmm1 movq xmm0,r15 ; weight divss xmm0,xmm1 movq r15,xmm0 ; bmi ; write bmi mov rax,SYS_write mov rdi,FD_stdout mov rsi,bmi_notice_text mov rdx,bmi_notice_length syscall movq xmm0,r15 mov rdi,3 call print_float mov rax,SYS_write mov rdi,FD_stdout mov rsi,newline_char mov rdx,1 syscall call clear_stdin ; exit xor rdi,rdi mov rax,SYS_exit syscall clear_stdin: ; 16 - read buff ; 4 - pollfd.fd ; 2 - pollfd.events ; 2 - pollfd.revents sub rsp,24 mov DWORD [rsp+16],FD_stdin mov WORD [rsp+20],POLLIN clear_stdin_loop: mov rax,SYS_poll lea rdi,[rsp+16] mov rsi,1 xor rdx,rdx syscall cmp rax,0 jle clear_stdin_end mov rax,SYS_read mov rdi,FD_stdin mov rsi,rsp mov rdx,16 syscall jmp clear_stdin_loop clear_stdin_end: add rsp,24 ret print_float: ; void print_float(float f, int percission) sub rsp,24 movss xmm1,[_10f] mov rcx,rdi print_float_scale_loop: mulss xmm0,xmm1 loop print_float_scale_loop ; put digits in memory cvtss2si rax,xmm0 mov rcx,23 mov rbx,10 print_float_reverse_loop: xor rdx,rdx div rbx add rdx,'0' mov [rsp+rcx],dl dec rcx cmp rax,0 jne print_float_reverse_loop push rcx push rdi add rcx,17 ; number to write mov rdx,rcx sub rdx,40 imul rdx,-1 sub rdx,rdi mov rax,SYS_write mov rdi,FD_stdout lea rsi,[rsp+rcx] syscall mov rax,SYS_write mov rdi,FD_stdout mov rsi,period_char mov rdx,1 syscall pop rdi pop rcx lea rsi,[rsp+24] sub rsi,rdi mov rdx,rdi mov rax,SYS_write mov rdi,FD_stdout syscall add rsp,24 ret ; on error, return 0 in rax. otherwise, return 1 in rax ; and the result in xmm0 read_float: ; float read_float() push r15 ; read count push r14 ; whole part sub rsp,21 ; read buffer xor r15,r15 mov r14,-1 read_float_loop: cmp r15,20 je read_float_size_error mov rax,SYS_read mov rdi,FD_stdin lea rsi,[rsp+20] mov rdx,1 syscall mov dil,[rsp+20] cmp r15,0 sete ah cmp dil,'0' sete al and al,ah jnz read_float_loop cmp dil,' ' sete al and al,ah jnz read_float_loop cmp dil,0xA ; \n je read_float_convert cmp dil,'.' je read_float_start_decimal call is_number ; dil is preserved cmp rax,0 je read_float_num_error sub dil,'0' mov [rsp+r15],dil inc r15 xor rax,rax cmp r14,-1 setne al add r14,rax jmp read_float_loop read_float_start_decimal: cmp r14,-1 jne read_float_num_error xor r14,r14 jmp read_float_loop read_float_convert: ; zero r14 if it is -1 xor rax,rax cmp r14,-1 cmove r14,rax ; invert scale sub r14,r15 imul r14,-1 mov rax,0 movq xmm0,rax xor rcx,rcx read_float_convert_whole_loop: cmp rcx,r14 je read_float_convert_dec_prepare mulss xmm0,[_10f] xor eax,eax mov al,[rsp+rcx] cvtsi2ss xmm1,eax addss xmm0,xmm1 inc rcx jmp read_float_convert_whole_loop read_float_convert_dec_prepare: mov rax,1 ; return value movss xmm7,[_0.1f] movss xmm6,[_10f] read_float_convert_dec_loop: cmp rcx,r15 je read_float_end xor ebx,ebx mov bl,[rsp+rcx] cvtsi2ss xmm1,ebx mulss xmm1,xmm7 addss xmm0,xmm1 divss xmm7,xmm6 inc rcx jmp read_float_convert_dec_loop read_float_end: add rsp,21 pop r14 pop r15 ret read_float_num_error: mov rax,SYS_write mov rdi,FD_stderr mov rsi,num_error_text mov rdx,num_error_length syscall mov rax,0 jmp read_float_end read_float_size_error: mov rax,SYS_write mov rdi,FD_stderr mov rsi,size_error_text mov rdx,size_error_length syscall mov rax,0 jmp read_float_end ; dil is preserved across calls is_number: ; bool is_number(char n) cmp dil,'0' jl is_number_fail cmp dil,'9' jg is_number_fail mov rax,1 ret is_number_fail: xor rax,rax ret section .data num_error_text: db "Invalid number!",0xA num_error_length: equ $ - num_error_text size_error_text: db "Number too long!",0xA size_error_length: equ $ - size_error_text period_char: db "." newline_char: db 0xA _10f: dd 10.0 _0.1f: dd 0.1 _100f: dd 100.0 inch_cm_scale: dd 2.54 lb_kg_scale: dd 2.20462 weight_prompt_text: db "Enter weight (pounds): " weight_prompt_length: equ $ - weight_prompt_text height_prompt_text: db "Enter height (inches): " height_prompt_length: equ $ - height_prompt_text height_notice_pre_text: db "Your metric height: " height_notice_pre_length: equ $ - height_notice_pre_text height_notice_post_text: db "cm",0xA height_notice_post_length: equ $ - height_notice_post_text weight_notice_pre_text: db "Your metric weight: " weight_notice_pre_length: equ $ - weight_notice_pre_text weight_notice_post_text: db "kg",0xA weight_notice_post_length: equ $ - weight_notice_post_text bmi_notice_text: db "Your BMI: " bmi_notice_length: equ $ - bmi_notice_text