{"id":30383,"date":"2006-07-25T07:00:00","date_gmt":"2006-07-25T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/07\/25\/issues-related-to-forcing-a-stub-to-be-created-for-an-imported-function\/"},"modified":"2006-07-25T07:00:00","modified_gmt":"2006-07-25T07:00:00","slug":"issues-related-to-forcing-a-stub-to-be-created-for-an-imported-function","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060725-00\/?p=30383","title":{"rendered":"Issues related to forcing a stub to be created for an imported function"},"content":{"rendered":"<p>\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/07\/24\/676669.aspx\">\nI noted last time<\/a>\nthat you can concoct situations that force the creation of\na stub for an imported function.\nFor example, if you declare a global function pointer variable:\n<\/p>\n<pre>\nDWORD (WINAPI *g_pGetVersion)() = GetVersion;\n<\/pre>\n<p>\nthen the C compiler is forced to generate the stub and assign\nthe address of the stub to the\n<code>g_pGetVersion<\/code> variable.\nThat&#8217;s the best it can do, since the loader will patch up only\nthe imported function address table; it won&#8217;t patch up anything\nelse in the data segment.\n<\/p>\n<p>\nThe C++ compiler, on the other hand, can take advantage of some\nC++ magic and secretly generate a &#8220;pseudo global constructor&#8221;\n(I just made up that term so don&#8217;t go around using it like it&#8217;s\nofficial or something)\nthat copies the value from the imported function address table\nto the <code>g_pGetVersion<\/code> variable at runtime.\nNote, however, that since this is happening at runtime, mixed\nin with all the other global constructors,\nthen the variable might not be set properly if you call it\nfrom any code that runs during construction of global objects.\nConsider the following buggy program made up of two files.\n<\/p>\n<pre>\n<i>\/\/ file1.cpp\n#include &lt;windows.h&gt;\nEXTERN_C DWORD (WINAPI *g_pGetVersion)();\nclass Oops {\n  public: Oops() { g_pGetVersion(); }\n} g_oops;\nint __cdecl main(int argc, char **argv)\n{\n  return 0;\n}\n\/\/ file2.cpp\n#include &lt;windows.h&gt;\nEXTERN_C DWORD (WINAPI *g_pGetVersion)() = GetVersion;\n<\/i>\n<\/pre>\n<p>\nThe rules for C++ construction of global objects is that global\nobjects within a single translation unit are constructed in the\norder they are declared (and destructed in reverse order),\nbut there is no enforced order for global objects from separate\ntranslation units.\nBut notice that there is an order-of-construction dependency\nhere.\nThe construction of the <code>g_oops<\/code> object requires that\nthe <code>g_pGetVersion<\/code> object be fully constructed,\nbecause it&#8217;s going to call through the pointer when the <code>Oops<\/code>\nconstructor runs.\n<\/p>\n<p>\nIt so happens that the Microsoft linker constructs global\nobjects in the order in which the corresponding OBJ files are\nlisted in the linker&#8217;s command line.\n(I don&#8217;t know whether this is guaranteed behavior or merely\nan implementation detail, so I wouldn&#8217;t rely on it.)\nConsequently,\nif you tell the linker to link <code>file1.obj + file2.obj<\/code>,\nyou will crash because the linker will generate a call to\nthe <code>Oops::Oops()<\/code> constructor before it gets\naround to constructing <code>g_pGetVersion<\/code>.\nOn the other hand, if you list them in the order\n<code>file2.obj + file1.obj<\/code>,\nyou will run fine.\n<\/p>\n<p>\nEven stranger: If you rename <code>file2.cpp<\/code> to\n<code>file2.c<\/code>, then the program will run fine regardless\nof what order you give the OBJ files to the linker,\nbecause the C compiler will use the stub instead of trying to\ncopy the imported function address at runtime.\n<\/p>\n<p>\nBut what happens if you mess up and declare a function as\n<code>dllimport<\/code> when it isn&#8217;t, or vice versa?\nWe&#8217;ll look at that next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I noted last time that you can concoct situations that force the creation of a stub for an imported function. For example, if you declare a global function pointer variable: DWORD (WINAPI *g_pGetVersion)() = GetVersion; then the C compiler is forced to generate the stub and assign the address of the stub to the g_pGetVersion [&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":[26],"class_list":["post-30383","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>I noted last time that you can concoct situations that force the creation of a stub for an imported function. For example, if you declare a global function pointer variable: DWORD (WINAPI *g_pGetVersion)() = GetVersion; then the C compiler is forced to generate the stub and assign the address of the stub to the g_pGetVersion [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30383","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=30383"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/30383\/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=30383"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=30383"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=30383"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}