{"id":111316,"date":"2025-06-27T07:00:00","date_gmt":"2025-06-27T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111316"},"modified":"2025-06-27T09:00:11","modified_gmt":"2025-06-27T16:00:11","slug":"20250627-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250627-00\/?p=111316","title":{"rendered":"Why do I get errors or warnings about some weird symbol called ?main@@YAHP$01E$AAV?$Array@PE$AAVString@Platform&#8230;, part 3"},"content":{"rendered":"<p>We have been investigating <a title=\"Why do I get errors or warnings about some weird symbol called ?main@@YAHP$01E$AAV?$Array@PE$AAVString@Platform..., part 2\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250626-00\/?p=111314\"> why a project is getting an error about a weird C++\/CX symbol<\/a>, and we tracked it down to three things:<\/p>\n<ul>\n<li>If you compile with C++\/CX, the compiler injects <code>vccorlib.lib<\/code> as a default library.<\/li>\n<li>The <code>vccorlib.lib<\/code> library provides a definition of <code>main<\/code>.<\/li>\n<li>The linker <a title=\"LINK input files\" href=\"https:\/\/learn.microsoft.com\/cpp\/build\/reference\/link-input-files?view=msvc-170\"> special rule for resolving references introduced by a library<\/a> causes the search for <code>main<\/code> to look in <code>vccorlib.lib<\/code> ahead of the fuzzer library that contains the <code>main<\/code> we want.<\/li>\n<\/ul>\n<p>To get the linker to find the intended <code>main<\/code>, we need to take away one of the conditions.<\/p>\n<p>For the first item, we could take away all the components that use C++\/CX. But presumably they are there because we need to test them, so that&#8217;s not an option.<\/p>\n<p>Another possibility is to remove <code>vccorlib.lib<\/code> from the default library list. The library is still needed, but we can add it back as an explicit library.<\/p>\n<pre style=\"white-space: pre-wrap;\">link \/out:fuzzer.exe \/subsystem:console fuzzer.obj cx.obj lib.lib <span style=\"border: solid 1px currentcolor;\">vccorlib.lib \/NODEFAULTLIB:vccorlib.lib<\/span>\r\n<\/pre>\n<p>The avoids the problem with the special rule: The reference to <code>main<\/code> came from <code>libcmt.lib<\/code>, so the search proceeds through the rest of the default libs, and then wraps around back to the explicit libraries. In the list of explicit libraries, we have been careful to put <code>lib.lib<\/code> ahead of <code>vccorlib.lib<\/code>, so that the <code>main<\/code> in <code>lib.lib<\/code> gets found first.<\/p>\n<p>For the second item, there&#8217;s not much we can do because the <code>vccorlib.lib<\/code> is provided as part of the toolchain, so we are not at liberty to modify it.<\/p>\n<p>For the third item, we can try to avoid the linker special rule by making sure that the reference to <code>main<\/code> does not come from a library in the first place. That ensures that the search starts with the first explicitly library rather than doing the weird wraparound thing.<\/p>\n<p>One way to force it is to have another object file that contains an explicit reference to <code>main<\/code><\/p>\n<pre style=\"white-space: pre-wrap;\"><span style=\"border: solid 1px currentcolor; border-bottom: none;\">rem new! An object file that requests main.                              <\/span>\r\n<span style=\"border: 1px currentcolor; border-style: none solid;\">&gt;forcemain.cpp echo int __cdecl main(int, char**); auto forcemain = main;<\/span>\r\n<span style=\"border: solid 1px currentcolor; border-top: none;\">cl \/c forcemain.cpp                                                      <\/span>\r\n\r\nrem Add it as the first object file.\r\nlink \/out:fuzzer.exe \/subsystem:console <span style=\"border: solid 1px currentcolor;\">forcemain.obj<\/span> fuzzer.obj cx.obj lib.lib\r\n\r\nrem success!\r\n<\/pre>\n<p>The first reference to <code>main<\/code> comes from <code>forcemain<\/code>, which is not a library, so the special library search rule does not come into play.<\/p>\n<p>I put <code>forcemain.obj<\/code> first to increase the likelihood that it will provide the first reference to <code>main<\/code>. If it came second, then maybe resolving a symbol from the first object file leads to a reference that is resolved by a library, and that in turn requests a reference to <code>main<\/code>, and now the special library search rule kicks in.<\/p>\n<p>It may be difficult to ensure that <code>forcemain.obj<\/code> comes first. For example, some tooling might sort the object files alphabetically, or somebody might just decide to sort them alphabetically as part of just making things more tidy,\u00b9 causing <code>forcemain.obj<\/code> to lose its special place at the front of the object list.<\/p>\n<p>Therefore, I like to use the <code>\/INCLUDE<\/code> trick.<\/p>\n<pre style=\"white-space: pre-wrap;\">link \/out:fuzzer.exe \/subsystem:console fuzzer.obj cx.obj lib.lib <span style=\"border: solid 1px currentcolor;\">\/INCLUDE:main<\/span>\r\n\r\nrem success!\r\n<\/pre>\n<p>The compiler team tells me that references injected via <code>\/INCLUDE<\/code> get ushered to the front of the line, so they get resolved before any references that come from the object files themselves. In this case, it means that <code>\/INCLUDE:main<\/code> ensures that <code>main<\/code> is resolved before any symbols from object files, thereby removing the dependency on the order of object files.<\/p>\n<p>My colleague <a href=\"https:\/\/learn.microsoft.com\/en-us\/archive\/blogs\/martynl\/\"> Martyn Lovell<\/a> noted that even though you can cobble together something that works, he considers it generally a mistake to put your entry point in a library. Libraries generally carry the meaning of &#8220;Use this only if necessary,&#8221; but in the case of the fuzzing library, their specific <code>main<\/code> function is mandatory, not a fallback. This is <a title=\"How does the linker decide whether to call WinMain or wWinMain?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241004-00\/?p=110338\"> a problem I discussed earlier<\/a> in the context of choosing between <code>WinMain<\/code> and <code>wWinMain<\/code>.<\/p>\n<p>The entry point should be in an explicit object file that is added to the project, or (my preferred option) the library should provide its main function under a name like <code>fuzzer_main<\/code> which programs are expected to forward to.<\/p>\n<pre>\/\/ fuzzer.cpp\r\n#include &lt;fuzzerlibrary.h&gt;\r\nint __cdecl main(int argc, char** argv)\r\n{\r\n    return fuzzer_main(argc, argv);\r\n}\r\n\r\nbool fuzzer_callback(void* data, int length)\r\n{\r\n    \u27e6 ... \u27e7\r\n}\r\n<\/pre>\n<p>This also allows you to do things like choose between two fuzzers at runtime, or run multiple fuzzers from a single binary or run the same fuzzer twice.<\/p>\n<pre>\/\/ fuzzer.cpp\r\n#include &lt;fuzzerlibrary1.h&gt;\r\n#include &lt;fuzzerlibrary2.h&gt;\r\nint __cdecl main(int argc, char** argv)\r\n{\r\n    \/\/ If run with no arguments, then provide\r\n    \/\/ some defaults.\r\n    if (argc == 1) {\r\n        static char arg1[] = \"default-argument1\";\r\n        static char arg2[] = \"default-argument2\";\r\n        static char* args[] = { argv[0], arg1, arg2 };\r\n        argc = 3;\r\n        argv = args;\r\n    }\r\n\r\n    \/\/ Run it through both fuzzers\r\n    int result = fuzzer1_main(argc, argv);\r\n    if (result == 0) {\r\n        result = fuzzer2_main(argc, argv);\r\n    }\r\n}\r\n    return result;\r\n}\r\n\r\nbool fuzzer_callback(void* data, int length)\r\n{\r\n    \u27e6 ... \u27e7\r\n}\r\n<\/pre>\n<p>Now, for convenience, the fuzzer library could also provide the <code>main<\/code> function that we put into <code>fuzzer.cpp<\/code>. But even so, there should be a separate name (like <code>fuzzer_main<\/code>) that can be used to invoke it explicitly.<\/p>\n<p>\u00b9 For example, keeping lists in alphabetical or numeric order reduces the likelihood of bad merges.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Forcing <CODE>main<\/CODE> to be found in the place we want.<\/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-111316","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Forcing <CODE>main<\/CODE> to be found in the place we want.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111316","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=111316"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111316\/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=111316"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111316"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111316"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}