{"id":43233,"date":"2015-01-02T07:00:00","date_gmt":"2015-01-02T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2015\/01\/02\/how-do-you-prevent-the-linker-from-discarding-a-function-you-want-to-make-available-for-debugging\/"},"modified":"2019-03-13T12:11:43","modified_gmt":"2019-03-13T19:11:43","slug":"20150102-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150102-00\/?p=43233","title":{"rendered":"How do you prevent the linker from discarding a function you want to make available for debugging?"},"content":{"rendered":"<p>We saw some time ago that you can ask the Windows symbolic debugger engine to <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2007\/04\/27\/2292037.aspx\">call a function directly from the debugger<\/a>. To do this, of course, the function needs to exist. <\/p>\n<p>But what if you want a function for the sole purpose of debugging? It never gets called from the main program, so the linker will declare the code dead and remove it. <\/p>\n<p>One sledgehammer solution is to <a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/vstudio\/bxwfs976.aspx\">disable discarding of unused functions<\/a>. This the global solution to a local problem, since you are now preventing the discard of <i>any<\/i> unused function, even though all you care about is one specific function. <\/p>\n<p>If you are comfortable hard-coding function decorations for specific architectures, you can use the <code>\/INCLUDE<\/code> directive. <\/p>\n<pre>\n#if defined(_X86_)\n#define DecorateCdeclFunctionName(fn) \"_\" #fn\n#elif defined(_AMD64_)\n#define DecorateCdeclFunctionName(fn) #fn\n#elif defined(_IA64_)\n#define DecorateCdeclFunctionName(fn) \".\" #fn\n#elif defined(_ALPHA_)\n#define DecorateCdeclFunctionName(fn) #fn\n#elif defined(_MIPS_)\n#define DecorateCdeclFunctionName(fn) #fn\n#elif defined(_PPC_)\n#define DecorateCdeclFunctionName(fn) \"..\" #fn\n#else\n#error Unknown architecture - don't know how it decorates cdecl.\n#endif\n#pragma comment(linker, \"\/include:\" DecoratedCdeclFunctionName(TestMe))\nEXTERN_C void __cdecl TestMe(int x, int y)\n{\n    ...\n}\n<\/pre>\n<p>If you are not comfortable with that (and I don&#8217;t blame you), you can create a false reference to the debugging function that cannot be optimized out. You do this by passing a pointer to the debugging function to a helper function outside your module that doesn&#8217;t do anything interesting. Since the helper function is not in your module, the compiler doesn&#8217;t know that the helper function doesn&#8217;t do anything, so it cannot optimize out the debugging function. <\/p>\n<pre>\nstruct ForceFunctionToBeLinked\n{\n  ForceFunctionToBeLinked(const void *p) { SetLastError(PtrToInt(p)); }\n};\n\nForceFunctionToBeLinked forceTestMe(TestMe);\n<\/pre>\n<p>The call to <code>Set&shy;Last&shy;Error<\/code> merely updates the thread&#8217;s last-error code, but since this is not called at a time where anybody cares about the last-error code, it is has no meaningful effect. The compiler doesn&#8217;t know that, though, so it has to generate the code, and that forces the function to be linked. <\/p>\n<p>The nice thing about this technique is that the optimizer sees that this class has no data members, so no data gets generated into the module&#8217;s data segment. The not-nice thing about this technique is that it is kind of opaque. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Put it outside the linker&#8217;s knowledge.<\/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-43233","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Put it outside the linker&#8217;s knowledge.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43233","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=43233"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/43233\/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=43233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=43233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=43233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}