From what I've been able to find, between Linux and Windows there are two common calling conventions: arguments for function calls are loaded either into registers or placed on the stack.
For example with the printf
function it is said Linux loads registers with the arguments that printf
needs. For printf
on Windows I've seen both conventions used. In my class, they have us place the arguments on the stack, however in code examples online the arguments are placed in registers.
This answer by Basile Starynkevitch, made me think Windows used stack only for arguments and Linux used registers. This answer by Jester shows Windows using registers for printf
arguments.
Next small part of the code I've written for my class shows that on Windows I've been using the stack for arguments:
section .data
msg: db "my message", 0ah, 0
section .text
_main:
push msg
call _printf
add esp, 4
I've also seen that people are able to use printf
in Windows assembly without the underscore. I know that is normal for Linux assembly code but on Windows I get an error if I don't use the underscore. Others on Windows don't seem to have this problem.
In the original question that Jester answers (link above), it doesn't seem as though the user asking the question uses any special NASM instruction that would allow for that, unless it is something in the linker command they're using.
C. K. Young only explains how you can use printf
without an underscore if you use a certain NASM option.
printf
without the underscore when they aren't using the NASM option?I've searched quite a bit but haven't found any explanations for these strange cases.
32-bit x86 CPUs don't have that many registers to use, so most calling conventions originally designed for them use mainly the stack.
This is obviously not as fast as using registers, and therefore once 64-bit x86 CPUs became more common, parameters were stored in registers as much as possible.
To produce a fully working application, you need to link your code to a "libc"; Windows provides at least 2 of those with their SDK, and there are also independent implementations like the one used by MinGW-w64; each of them will have their functions exported using a specific calling convention that you should match, and using leading "_" in the name is usually how it prevents conflicting calls from linking successfully.