Skip to main content
Engineering LibreTexts

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{\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}}\)

    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:

    截屏2021-07-29 下午10.10.45.png

    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.


    12.7: Example, Statistical Function2 (non-leaf) is shared under a not declared license and was authored, remixed, and/or curated by LibreTexts.

    • Was this article helpful?