In assembly, all bets are off and you can pass parameters any way you like, provided that the caller and the callee agree on how it's done.
Put arguments on the stack, put a pointer to them on the stack, put them into registers, stash them in a fixed memory location, it's all up to you. I've seen cases where some arguments were passed in registers, while others were passed on the stack or passed by reference.
How you transfer control is also up to you. Execute a "call" instruction, or a software interrupt. The old PDP-10 architecture has like five different ways of calling a subroutine, and you had to know which one to use. The IBM-360 architecture also has a number of ways.
(You want to see crazy? Read the famous Interrupt List, which was a collection of all the known software interrupt calls available for the 286 architecture. Practically every piece of software you installed under MS-DOS added some new software interrupts to the pot, and they each had their own calling convention and many of them collided with each other.)
In general, your best approach is to find out what other programmers are doing and do the same thing. Either that, or document your function very well so that users know how to call it.
Now, if your assembly is going to call or be called by another language, such as C, C++, Fortran, etc., then you need to research the standard calling conventions that were established by the language designers and which usually also depend on the architecture. For example, for C on 32-bit x86, the arguments would be passed on the stack, while for Sparc, up to five arguments would be passed in registers and anything beyond that went on the stack.
As for structures, the C standard calls for them to be unpacked and the individual elements to be passed as separate arguments, to be re-assembled into a structure by the callee. If the structure is very large, this can be insanely wasteful, so it's better to pass a pointer to the structure instead.
If the function returns a structure, the caller allocates space to receive it, and passes a pointer to that space as a "secret" argument to the function.
Arrays are always passed as pointers.
For Fortran, everything is passed by reference, meaning that values can be returned to any argument. Even constants are stashed in memory somewhere and a pointer to them is passed to the called subroutine. (Thus making it possible to accidentally change the value of a constant.)