.Open Assembly Language Functions and Procedures . Motivation To learn how to write functions and procedures in Assembly Language, along with an understanding of how to pass parameters to functions and procedures in Assembly Language, and returning values from functions and procedures in Assembly Language. . Introduction Working with functions and procedures in Assembly Language is quite similar to how one works with functions and procedures in a high level language. There is the function/procedure name, parameters to pass to the function/procedure, and a $return_value from the function/procedure if there is one. Parameters can be passed to functions/procedures $by_value or $by_reference. Global variables in the program can also be accessed by functions and procedures. In assembly language, parameters whether they are passed $by_value or $by_reference can be passed with the value or reference in a register or pushed onto the $stack. It is considered good practice with passing the data in registers for 64 bit architectures rather than passing on the stack for consideration of not worrying about performance issues when the stack values are not lined up on 64 bit memory bus boundaries. All $examples are done with NASM. by_value::= passing of actual variable values as parameters, this is acceptable for atomic data types such as integers, and floating point, not advised for structures, classes, or arrays. by_reference::= passing of pointers or memory location reference of a variable as a parameter. This is perhaps the best approach for any and all data types. stack::= similar to the stack data structure found in high level programming languages. In Assembly Language, the stack keeps an $activation_record or a $stack_frame, and can hold parameter values whether they are passed $by_value or $by_reference. return_value::= activation_record::= record keeping of local variables in a procedure, parameters passed to the procedure, and return address of calling code. This is also called the $stack_frame, and sometimes also called the call stack. stack_frame::= See $activation_record. examples::= procedures and functions with: $no_parameters_no_return_value | $parameters_no_return_values | $no_parameters_has_return_value | $has_parameters_has_return_value no_parameters_no_return_value::= $no_param_no_return_val_32bit | $no_param_no_return_val_64bit no_param_no_return_val_32bit::= a sample function that takes on no parameters and has no return value. This is the equivalent of a C/C++ function that returns a void and has no parameters. .As_is ... ; code before the call .As_is call some_function ; call some_function .As_is ... ; code after the call .As_is ... ; code after the call .As_is mov eax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is ... ; do code for function here .As_is ret ; return from the function back to the calling code no_param_no_return_val_64bit::= a sample function that takes on no parameters and has no return value. This is the equivalent of a C/C++ function that returns a void and has no parameters. .As_is ... ; code before the call .As_is call some_function ; call some_function .As_is ... ; code after the call .As_is ... ; code after the call .As_is mov rax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is ... ; do code for function here .As_is ret ; return from the function back to the calling code parameters_no_return_values::= $has_params_no_return_val_32bit | $has_params_on_stack_no_return_val_32bit | $has_params_no_return_val_64bit | $has_params_on_stack_no_return_val_64bit has_params_no_return_val_32bit::= a sample function that takes on parameters both $by_value and $by_reference in the example and has no return value. This is the equivalent of a C/C++ function that returns a void and has parameters. .As_is section .data .As_is some_val dd 5 .As_is some_val2 dd 6 .As_is result dd 0 .As_is ret_val dd 0 .As_is section .text .As_is global main .As_is main: .As_is mov eax, some_val ; this example has some_val being passed by value in eax register .As_is lea esi, [some_val2]; esi contains the pointer to some_val2, being passed by reference .As_is lea edi, [result] ; edi contains the pointer to variable named result, passed by reference .As_is call some_function ; call some_function .As_is ... ; code after the call .As_is ... ; code after the call .As_is mov eax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is add eax, [esi] ; get the content pointed by esi, and add it to eax, this is: eax = eax + &esi in a C/C++ way of things .As_is mov [edi], eax ; store value of eax in memory location pointed by edi. .As_is ret ; return from the function back to the calling code has_params_on_stack_no_return_val_32bit::= a sample function that takes on parameters being pushed onto the stack both $by_value and $by_reference in the example and has no return value. This is the equivalent of a C/C++ function that returns a void and has parameters. .As_is section .data .As_is some_val dd 5 .As_is some_val2 dd 6 .As_is sum dd 0 .As_is ret_val dd 0 .As_is section .text .As_is global main .As_is main: .As_is mov eax, [some_val] ; load [some_val] value into eax .As_is push eax ; this example has some_val being passed by value pushed on the stack .As_is lea eax, [some_val2]; esi contains the pointer to some_val2, being passed by reference .As_is push eax ; push memory address pointed by esi onto stack .As_is lea eax, [sum] ; edi contains the pointer to variable named result, passed by reference .As_is push eax ; push memory address pointed by edi onto stack .As_is call some_function ; call some_function .As_is add esp, 12 ; 12 bytes were pushed on stack, readjust stack pointer to remove them .As_is mov eax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is push ebp ; set up stack frame .As_is mov ebp, esp ; ebp points to the stack pointer .As_is mov eax, [ebp+16] ; [ebp+12] contains the value of eax passed on the stack .As_is mov esi, [ebp+12] ; esi points to memory address of second parameter .As_is mov edi, [ebp+8] ; edi points to memory address of third parameter .As_is add eax, [esi] ; add eax to value pointed by esi .As_is mov [edi], eax ; store value of eax in memory location pointed by [edi]. .As_is pop ebp ; restore old base pointer .As_is ret ; return from the function back to the calling code has_params_no_return_val_64bit::= a sample function that takes on parameters both $by_value and $by_reference in the example and has no return value. This is the equivalent of a C/C++ function that returns a void and has parameters. .As_is section .data .As_is some_val dq 5 .As_is some_val2 dq 6 .As_is sum dq 0 .As_is ret_val dq 0 .As_is section .text .As_is global main .As_is main: .As_is mov rbp, rsp; for correct debugging .As_is mov rax, [some_val] ; this example has some_val being passed by value in rax register .As_is lea rsi, [some_val2]; esi contains the pointer to some_val2, being passed by reference .As_is lea rdi, [sum] ; edi contains the pointer to variable named result, passed by reference .As_is call some_function ; call some_function .As_is mov rax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is add rax, [rsi] ; get the content pointed by rsi, and add it to rax, this is: rax = rax + &rsi in a C/C++ way of things .As_is mov [rdi], rax ; store value of rax in memory location pointed by rdi. .As_is ret ; return from the function back to the calling code has_params_on_stack_no_return_val_64bit::= a sample function that takes on parameters being pushed onto the stack both $by_value and $by_reference in the example and has no return value. This is the equivalent of a C/C++ function that returns a void and has parameters. .As_is section .data .As_is some_val dq 5 .As_is some_val2 dq 6 .As_is sum dq 0 .As_is ret_val dq 0 .As_is section .text .As_is global main .As_is main: .As_is mov rax, [some_val] .As_is push rax ; this example has some_val being passed by value pushed on the stack .As_is lea rax, [some_val2]; rax contains the pointer to some_val2, being passed by reference .As_is push rax ; push memory address pointed by rax onto stack .As_is lea rax, [sum] ; rax contains the pointer to variable named result, passed by reference .As_is push rax ; push memory address pointed by rax onto stack .As_is call some_function ; call some_function .As_is add rsp, 24 ; clear out the stack, we pushed 24 bytes onto stack, adding 24 to rsp "pops" the 24 bytes off stack .As_is mov rax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is push rbp .As_is mov rbp, rsp .As_is mov rax, [rbp+32] ; [rbp+32] contains the value of rax passed on the stack .As_is mov rsi, [rbp+24] ; [rbp+24] contains the value of second parameter pointer passed on the stack .As_is mov rdi, [rbp+16] ; [rbp+16] contains the value of third parameter pointer passed on the stack .As_is add rax, [rsi] ; add content of [rsi] to rax .As_is mov [rdi], rax ; store value of rax in memory location pointed by [rdi]. .As_is pop rbp .As_is ret ; return from the function back to the calling code no_parameters_has_return_value::= $no_param_has_return_val_32bit | $no_param_has_return_val_64bit no_param_has_return_val_32bit::= a sample function that takes on no parameters and has return value. This is the equivalent of a C/C++ function that returns an integer and has no parameters. .As_is ... ; code before the call .As_is call some_function ; call some_function .As_is ... ; code after the call .As_is ... ; code after the call .As_is mov eax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is ... ; do code for function here .As_is mov eax, a_ret_val ; returns a_ret_val as the return value .As_is ret ; return from the function back to the calling code no_param_has_return_val_64bit::= a sample function that takes on no parameters and has return value. This is the equivalent of a C/C++ function that returns an integer and has no parameters. .As_is ... ; code before the call .As_is call some_function ; call some_function .As_is ... ; code after the call .As_is ... ; code after the call .As_is mov rax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is ... ; do code for function here .As_is mov rax, a_ret_val ; returns a_ret_val as the return value .As_is ret ; return from the function back to the calling code has_parameters_has_return_value::= $has_params_has_return_val_32bit | $has_params_on_stack_has_return_val_32bit | $has_params_has_return_val_64bit | $has_params_on_stack_has_return_val_64bit has_params_has_return_val_32bit::= a sample function that takes on parameters both $by_value and $by_reference in the example and has an integer return value. This is the equivalent of a C/C++ function that returns an integer and has parameters. .As_is ... ; code before the call .As_is mov eax, some_val ; this example has some_val being passed by value in eax register .As_is lea esi, [some_val2]; esi contains the pointer to some_val2, being passed by reference .As_is lea edi, [result] ; edi contains the pointer to variable named result, passed by reference .As_is call some_function ; call some_function .As_is ... ; code after the call .As_is ... ; code after the call .As_is mov eax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is add eax, [esi] ; get the content pointed by esi, and add it to eax, this is: eax = eax + &esi in a C/C++ way of things .As_is ret ; return from the function back to the calling code, eax is the return value has_params_on_stack_has_return_val_32bit::= a sample function that takes on parameters being pushed onto the stack both $by_value and $by_reference in the example and has a return value. This is the equivalent of a C/C++ function that returns an integer and has parameters. .As_is ... ; code before the call .As_is push some_val ; this example has some_val being passed by value pushed on the stack .As_is lea esi, [some_val2]; esi contains the pointer to some_val2, being passed by reference .As_is push esi ; push memory address pointed by esi onto stack .As_is lea edi, [result] ; edi contains the pointer to variable named result, passed by reference .As_is push edi ; push memory address pointed by edi onto stack .As_is call some_function ; call some_function .As_is ... ; code after the call, you have the corresponding pops from the above pushes here IF the function does not .As_is ; remove them. It is important to have functions be documented as to how they behave and do any clean up .As_is ... ; code after the call .As_is mov eax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is mov eax, [ebp+12] ; [ebp+12] contains the value of eax passed on the stack .As_is add eax, [ebp+8] ; add content of [ebp+8] to eax, and content of eax is returned to calling code as return value .As_is ret ; return from the function back to the calling code has_params_has_return_val_64bit::= a sample function that takes on parameters both $by_value and $by_reference in the example and has no return value. This is the equivalent of a C/C++ function that returns a void and has parameters. .As_is ... ; code before the call .As_is mov rax, some_val ; this example has some_val being passed by value in rax register .As_is lea rsi, [some_val2]; esi contains the pointer to some_val2, being passed by reference .As_is lea rdi, [result] ; edi contains the pointer to variable named result, passed by reference .As_is call some_function ; call some_function .As_is ... ; code after the call .As_is ... ; code after the call .As_is mov rax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is add rax, [rsi] ; get the content pointed by rsi, and add it to rax, this is: rax = rax + &rsi in a C/C++ way of things .As_is ret ; return from the function back to the calling code, with return value in rax has_params_on_stack_has_return_val_64bit::= a sample function that takes on parameters being pushed onto the stack both $by_value and $by_reference in the example and has no return value. This is the equivalent of a C/C++ function that returns a void and has parameters. .As_is ... ; code before the call .As_is push some_val ; this example has some_val being passed by value pushed on the stack .As_is lea rsi, [some_val2]; rsi contains the pointer to some_val2, being passed by reference .As_is push rsi ; push memory address pointed by rsi onto stack .As_is lea rdi, [result] ; rdi contains the pointer to variable named result, passed by reference .As_is push rdi ; push memory address pointed by rdi onto stack .As_is call some_function ; call some_function .As_is ... ; code after the call, you have the corresponding pops from the above pushes here IF the function does not .As_is ; remove them. It is important to have functions be documented as to how they behave and do any clean up .As_is ... ; code after the call .As_is mov rax, ret_val ; main should have a return value, in place of whatever ret_val is .As_is ret ; return from your main .As_is some_function: ; some_function label (in MASM, you would use some_function proc, with some_function endp after the code block) .As_is mov rax, [rbp+24] ; [rbp+24] contains the value of rax passed on the stack .As_is add rax, [rbp+16] ; add content of [rbp+16] to rax .As_is ret ; return from the function back to the calling code, with return value in rax .Close Assembly Language Functions and Procedures