Functions are a very important concept in program design. They can encapsulate relatively independent logic into a simple call, increasing the reusability of the logic. From a usage perspective, functions emphasize input and output; they accept parameters, perform a specific process, and then output the result.
A function is a type of subprogram, and it is also a type of callable unit. A programmer can write a function in source code that is compiled to machine code that implements similar semantics
Function calls are primarily accomplished using a stack data structure. In summary, It saves the current execution context by pushing onto the stack, then jumps to another piece of code to execute, and then pops the stack back to the previous context after execution is complete. And the structure used to save the current state is usually called a stack frame.
The structure used to save the current state is usually called a stack frame. From the perspective of high-level programming languages, it can be compared to a structure. However, in the underlying implementation using assembly language, it may simply use registers to record the top and bottom of the stack.
The CPU has no concept of functions, methods, classes, objects. The CPU only recognizes: instruction addresses, registers, memory, jumps, When you call an add function in a main function, for example:
int add(int a, int b) {
// xxxx
}
int main() {
add(1, 4);
return 0;
}
The underlying assembly might look like this (x86–64):
"add(int, int)":
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov edx, DWORD PTR [rbp-4]
mov eax, DWORD PTR [rbp-8]
add eax, edx
pop rbp
ret
"main":
push rbp
mov rbp, rsp
mov esi, 5
mov edi, 1
call "add(int, int)"
mov eax, 0
pop rbp
ret
The two crucial statements at the beginning of each function: push rbp and mov rbp, rsp, are used to create stack frames. (The purpose of push rbp is to restore the rbp register to its value before the call ends)
rbp and rsp are two commonly used register names.
rbp -> bottom of the current function stack
rsp -> top of the current stack
The call add(int, int) statement then performs two operations: saves the return address (next instruction address) and jumps to the new function to run:
And then it may also save some local variables and other information:
Next, some operations are performed using registers, and the results are saved to the eax register (this register is usually used to store the return value). Then, pop rbp restores the rbp register to its state before this function was called.
Finally, the ret statement corresponds to the call statement, and it also does two things: its function is to retrieve the return address from the top of the stack and jump back to main function. This concludes the call to the add function. Then execution will continue from the line mov eax, 0 in the main function.
Of course, please also note that the so-called popping of a stack frame may not actually clear old data for performance reasons; it may only change the state of registers.
Furthermore, with the advancement of modern compilers, many unnecessary steps are omitted, so the actual implementation may be even more streamlined and difficult to understand.
A more technical description of this process is that it involves temporarily transferring enforcement power and then restoring it.






Top comments (0)