{"id":11333,"date":"2011-03-02T07:00:00","date_gmt":"2011-03-02T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/03\/02\/although-the-x64-calling-convention-reserves-spill-space-for-parameters-you-dont-have-to-use-them-as-such\/"},"modified":"2011-03-02T07:00:00","modified_gmt":"2011-03-02T07:00:00","slug":"although-the-x64-calling-convention-reserves-spill-space-for-parameters-you-dont-have-to-use-them-as-such","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110302-00\/?p=11333","title":{"rendered":"Although the x64 calling convention reserves spill space for parameters, you don&#039;t have to use them as such"},"content":{"rendered":"<p>\nAlthough the\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/01\/14\/58579.aspx\">\nx64 calling convention<\/a>\nreserves space on the stack as spill locations\nfor the first four parameters (passed in registers),\nthere is no requirement that the spill locations actually be used\nfor spilling.\nThey&#8217;re just 32 bytes of memory available for scratch use by the function\nbeing called.\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nWe have a test program that works okay when optimizations are disabled,\nbut when compiled with full optimizations, everything appears to be wrong\nright off the bat.\nIt doesn&#8217;t get the correct values for\n<code>argc<\/code> and <code>argv<\/code>:\n<\/p>\n<pre>\nint __cdecl\nwmain( int argc, WCHAR** argv ) { ... }\n<\/pre>\n<p>\nWith optimizations disabled, the code is generated correctly:\n<\/p>\n<pre>\n        mov         [rsp+10h],rdx  \/\/ argv\n        mov         [rsp+8],ecx    \/\/ argc\n        sub         rsp,158h       \/\/ local variables\n        mov         [rsp+130h],0FFFFFFFFFFFFFFFEh\n        ...\n<\/pre>\n<p>\nBut when we compile with optimizations, everything is completely\nmessed up:\n<\/p>\n<pre>\n        mov         rax,rsp\n        push        rsi\n        push        rdi\n        push        r13\n        sub         rsp,0E0h\n        mov         qword ptr [rsp+78h],0FFFFFFFFFFFFFFFEh\n        mov         [rax+8],rbx    \/\/ ??? should be ecx (argc)\n        mov         [rax+10h],rbp  \/\/ ??? should be edx (argv)\n<\/pre>\n<\/blockquote>\n<p>\nWhen compiler optimizations are disabled, the Visual C++ x64 compiler\nwill spill all register parameters into their corresponding slots.\nThis has as a nice side effect that debugging is a little easier,\nbut really it&#8217;s just because you disabled optimizations,\nso the compiler generates simple, straightforward code,\nmaking no attempts to be clever.\n<\/p>\n<p>\nWhen optimizations are enabled, then the compiler becomes more\naggressive about removing redundant operations and using memory\nfor multiple purposes when variable lifetimes don&#8217;t overlap.\nIf it finds that it doesn&#8217;t need to save <code>argc<\/code>\ninto memory (maybe it puts it into a register),\nthen the spill slot for <code>argc<\/code> can be used for\nsomething else; in this case, it&#8217;s being used to preserve\nthe value of <code>rbx<\/code>.\n<\/p>\n<p>\nYou see the same thing even in x86 code,\nwhere the memory used to pass parameters can be re-used\nfor other purposes once the value of the parameter is no\nlonger needed in memory.\n(The compiler might load the value into a register and use\nthe value from the register for the remainder of the function,\nat which point the memory used to hold the parameter becomes\nunused and can be redeployed for some other purpose.)\n<\/p>\n<p>\nWhatever problem you&#8217;re having with your test program,\nthere is nothing obviously wrong with the code generation\nprovided in the purported defect report.\nThe problem lies elsewhere.\n(And it&#8217;s probably somewhere in your program.\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/02\/10\/10127054.aspx\">\nDon&#8217;t immediately assume that the reason for your problem\nis a compiler bug<\/a>.)\n<\/p>\n<p>\n<b>Bonus chatter<\/b>:\nIn a (sadly rare) follow-up, the customer confessed that the\nproblem was indeed in their program.\nThey put a function call inside an <code>assert<\/code>,\nand in the nondebug build, they disabled assertions\n(by passing <code>\/DNDEBUG<\/code> to the compiler),\nwhich means that in the nondebug build, the function was never called.\n<\/p>\n<p>\n<b>Extra reading<\/b>:\n<a HREF=\"http:\/\/blogs.msdn.com\/ntdebugging\/archive\/2009\/01\/09\/challenges-of-debugging-optimized-x64-code.aspx\">\nChallenges of debugging optimized x64 code<\/a>.\nThat <code>.frame \/r<\/code> command is real time-saver.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Although the x64 calling convention reserves space on the stack as spill locations for the first four parameters (passed in registers), there is no requirement that the spill locations actually be used for spilling. They&#8217;re just 32 bytes of memory available for scratch use by the function being called. We have a test program that [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-11333","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Although the x64 calling convention reserves space on the stack as spill locations for the first four parameters (passed in registers), there is no requirement that the spill locations actually be used for spilling. They&#8217;re just 32 bytes of memory available for scratch use by the function being called. We have a test program that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11333","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=11333"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/11333\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=11333"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=11333"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=11333"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}