|In ASM there is no distinction between functions and procedures. The name procedure is usually used. You can only CALL a procedure. A function in the high-level sense (a procedure that returns something) is just a variant.
Regarding passing parameters to procedures in ASM. This can be done:
a) By putting values to CPU registers. This works if the number of parameters is small and parameters are rather simple data types. The procedure has direct access to parameters by means of registers. Compilers do this for simple functions/procedures/methods. Of course you need to save registers to stack and restore them after return. This is named the call sequence/frame of the procedure.
b) By pushing parameters to the stack. This is the facto standard. You can push parameters from left to right (the so-called "Pascal" convention) or from right to left (the so-called "C" convention). The "C" convention works also with procedures that have a variable number of parameters. This is why the C function printf has the format as the first (and mandatory) parameter - it will be on the top of the stack when entering printf and printf will know where to find it (the format is supposed to correctly describe the number ad type of each other parameters like %s, %d etc.)
When returning from the procedure the stack must be discarded of the parameters that were put on the stack. This can be done by the caller (the "C" approach) or by the procedure (the "Pascal" approach).
E.g. "ADD SP, 24" or "RET 24". The c/C++ compilers use of course the "C" approach.
Observe that the caller "knows" exactly how many parameters were pushed onto the stack so discarding the stack by the caller is more natural. Windows SDK uses "Pascal" convention.
When dealing with large objects that must be passed, it's easier to pass then by reference, i.e. to pass an address (pointer) to a memory area where the object is stored. A pointer is a simple type.
If you really need to pass a large object by value (i.e. make a copy), you can copy the internal representation of the object onto the stack, and define the stack frame so that procedure has access to it. However this is more time-consuming.
b) Combinations of the above 2 methods.
A procedure can return a value (i.e. becoming a function) by:
1) A register (if the return value is a scalar type). For Intel CPU, the convention is to return in the accumulator (AL, AX, DX:AX, EAX, etc., depending on the processor type). Observe that scalar types include all numerical values (int, float, double) and pointers.
2) If the result is a large object, things get complicated, because when converting "return t" into machine code, a copy needs to be done somewhere in memory. However compilers can do whatever they want, assuming they don't break the language semantics. A copy could be made onto the stack.
That's why is best to avoid methods that return objects in C++/C# etc. Pass a reference/pointer where you want the result to be placed instead.
See for example: <a href="https://en.wikipedia.org/wiki/Copy_elision#Return_value_optimization">
If you work directly in ASM and are not just interested in interfacing high-level language with ASM-level modules, you can use any combination of the above methods. For example, pass the first parameter by means of a register and the rest onto the stack (there are compilers that do that).
However, I recommend to stick to conventional methods. You never know when you will need to call an ASM procedure from C++ or a C++ method/function from ASM.
In any case, any compiler documents (or should document) very exactly how it transfers parameter to procedures, and hw results are returned by functions. If you need to work at this level, read this carefully, and then make a small interface project. What I described above is merely a top-level sketch.
Unfortunately, ASM is not so much taught in universities nowadays (more just as an addendum to digital electronics) and this is really a pity. Many questions regarding pointers, references, memory allocation, constructors, destructors etc. would become more clear and even obvious to developers if they had a small ASM experience.