====== Scenario x64_6: Passing floating point parameters. Floating-point calculation function. ======
In this scenario, we will extend our math library with a function performing the simple calculations on single-precision floating-point values. We will start by writing a function for adding six values. This example will present argument passing through the XMM registers and also through the stack, showing the order and addresses of stack-allocated arguments.
** Prerequisites **\\
Read the section “Creating static libraries”. Go through previous scenarios where the conversion library and main program are described, and the initial code of both is presented. You should have the main program and library with conversion functions ready to be able to print results in a console.
** Scenario **\\
Extend the code of a library with an additional function to calculate the sum of six floating-point arguments.
** Result **\\
The sum is properly calculated and displayed by programs prepared in the previous scenarios.
** Start **\\
You can make a copy of a function that calculates the sum of six integers.
** Step 1**\\
The function adds six floating-point values. It takes the first four arguments from XMM registers, and the latter two from the stack. Please note that for each argument, there is an 8-byte space reserved on the stack.
.data
; define six floating point variables
float_0 real4 1.0
float_1 real4 2.0
float_2 real4 3.0
float_3 real4 4.0
float_4 real4 0.3
float_5 real4 0.4
.code
; ---------------------------------
; sum of six floating-point arguments
; this is a leaf function
; does not need to reserve shadow space
; arguments passed as MSVC does
; a = XMM0
; b = XMM1
; c = XMM2
; d = XMM3
; e = [RSP + 28h]
; f = [RSP + 30h]
; ---------------------------------
sum_6_float proc
addss xmm0, xmm1 ; a + b
addss xmm0, xmm2 ; + c
addss xmm0, xmm3 ; + d
movss xmm1, DWORD PTR [rsp + 28h]
addss xmm0, xmm1 ; + e
movss xmm1, DWORD PTR [rsp + 30h]
addss xmm0, xmm1 ; + f
ret
sum_6_float endp
The function is called from a main program. The caller passes arguments according to the Windows x64 ABI. First four arguments through XMM0 - XMM3 registers. Further arguments are placed onto the stack. The caller is also responsible for reserving the shadow space for all arguments before the call, even those passed through registers.
** Step 2 **\\
To call the function, we will use the approach in which the caller first reserves the shadow space for all six arguments and later puts the last two of them using indirect **movss** instructions.
The **movss** instruction copies a scalar single-precision value to the lower quarter of the XMM register. Please refer to the instruction set description for details.
;call sum of 6 floating-point function
sub rsp, 30h ; 48 bytes of shadow space
movss xmm0, float_0 ; 1st argument
movss xmm1, float_1 ; 2nd argument
movss xmm2, float_2 ; 3rd argument
movss xmm3, float_3 ; 4th argument
movss xmm4, float_4 ; 5th argument
movss DWORD PTR [rsp+20h], xmm4
movss xmm5, float_5 ; 6th argument
movss DWORD PTR [rsp+28h], xmm5
call sum_6_float ; function call
add rsp, 30h ; stack cleanup
; result in xmm0
** Result validation **\\
The code of a function should be called from the main program. After obtaining the result of an addition, you should call the conversion function and later display the floating-point value in a console.
** If it does not print the proper value? **\\
Please remember the order and placement of the arguments and result. Please keep the Windows ABI calling convention and preserve any non-volatile register before use. Observe the stack; every modification you make before a function call or inside the function should be reversed afterwards.