12.7: Example, Statistical Function2 (non-leaf)
- Page ID
- 58054
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\dsum}{\displaystyle\sum\limits} \)
\( \newcommand{\dint}{\displaystyle\int\limits} \)
\( \newcommand{\dlim}{\displaystyle\lim\limits} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\(\newcommand{\longvect}{\overrightarrow}\)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)This extended example will demonstrate calling a simple void function to find the minimum, median, maximum, sum and average of an array of numbers.
The High-Level Language (HLL) call for C/C++ is as follows:
stats2(arr, len, min, med1, med2, max, sum, ave);
For this example, it is assumed that the array is sorted in ascending order. Additionally, for this example, the median will be the middle value. For an even length list, there are two middle values, med1 and med2, both of which are returned. For an odd length list, the single middle value is returned in both med1 and med2.
As per the C/C++ convention, the array, arr, is call-by-reference and the length, len, is call-by-value. The arguments for min, med1, med2, max, sum, and ave are all call-by- reference (since there are no values as yet). For this example, the array arr, min, med1, med2, max, sum, and ave variables are all signed double-word integers. Of course, in context, the len must be unsigned.
Caller
In this case, there are 8 arguments and only the first six can be passed in registers. The last two arguments are passed on the stack. The assembly language code in the calling routine for the call to the stats function would be as follows:
; stats2(arr, len, min, med1, med2, max, sum, ave);
push ave ; 8th arg, add of ave
push sum ; 7th arg, add of sum
mov r9, max ; 6th arg, add of max
mov r8, med2 ; 5th arg, add of med2
mov rcx, med1 ; 4th arg, add of med1
mov rdx, min ; 3rd arg, addr of min
mov esi, dword [len] ; 2nd arg, value of len
mov rdi, arr ; 1st arg, addr of arr
call stats2
add rsp, 16 ; clear passed arguments
The 7th and 8th arguments are passed on the stack and pushed in reverse order in accordance with the standard calling convention. After the function is completed, the arguments are cleared from the stack by adjusting the stack point register (rsp). Since two arguments, 8 bytes each, were passed on the stack, 16 is added to the stack pointer.
Note, the setting of the esi register also sets the upper-order double-word to zero, thus ensuring the rsi register is set appropriately for this specific usage since length is unsigned.
No return value is provided by this void routine. If the function was a value returning function, the value returned would be in the A register.
Callee
The function being called, the callee, must perform the prologue and epilogue operations (as specified by the standard calling convention). Of course, the function must perform the summation of values in the array, find the minimum, medians, and maximum, compute the average, return all the values.
When call-by-reference arguments are passed on the stack, two steps are required to return the value.
- Get the address from the stack.
- Use that address to return the value.
A common error is to attempt to return a value to a stack-based location in a single step, which will not change the referenced variable. For example, assuming the double-word value to be returned is in the eax register and the 7th argument is call-by-reference and where the eax value is to be returned, the appropriate code would be as follows:
mov r12, qword [rbp+16]
mov dword [r12], eax
These steps cannot be combined into a single step. The following code
mov dword [rbp+16], eax
Would overwrite the address passed on the stack and not change the reference variable. The following code implements the stats2 example.
; Simple example function to find and return the minimum,
; maximum, sum, medians, and average of an array.
; -----
; HLL call:
; stats2(arr, len, min, med1, med2, max, sum, ave);
; Arguments:
; arr, address – rdi
; len, dword value – esi
; min, address – rdx
; med1, address - rcx
; med2, address - r8
; max, address - r9
; sum, address – stack (rbp+16)
; ave, address – stack (rbp+24)
global stats2
stats2:
push rbp ; prologue
mov rbp, rsp
push r12
; -----
; Get min and max.
mov eax, dword [rdi] ; get min
mov dword [rdx], eax ; return min
mov r12, rsi ; get len
dec r12 ; set len-1
mov eax, dword [rdi+r12*4] ; get max
mov dword [r9], eax ; return max
; -----
; Get medians
mov rax, rsi
mov rdx, 0
mov r12, 2
div r12 ; rax = length/2
cmp rdx, 0 ; even/odd length?
je evenLength
mov r12d, dword [rdi+rax*4] ; get arr[len/2]
mov dword [rcx], r12d ; return med1
mov dword [r8], r12d ; return med2
jmp medDone
evenLength:
mov r12d, dword [rdi+rax*4] ; get arr[len/2]
mov dword [r8], r12d ; return med2
dec rax
mov r12d, dword [rdi+rax*4] ; get arr[len/2-1]
mov dword [rcx], r12d ; return med1
medDone:
; -----
; Find sum
mov r12, 0 ; counter/index
mov rax, 0 ; running sum
sumLoop:
add eax, dword [rdi+r12*4] ; sum += arr[i]
inc r12
cmp r12, rsi
jl sumLoop
mov r12, qword [rbp+16] ; get sum addr
mov dword [r12], eax ; return sum
; -----
; Calculate average.
cdq
idiv rsi ; averge = sum/len
mov r12, qword [rbp+24] ; get ave addr
mov dword [r12], eax ; return ave
pop r12 ; epilogue
pop rbp
ret
The choice of the registers is arbitrary with the bounds of the calling convention. The call frame for this function would be as follows:

In this example, the preserved registers, rbp and then r12, are pushed. When popped, they must be popped in the exact reverse order r12 and then rbp in order to correctly restore their original values.

