{"id":109077,"date":"2023-11-29T07:00:00","date_gmt":"2023-11-29T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109077"},"modified":"2023-11-29T07:09:57","modified_gmt":"2023-11-29T15:09:57","slug":"20231129-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231129-00\/?p=109077","title":{"rendered":"Why does the Windows Portable Executable (PE) format have separate tables for import names and import addresses?, part 1"},"content":{"rendered":"<p>In the Windows Portable Executable (PE) format, the image import descriptor table describes the functions imported from a specific target DLL.<\/p>\n<pre>struct IMAGE_IMPORT_DESCRIPTOR {\r\n    DWORD   OriginalFirstThunk;\r\n    DWORD   TimeDateStamp;\r\n    DWORD   ForwarderChain;\r\n    DWORD   Name;\r\n    DWORD   FirstThunk;\r\n};\r\n<\/pre>\n<p>The <code>OriginalFirstThunk<\/code> points to an array of pointer-sized <code>IMAGE_THUNK_DATA<\/code> structures which describe the functions being imported. The <code>FirstThunk<\/code> points to an array of pointers, whose initial values are a copy of the values pointed to by <code>OriginalFirstThunk<\/code>. When the DLL is loaded, those initial values in the <code>FirstThunk<\/code> table are replaced by the actual function pointers determined at runtime.<\/p>\n<p>But why are there two copies of the table? The two tables are never needed at the same time, so why not reuse the memory? When the DLL is initially loaded, the entries describe the functions being imported, and after the function addresses are located, they could be written back into the same table.<\/p>\n<p>The answer is <a title=\"What is DLL import binding?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100318-00\/?p=14563\"> DLL binding<\/a>.<\/p>\n<p>As a load-time optimization, you can <i>bind<\/i> your DLL to its targets. If the target DLL has <code>0x20304000<\/code> as its preferred base address, then if the DLL gets loaded at that preferred base address, you know what all the function addresses are going to be, and <i>binding<\/i> records those precalculated function addresses into the <code>FirstThunk<\/code> table. After binding is performed, the <code>FirstThunk<\/code> table now holds the precalculated function addresses and is not a copy of the <code>OriginalFirstThunk<\/code> table. The module timestamp of the DLL that was used to calculate the bindings is recorded in the image import directory.\u00b9<\/p>\n<p>When the DLL is loaded, the loader checks whether the module timestamp recorded in the image import descriptor matches the timestamp of the actual module found at runtime. If so, then it just uses the precalculated values in the <code>FirstThunk<\/code> table. And if not, then the loader uses the <code>OriginalFirstThunk<\/code> table to look up the functions at runtime.<\/p>\n<p>Therefore, you can&#8217;t combine the <code>OriginalFirstThunk<\/code> and <code>FirstThunk<\/code> tables: If the precalculated values in the <code>FirstThunk<\/code> table cannot be used, you need to go back to the original values in <code>OriginalFirstThunk<\/code> to resolve the imports the old-fashioned way.<\/p>\n<p><b>Bonus chatter<\/b>: Binding is of relatively little value nowadays <a title=\"How important is it nowadays to ensure that all my DLLs have non-conflicting base addresses?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170120-00\/?p=95225\"> due to address space layout randomization<\/a>.<\/p>\n<p>\u00b9 And the module timestamp <a title=\"Why are the module timestamps in Windows 10 so nonsensical?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180103-00\/?p=97705\"> is often not really a timestamp<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Even though their lifetimes don&#8217;t overlap, you sometimes need to go back in time.<\/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-109077","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Even though their lifetimes don&#8217;t overlap, you sometimes need to go back in time.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109077","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=109077"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109077\/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=109077"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109077"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109077"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}