IntroductionI don't know if you know, but every code C is compiled for a https://pt.stackoverflow.com/q/142289/101 . This machine code is ideal for the computer, but difficult for the human to understand, so we have higher-level languages with concepts that we understand better. https://en.wikipedia.org/wiki/Function_(mathematics) that we apply in programming. Directly it does not exist in the machine code. The possible instructions are:simple numerical operations,data movement between memory and recorders,Simple execution flow control.Call and returnThe function call actually is an instruction http://x86.renejeschke.de/html/file_module_x86_id_26.html that actually it's like it's a GOTO (or) JMP, as is known in Assembly), so it only diverts the execution of the application to the address where the code would be the function. The basic difference of CALL is that it saves the address where it should go back in a pile, so when it is inside the function and find an instruction http://x86.renejeschke.de/html/file_module_x86_id_280.html , she will take the address that is at the top of the pile to give another GOTO to it and divert execution to this address. So in a way we can say that the function is just this.In fact, the function, i.e. the generated machine code needs a header (prologue) and footer ( epilogue) that you programmer does not realize because it is something that does not matter to your understanding of your code.Since all operations are carried out in registers and you cannot lose the data that are there because normal execution probably still needs them and tells that they will be there when there is a deviation to a function it is necessary to preserve the status of registers.Then some instructions are placed before https://pt.stackoverflow.com/q/104814/101 that does this job https://pt.stackoverflow.com/q/3797/101 .At the end of running your code it is necessary to restore the state of the registers by taking what is in the stack, this always occurs before an instruction RET.Normally there will be a global symbol of the application to contain the address where the function code is, so the code you call can use what we know as a variable (thick mode). This is important because it is common that the actual execution address is not real, even considering that we are in virtual memory, so understand that real is neither the physical address I am talking about, it is not known until that code is loaded into memory, so you need to use this symbol and not a real address. At least in functions that may be called from any part of the code and cannot be optimized to contain the direct address.Arguments, parameters and returnOf course the function can have passage https://pt.stackoverflow.com/q/32448/101 . If this occurs it is necessary to transfer their values to their function, this usually happens in the stack.As in fact the generated final code is not shared in functions and yes is one thing only, in fact what you are doing is copying the data from one variable to another, that is, equivalent to a simple assignment.But there are actually no machine code variables. What you do is to transport data from memory to another point of memory, passing the registrars, and how optimization it can transport from memory to the registrar, or even from the registrar to register when it is possible.It is common if you try to make only movements between registers because they are much faster, but not, it is always possible, even because if you have many parameters you do not have enough registers, and not all can be used for that and also have data that does not fit in the register. What is copied is simple numerical data that fit in the register, remembering that char is a numeric datum, hands, remembering that https://pt.stackoverflow.com/q/91336/101 , and data in structs that don't usually go in registers.The same occurs with the return. In general a register is highlighted so that it is made. As with the passing of parameters, there is a https://en.wikipedia.org/wiki/Calling_convention for the returned data that the code you called will already have to use when you finish the function code ( https://en.wikipedia.org/wiki/X86_calling_conventions ). Normally the return of the function only does not enter register when it is too large and can be placed in memory directly at the location of the variable or temporary storage location contained in the caller function.Parameters can be considered local variables of the function, so what you're doing is putting values in these variables. Then everything goes to the running stack in memory, if you cannot optimize to register.Real ExampleOf course what I just described is the most common, depends on the processor architecture can work a little different. Some compiler C can do some things a little different, since it fulfills what is in the language specification.Think of a function C like this:int add(int i,int j) {
int p = i + j;
return p;
}
The compiled code would look like this:.globl add
add:
pushl %ebp //cabeçalho salvando em pilha o registrador que será manipulado
movl %esp, %ebp //joga o ponteiro da pilha em ebp
subl $4, %esp //aloca espaço (4 bytes) na pilha para a variável p
movl 8(%ebp), %edx //8(%ebp) é o i, só atribuição do que está na pilha + 8 bytes
addl 12(%ebp), %edx //12(%ebp) é o j, aqui já faz a adição, edx é o outro operando
movl %edx, -4(%ebp) //-4(%ebp) é o p, atribuição
movl -4(%ebp), %eax //eax é o registrador de retorno
leave //é o mesmo que dar movl %ebp, %esp; popl %ebp ret, é o rodapé
%esp is register with the current stack location pointer. When you have a 12(%ebp) is the address indicated by the value that is in the register %ebp plus 12 bytes. %ebp is where the frame of the stack of this function.The call to this function will be something like this:add(1, 2)
In Assembly:pushl $2 //joga o segundo parâmetro na pilha
pushl $1 //joga o primeiro parâmetro na pilha
call add //desvia para a função
Try yourself, make simple codes, compile using GCC with option -S and see the resulting Assembly from it. In Visual C is /FA.The result will not always be the same, it depends a little on the compiler.There is a different assembly syntax. If you use GCC 7 and use syntax Intel the generated function will be:push rbp
mov rbp, rsp
mov DWORD PTR [rbp-20], edi
mov DWORD PTR [rbp-24], esi
mov edx, DWORD PTR [rbp-20]
mov eax, DWORD PTR [rbp-24]
add eax, edx
mov DWORD PTR [rbp-4], eax
mov eax, DWORD PTR [rbp-4]
pop rbp
ret
See https://godbolt.org/g/WL8NtK . Also https://github.com/maniero/SOpt/blob/master/C/Function/LowLevel.c .ConclusionIt seems complicated, but as you learn it becomes easy, because in fact the simplest concepts are concrete. That is why I usually say that people should learn to program from the bottom up, with Assembly, or at least C, understanding everything that occurs in the compilation process, leaving the abstractions for later.In short, this is what I've obviously made simplifications, if you want to understand even need to research something deeper and precise, if you have specific questions, ask new questions.