Talk:X86 calling conventions
This is the talk page for discussing improvements to the X86 calling conventions article. This is not a forum for general discussion of the article's subject. |
Article policies
|
Find sources: Google (books · news · scholar · free images · WP refs) · FENS · JSTOR · TWL |
This article is rated C-class on Wikipedia's content assessment scale. It is of interest to the following WikiProjects: | |||||||||||||||||
|
Pascal calling convention
edit"Pascal, as used in the Pascal programming language". This is a tired myth. The language never specified a calling convention, any more than the C language did. This could be converted to a reference to a specific compiler (my guess is Borland). However, it is incorrect as it is.
It is more a reference to the order of pushing registers on the stack in old compilers, which was later fixated in old 16-bit Windows versions. Note that Microsoft also had a Pascal compiler (last version 1985 iirc)
2A02:A458:C30A:1:C17F:5765:9DCF:67D0 (talk) 12:09, 30 December 2021 (UTC)
double/float arguments on Linux/GCC
editIn Linux/GCC, double/floating point values should be pushed on the stack via the x87 pseudo-stack. [...] Using this method ensures it is pushed on the stack in the correct format.
I cannot verify this. Where is the citation/reference? What other "method" is not "correct"? --130.34.188.206 (talk) 01:41, 24 July 2012 (UTC)
Difference between GCC 4.4 and 4.5
edit" Since GCC version 4.5, the stack must be aligned to a 16-byte boundary when calling a function (previous versions only required a 4-byte alignment.) "
I can not find this statement in the internet. Some related discussions here:
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38496#c9
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838
- https://mail.python.org/pipermail/python-dev/2010-May/100044.html
- https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
Basically that's says:
- x86 ABI only requires stack aligned to 4 bytes.
- The 16 bytes alignment is required when SSE instruction is used.
- x86-64 ABI require 16 byte stack alignment (SSE is enabled by default in this case).
- GCC is using 16 bytes alignment by default nowadays, see the -mpreferred-stack-boundary option (https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html).
- It seems that GCC 4.4, and even earlier version date back to 2006 is already using the 16 bytes alignment (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38496#c25 , https://groups.google.com/forum/#!topic/ia32-abi/T5s-UGmUO_E).
- The bug report above is just suggesting a fix to accept the 4 byte alignment when it is possible. — Preceding unsigned comment added by Wanttoknow (talk • contribs) 14:28, 19 July 2016 (UTC)
thiscall on GCC incorrect?
editThe section on thiscall for GCC seems to be incorrect.
From http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
- thiscall
- On the Intel 386, the thiscall attribute causes the compiler to pass the first argument (if of integral type) in the register ECX. Subsequent and other typed arguments are passed on the stack. The called function will pop the arguments off the stack. If the number of arguments is variable all arguments are pushed on the stack. The thiscall attribute is intended for C++ non-static member functions. As gcc extension this calling convention can be used for C-functions and for static member methods.
History/meaning of cdecl?
editI've looked around and can't find what exactly "cdecl" means - I'm assuming it's an abbreviation of "C declaration" but can't find a source that says so. Anyone have any insight? Would be a nice bit of information to include in the article. JonathonReinhart (talk) 07:31, 15 April 2010 (UTC)
return struct
editWhat if the returned value is larger than 32 bits ? For 64bit values I think the EAX:EDX pair is used instead, but when a large struct is returned, then it's returned on the stack. Anybody can explain the stack layout in this case ? Also for floating point values FP(0) is used, if I remember correctly.
- From memory, when a function returns a struct, the caller allocates space for the returned stuct on the stack and the callee writes into this space. I don't have a citation for this handy, but someone should be able to look it up. 128.174.236.250 (talk) 19:58, 27 February 2009 (UTC)
- This is largely true, but none of this is written in stone! It's completely up to the implementation of a particular language (not only C/C++...) and particular compiler. For regular internal calls (i.e. those which not use an external linker), many different schemes and conventions are used—sometimes even within a single compiler—for optimization. 83.255.38.25 (talk) 17:11, 5 April 2011 (UTC)
What happens with small structs varies wildly. Though the system abi might have something to say about that (e.g. on Mac, Windows is essentially free for all) 88.159.64.117 (talk) 11:12, 29 December 2011 (UTC)
Yes, struct return format matters. It should probably be added to a table. For now, here are some links:
thiscall
editThere seems to be a conflict between the thiscall and the returning of class/structures. Both state that they are supposed to be passed as the "first" parameter. But only one can be number 1 ;). I'm guessing the return value wins out here and you'd have:
push c
push b
push a
push [address of this]
push [address of return]
call func
Right now I'm playing around with creating function calls on the fly. Some disassembly is required for this. If I find out for sure, I'll move this fact to the normal page.
About the thiscall convention, I was wondering if 'this' can be NULL? Can't find out...
I believe that it can never happen. The only problem I can think about are "Class Functions" (declared as 'static' in Java and C++) but if you use 'this' in such a function you will have a compilation error. (I'll make sure it's true and will let you know)
Yes, it can and does happen. Try it:
C* p= 0;
p->foo(); // segfault crash
//...
/* Must not be virtual!! */
void C::foo()
{
cout << this << endl;
}
Static functions do not have access to a "this" pointer.
A "this" pointer being NULL has no effect other than a likely segfault when you attempt to access a class data member (as it would take the offset of the member and add it to the "this" pointer, then attempt to access it). Member functions only exist in code once and non-static ones are passed a hidden "this" pointer so that they can "know" which instance of the class they are working on. To most users, this is completely transparent and it would appear each instance has its own copy of the functions.
71.200.70.242 03:20, 2 November 2006 (UTC)
In the previous exemple, the call p->foo(); will create a segfault crash... That's why one can consider that this will never be NULL...
stdcall
editI've changed the line about whether the registers are preserved by the caller within the function, and added the {{dubious}} template, since I don't know what the real answer is. The line, before my change, was "Registers EAX, ECX, and EDX are preserved ** not preserved! ** for use within the function", which is obviously not helpful.
I've also removed a couple of other comments placed within the body of the article. If you want to clean up something, clean it up, or leave a comment on the talk page, not within the article itself.
--MrBoo (talk, contribs) 18:42, 27 October 2006 (UTC)
- The previous versions didn't say they were preserved WITHIN the function, but that they were preserved for the function to use them without saving. Microsoft abide by the Intel ABI, and thus, since functions are free to use EAX,ECX and EDX *without* first pushing (saving) it, then, technically, it is true that these registers (if need be) are preserved prior a call. In any case, putting the sentence "Registers [...] are not preserved [...]" would be confusing, because it would seem to say that others might be (which is definitly NOT the case: it is the responsibility of the callee and modifier of these other regs to save them first). Also, primitive data types of size <= 8 bytes are returned via EDX:EAX, which underlines again that these regs are obviously needed to be saved prior an stdcall since they will be overwritten by the return.
- So, anyway, Długosz was mistaken with his addition there.
- I would say to "Długosz" BE CAREFUL with your edits, in doubt, use the talk page. In the thiscall section, you stated "Windows API functions don't have a this pointer!", well, the section was already talking about *C++ member functions*, and non-static was obviously implicit but should be noted. I have reverted to Letdorf's version, though I agree that Windows functions can be misleading. This should be replaced by on Microsoft Visual C++ compiler.
- Another note: there was a mistake even in the other versions (pre Długosz), when saying "This is the same method used by Windows thiscall functions that use variable arguments." This is untrue: in Visual C++, this is passed in ECX, regardless of the use of the ... operator.
Standard Entry Sequence
editI'm pretty sure this isn't right:
mov ebp, esp ;make the base pointer point to the current stack location which is where the parameters are
At this point in code, the closest elements on the stack are the old ebp, then the return address, and only then the parameters. The mistake is repeated elsewhere in the section I think. Aaron McDaid (talk - contribs) 00:03, 24 November 2006 (UTC)
Pascal == Stdcall ??
editEverything I've seen says that Pascal is the same as Stdcall: right-to-left, callee cleans up stack. —The preceding unsigned comment was added by 70.19.86.148 (talk) 22:30, 28 December 2006 (UTC).
- If I got it right, the only thing in question is, if the pascal keyword pushes the parameters left-to-right or right-to-left. Before reading your comment, I thought it was left-to-right and that's what the wikipedia article had said, before you doubted it. However, I've found different opinions in the internet:
- pro left-to-right:
- http://webster.cs.ucr.edu/Page_win32/win32API.html
- http://support.microsoft.com/kb/100832/en-us?spid=3041&sid=global (it doesn't say pascal is left-to-right, but it says that stdcall is supported, pascal is not, which implies that stdcall and pascal are different things)
- http://www.swissdelphicenter.ch/torry/printcode.php?id=1233
- pro right-to-left:
- http://gcc.gnu.org/onlinedocs/gnat_ugn_unw/Stdcall-Calling-Convention.html (pascal means the language here, not the keyword, but the calling convention should be the same)
- http://www.unixwiz.net/techtips/win32-callconv.html
- After all, one opinion must be wrong, but I can't see which. Perhaps we should write that in the article? --BB-Froggy 13:31, 5 January 2007 (UTC)
Be careful here, to not confuse traditional Pascal conventions and what C compilers make out of it in their "Pascal" modifier. This is the same problem as with "cdecl" in other languages. It is not an universal "c" calling convention, but more specifically the "c compiler that this compiler sees as its natural twin", which can vary subtally This means it can be also a C++ compiler. (like with Delphi) with additional constraints
So Pascal traditionally pushed right to left and callee popped. But to assume such things about modern compilers (like Delphi and Free Pascal) is dangerous, since they are generally more flexible in calling conventions than C because they lack the need for a fixed calling conventions because they don't have loosely typed varargs kludges (printf) in normal code. In fact, both of them have a register convention as default. 88.159.73.216 10:34, 8 January 2007 (UTC)
Just thought I would weigh in here. I looked up the __pascal keyword in the Watcom C/C++ User's Guide, and its clear that:
- __pascal calling convention was used for OS/2 1.x and Microsoft Windows 3.x APIs
- __pascal pushes arguments on the stack from left to right (opposite of __stdcall), the callee cleans up
I think that this is an authoritative source, and I am accordingly writing it into the article. Choppingmall 17:25, 12 January 2007 (UTC)
What platform is Watcom authorative for? 32-bit Dos is all I can think off and varies wildly by vendor. Moreover "pascal" calling conventions are not limited to Windows. Classic MacOS had them too, default even.
I would simply keep "pascal" as a family of calling conventions "right-to-left, callee cleans up stack". Stdcall is then a specific version that als details which registers are saved. 88.159.64.117 (talk) 11:15, 29 December 2011 (UTC)
- Seems it was depending on the Pascal compiler. The only one I'm sure about, is for Borland Turbo Pascal for DOS, which used “left‑to‑right + the callee clean the stack” (I remember this, I did assembly with the assembler embedded directly into the language).--Hibou57 (talk) 10:41, 18 April 2013 (UTC)
Custom calling conventions
editAfaik GCC has some form of custom calling conventions too, at least for prototypes (iirc see FreeBSD csu code, the part that wraps syscalls). Free Pascal has a bit more, for its AmigaOS connectivity. Another 16-bit compiler that had custom calling conventions was the TopSpeed 3.x series (Pascal,C++,Modula2 iirc)
One main use of a custom calling convention is already illustrated above; interfacing to APIs that are not in procedural format. System calls mostly (Dos interrupts, AmigaOS Api which uses a custom register allocation per function, even Linux and BSD syscalls).
Even though BSD syscalls are generally procedural (contrary to x86 Linux), they have to be modified because there are slight differences relating to the errorhandling, and on x86_64 they exchange ecx with r10
The other major application is intrinsics; defining inline functions over assembler code, with the calling conventions specifying where parameters should go. A classic is the x86-Dos outport: (the exact syntax is fictional here)
- pragma customcall (edx,eax)
__inline __asm void outport (int port,char value) {outb %al,%edx}
which means - the code should be inlined (__inline) and is a single assembler instruction (outb %al,%edx). - the first argument should go into edx, the second into eax (but in practice %al), exactly where the asm instruction expects them.
You can probably imagine other cases like SSE instructions now.
88.159.73.216 10:48, 8 January 2007 (UTC) (minorly updated with x86_64 details in dec 2011)
Case Sensitivity
editShould the article include a description of the case-senstivity of the calling conventions?
cdecl and stdcall names are case-senstive. pascal names are not.
While technically not part of the calling convention, there is the greater good to consider. If case-sensitivity is included, it would help those reading this article who are trying to resolve calling convention related problems. —Preceding unsigned comment added by 71.96.69.21 (talk) 07:34, 10 March 2009 (UTC)
Visual Studio 2007
editSomeone mentions this (AFAIK) non-existent Visual Studio version. Probably version 2005 or 2008 is meant. —Preceding unsigned comment added by 85.220.124.20 (talk) 00:40, 7 July 2009 (UTC)
Abstract Binary Interface?
editThe beginning of the article maps "ABI" to "Abstract Binary Interface". I'm pretty sure this is incorrect. Later in the article, "ABI" is mapped to "Application Binary Interface" which is what I've more commonly heard ABI defined as Electron100 (talk) 23:16, 31 December 2009 (UTC)
x64 Sections
editWhy are these two sections in an article titled "x86 calling conventions"? I think they should be in a separate article, or perhaps in x86-64. Jeh (talk) 11:51, 16 November 2010 (UTC)
Table of x86 calling conventions
editThe term "Red zone below stack" is never discussed before the table and is not explained, it should perhaps also be described how large it is, but on the other hand this is wikipedia and not the reference work... What it means is: For leaf functions (functions not calling other functions), they are free to use a certain number of bytes on the stack without having to change the stack pointer first. This matters for interrupt/signal handlers because they must start by moving the stack pointer below the red zone before they can push anything onto the stack, otherwise they risk corrupting data in leaf functions' red zone. 62.95.76.2 (talk) 08:24, 28 October 2011 (UTC)
Caller-/callee-safed registers
editIsn't it part of the calling convention, which processor registers must be saved by the caller/callee? If yes, it should be mentioned here. If not, where does this information belong to? --RokerHRO (talk) 09:11, 9 July 2013 (UTC)
- Oh, I see, it is mentioned in the text, but missed in the overview table below. It should be there, too. What do you think? :-/ --RokerHRO (talk) 09:14, 9 July 2013 (UTC)
"bare" of an OS or compilers, as did the IBM PC.
editTechnically true for certain values or "OS", "compilers", and "IBM PC".
The "IBM PC" came with ROM BASIC, which included File Access, Disk Access and Memory Access, and certainly had a calling convention, although not a CALL statement. — Preceding unsigned comment added by 203.206.162.148 (talk) 04:55, 12 August 2013 (UTC)
Lattice c return registers
editThe Lattice C 16 bit compiler returned 32 bit values in the AX:BX pair, not DX:AX. See http://bitsavers.informatik.uni-stuttgart.de/pdf/lattice/Lattice_C_8086_1982.pdf page 32. — Preceding unsigned comment added by 217.169.14.28 (talk) 07:28, 1 June 2015 (UTC)
Should the x64 calling convention be labeled as a variant of "__fastcall"?
editI have noticed that the MSDN refers to the standard x64 calling convention as __fastcall[1], as do various other sources[2][3][4]. Considering this, should the main article be updated to mention this? I'm not too familiar with wikipedia policies for this sort of thing, so I'll just leave the information here. 24.222.178.254 (talk) 21:43, 10 June 2016 (UTC)
References
- ^ https://msdn.microsoft.com/en-us/library/ms235286.aspx
- ^ http://forum.nasm.us/index.php?PHPSESSID=uqpaa0f4k5e1s7m70qvk3salc6&topic=1758.msg7484#msg7484
- ^ http://www.codemachine.com/article_x64deepdive.html (search for "default")
- ^ http://www.agner.org/optimize/calling_conventions.pdf (Table 16, pg.28-29)
"Parameters in registers" Column for x86-64 Entry
editIt lists the order as RDI, RSI, RDX, RCX, R8, R9, XMM0–7, but I think this is slightly unclear, for two reasons. The assembly output of compiling C code like:
static const char *string = "Hello, world!\n";
write ( 0, string, 14 );
results in the call to write() being something like:
movl $14,%edx movq $string,%rsi movl $0,%edi call write
The first point being that since on x86_64 pointers are 64 bits, but integers still default to 32 bits, it would be more accurate to say that the order is EDI/RDI, etc., depending on whether the parameter is an integer or an address.
The second point being that it might be helpful to indicate that the "order" referred to is how the code is read, left to right, *not* the order in which they are actually pushed onto the stack, right to left. So the "first" parameter from the callee's signature gets the first register in the described order, even though, in this case, it would be the third parameter pushed onto the stack, which might make one think that it was passed in EDX instead of EDI.
These are not academic points but things that actually did trip up my efforts for a bit before I looked a the -S output from gcc, so I thought I'd point out my misconceptions from having read the original text. — Preceding unsigned comment added by Ddade (talk • contribs) 05:06, 8 October 2016 (UTC)
Passing structs
editIn x86-64, there seems to be also a difference when passing structs:
- GCC, clang and ICC pass a struct comprising two doubles in xmm0 and xmm1 (https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,source:'struct+Vec2d+%7B+double+x%3B+double+y%3B+%7D%3B%0A%0Adouble+x1,+y1%3B%0A%0Avoid+f+(Vec2d+vec)%0A%7B%0A++++x1+%3D+vec.x%3B%0A++++y1+%3D+vec.y%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:,s:0,t:'0'),(g:!((h:compiler,i:(compiler:clang_trunk,filters:(b:'0',commentOnly:'0',directives:'0',intel:'0'),options:'-O3',source:1),l:'5',n:'0',o:'x86-64+clang+(trunk)+(Editor+%231,+Compiler+%231)',t:'0')),k:50,l:'4',n:'0',o:,s:0,t:'0')),l:'2',n:'0',o:,t:'0')),version:4)
- CL passes the same struct on the stack and puts the address in rxy (https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(j:1,source:'struct+Vec2d+%7B+double+x%3B+double+y%3B+%7D%3B%0A%0Adouble+x1,+y1%3B%0A%0Avoid+f+(Vec2d+vec)%0A%7B%0A++++x1+%3D+vec.x%3B%0A++++y1+%3D+vec.y%3B%0A%7D%0A'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:,s:0,t:'0'),(g:!((h:compiler,i:(compiler:cl19_64,filters:(b:'0',commentOnly:'0',directives:'0',intel:'0'),options:/Ox,source:1),l:'5',n:'0',o:'x86-64+CL+19+2017+RTW+(Editor+%231,+Compiler+%231)',t:'0')),k:50,l:'4',n:'0',o:,s:0,t:'0')),l:'2',n:'0',o:,t:'0')),version:4)
If the doubles appear as separate parameters, they are always passed in registers.
(That's also in line with https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx) — Preceding unsigned comment added by 217.13.68.110 (talk) 06:27, 12 April 2017 (UTC)
Callee clean-up
editThe information regarding the callee clean-up convention in x86 is wrong: ret n
unwinds the stack after returning to the caller (and not before) -- i.e., the return address is first popped from the stack, and, subsequently the stack pointer is incremented by n
. Here's the respective snippet from Intel's software dev. manual (Vol. 2, Instruction Set Reference, pp. 4-553)[1]: "The optional source operand specifies the number of stack bytes to be released after the return address is popped; the default is none. This operand can be used to release parameters from the stack that were passed to the called procedure and are no longer needed. It must be used when the CALL instruction used to switch to a new procedure uses a call gate with a non-zero word count to access the new procedure. Here, the source operand for the RET instruction must specify the same number of bytes as is specified in the word count field of the call gate." — Preceding unsigned comment added by Vkemerlis (talk • contribs) 15:51, 1 May 2017 (UTC)
- This is misleading. "After the return address is popped," yes. But the return isn't complete until the CPU starts executing instructions after the CALL. The called procedure cannot possibly do anything "after the return"!!!
- I would accept wording along the lines of "as part of the function of the RET instruction". I will not accept wording that says or implies that the "called procedure" does anything "after the return".
- Do you understand the problem with that wording?
- By the way, everything in there about call gates is irrelevant for Microsoft's calling conventions. They don't use call gates.
- Also btw, thank you for starting the discussion on the talk page, but having done so you should not re-revert to your preferred version until consensus is arrived at to support your change. WP:BRD means "bold, revert, discuss". It is not bold, revert, post an explanation and re-revert as if your explanation is all anybody should need to accept your change. There is no consensus for your change. Jeh (talk) 19:03, 1 May 2017 (UTC)
Oops, sorry for reverting without discussing first. I think that the whole point of dispute is that I'm mostly focusing on the semantics of the ret n
x86 instruction. I do agree that, at the high-level, it's the callee that basically unwinds the stack (i.e., by executing the ret n
instruction), but the way the sentence, regarding ret
in particular, was phrased before creates some confusion with respect to when the return address is popped and the stack pointer is advanced. How about the following:
"In these conventions, the callee cleans up the arguments from the stack. Functions which utilize these conventions are easy to recognize in ASM code because they will unwind the stack after returning. The x86 ret instruction allows an optional 16-bit parameter that specifies the number of stack bytes to release after returning to the caller." -> "In these conventions, the callee cleans up the arguments from the stack. Functions which utilize these conventions are easy to recognize in ASM code because they will unwind the stack before returning. The x86 ret instruction allows an optional 16-bit parameter that specifies the number of stack bytes to release after popping the return address from the stack and before returning to the caller."
(PS: yes the whole part regarding call gates is irrelevant; I just copy-pasted the whole par.) Vkemerlis (talk) 19:23, 2 May 2017 (UTC)
- I'm sorry, I still find it misleading and ambiguous. I'll propose a different wording a bit later (busy IRL now). Thank you for responding. Jeh (talk) 19:31, 2 May 2017 (UTC)
Topspeed/Clarion
editIt's been a while, but iirc one of the peculiarities of the Topspeed calling conventions was/is that parameters registers not used for parameters are callee-saved (iow non-volatile). 2A02:A458:C30A:1:C17F:5765:9DCF:67D0 (talk) 12:11, 30 December 2021 (UTC)
Flags?
editWhat about the flags register? — Preceding unsigned comment added by 77.61.180.106 (talk) 11:43, 1 April 2022 (UTC)
In stdcall, which registers should be saved?
editIn The Assembly Programming Master Book by Vlad Pirogov, there is a listing showing a skeleton definition of a window function that explicitly saves EBX, EBP, ESI, and EDI, and according to a comment following the listing, "[t]his is a requirement specified in the documentation". Could anyone please confirm this? Kamil Kurkiewicz (talk) 17:10, 6 January 2023 (UTC)
Clarifying parameter passing in Microsoft 64b calls
editThere should be some mention in the Microsoft x64 calling convention section clarifying that parameters that are passed in registers are passed in the register corresponding with their parameter position regardless of any intervening parameter that gets passed in a different type of register. For example:
fun1(int a, int b, int c) passes as expected with a in RCX, b in RDX, and c in R8, but...
fun2(int a, double b, int c) passes all these with a in RCX, b in XMM1 (not in XMM0), and c in R8 (not in RDX).
I'm not sure how to phrase this elegantly in the article for average readers without sounding clumsy. — al-Shimoni (talk) 09:30, 1 May 2023 (UTC)
- Do you have a reference for this? We can use it for inspiration on how to phrase it. bungalo (talk) 15:28, 1 May 2023 (UTC)