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.
;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.