{"id":14563,"date":"2010-03-18T07:00:00","date_gmt":"2010-03-18T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/03\/18\/what-is-dll-import-binding\/"},"modified":"2010-03-18T07:00:00","modified_gmt":"2010-03-18T07:00:00","slug":"what-is-dll-import-binding","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100318-00\/?p=14563","title":{"rendered":"What is DLL import binding?"},"content":{"rendered":"<p>\nLast time, we saw how\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2010\/03\/17\/9980011.aspx\">\n<i>hinting<\/i> is used to speed up\nthe resolving of imported functions<\/a>.\nToday, we&#8217;ll look at <i>binding<\/i>.\n<\/p>\n<p>\nRecall that the module loader resolves imports by locating the\nfunction in the export table of the linked-to DLL\nand\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2006\/07\/20\/672695.aspx\">\nrecording the results in the loaded module&#8217;s table of\nimported function addresses<\/a>\nso that code from the module can jump indirectly through the table\nand reach the target function.\n<\/p>\n<p>\nOne of the consequences of this basic idea is that the table of\nimported function addresses is written to at module load time.\nWriteable data in a module is stored in the form of copy-on-write\npages.\nCopy-on-write pages are a form of computer optimism:\n&#8220;I&#8217;m going to assume that nobody writes to this page,\nso that I can share it among all copies of the DLL loaded\ninto different processes&#8221;\n(assuming other conditions are met,\nnot important to this discussion; don&#8217;t make me bring back\nthe nitpicker&#8217;s corner).\n&#8220;In this way, I can conserve memory,\nleaving more memory available for other things.&#8221;\nBut once you write to the page,\nthat assumption is proven false, and the memory manager needs\nto make a private copy of the page for your process.\nIf two processes load your DLL,\nthey each get their own copy of the memory once they write to it,\nand the opportunity to share the memory between the two DLLs is lost.\n<\/p>\n<p>\nWhat is particularly sad is when the copy-on-write page is forced\nto be copied because two processes wrote to the pages,\neven if the processes <i>wrote the same value<\/i>.\nSince the two pages are now once again identical,\nthey could in principle be shared again.\n(The memory manager doesn&#8217;t do <code>memcmp<\/code>s of\nevery potentially-shared page each time you write to it,\non the off chance that you happened to make two pages\ncoincidentally identical.\nOnce a copy-on-write page is written to, the memory manager makes\nthe copy and says, &#8220;Oh well, it was good while it lasted.&#8221;)\n<\/p>\n<p>\nOne of the cases where two processes both write to the page and\nwrite the same value is when they are resolving imports to the same\nDLL.\nIn that case, the call to <code>GetProcAddress<\/code> will return\nthe same value in both processes (assuming the target DLL is loaded\nat the same base address in both processes),\nand you are in the sad case where two processes dirty the page\nby writing the same value.\n<\/p>\n<p>\nTo make this sad case happy again, the module loader has an optimization\nto avoid writing to pages it doesn&#8217;t have to:\nWe pre-initialize the values in the table of\nimported function addresses to a prediction as to what the\nactual address of the function will be.\nThen we can have the module loader compare the return value of\n<code>GetProcAddress<\/code> against the predicted value,\nand if they are the same, it skips the write.\nIn context diff format:\n<\/p>\n<pre>\n\/\/ error checking deleted since it's not relevant to the discussion\nfor (Index = 0; Index &lt; NumberOfImportedFunctions; Index++) {\n  FunctionPointer = GetProcAddress(hinst, ImportEntry[Index]);\n- TableEntry[Index] = FunctionPointer;\n+ if (TableEntry[Index] != FunctionPointer)\n+   TableEntry[Index] = FunctionPointer;\n}\n<\/pre>\n<p>\nBut wait, we can optimize this even more.\nHow about avoiding the entire loop?\nThis saves us the trouble of having to call <code>GetProcAddress<\/code>\nin the first place.\n<\/p>\n<p>\nThere is an extra field in the import descriptor table entry called\n<code>TimeDateStamp<\/code> which records the timestamp of the\nDLL from which the precomputed function pointer values were obtained.\nEvery DLL has a timestamp, recorded in the module header information.\n(The format of this timestamp is in\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/09\/05\/54806.aspx\">\nseconds since January 1, 1970<\/a>,\ncommonly known as unix time format.)\nBefore the module loader resolves imported functions,\nit compares the timestamp in the import descriptor table entry\nagainst the timestamp in the actual DLL that got loaded.\nIf they match (and if the actual DLL was loaded at its preferred\nbase address),\nthen the module loader skips the loop entirely:\nAll the precomputed values are correct.\n<\/p>\n<p>\nThat&#8217;s the classical model for binding.\nThere have been some changes since the original implementation,\nbut they don&#8217;t change the underlying principle:\nPrecompute the answers and associate them with a key which lets\nyou determine whether the information against which the values were\nprecomputed matches the information that you actually have.\n<\/p>\n<p>\nBinding therefore is a performance optimization to address both\nwall-clock running time\n(by reducing the amount of computation performed at\nmodule load time)\nand memory consumption\n(by reducing the number of copy-on-write pages actually written to).\n<\/p>\n<p>\n<b>Exercise<\/b>:\nWhy is the timestamp stored in the module header?\nWhy not just use the actual file last-modified time?\n<\/p>\n<p>\n<b>Exercise<\/b>:\nWhen you rebase a DLL, does it update the timestamp?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time, we saw how hinting is used to speed up the resolving of imported functions. Today, we&#8217;ll look at binding. Recall that the module loader resolves imports by locating the function in the export table of the linked-to DLL and recording the results in the loaded module&#8217;s table of imported function addresses so 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-14563","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Last time, we saw how hinting is used to speed up the resolving of imported functions. Today, we&#8217;ll look at binding. Recall that the module loader resolves imports by locating the function in the export table of the linked-to DLL and recording the results in the loaded module&#8217;s table of imported function addresses so that [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/14563","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=14563"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/14563\/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=14563"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=14563"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=14563"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}