{"id":100165,"date":"2018-11-08T07:00:00","date_gmt":"2018-11-08T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=100165"},"modified":"2021-02-13T07:33:17","modified_gmt":"2021-02-13T15:33:17","slug":"20181108-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20181108-00\/?p=100165","title":{"rendered":"Gotchas when using linker sections to arrange data, part 1"},"content":{"rendered":"<p>We saw <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20181107-00\/?p=100155\"> last time<\/a> that you can use linker sections to arrange the order in which data appears in the module. We ended with a diagram like this:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px black;\"><code>mydata$a<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>firstInitializer<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>main.obj<\/code><\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"2\"><code>mydata$g<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>DoThisSooner3<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file3.obj<\/code><\/td>\n<td style=\"border: solid black; border-width: 1px 0px;\" rowspan=\"2\">unspecified<br \/>\norder<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>DoThisSooner4<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file4.obj<\/code><\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"3\"><code>mydata$m<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>Function2<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file2.obj<\/code><\/td>\n<td style=\"border: solid black; border-width: 1px 0px;\" rowspan=\"3\">unspecified<br \/>\norder<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>Function1<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file1.obj<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>Function3<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file3.obj<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"2\"><code>mydata$t<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>DoThisLater2<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file2.obj<\/code><\/td>\n<td style=\"border: solid black; border-width: 1px 0px;\" rowspan=\"2\">unspecified<br \/>\norder<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>DoThisLater4<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file4.obj<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>mydata$z<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>lastInitializer<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>main.obj<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Based on this table, we would be tempted to write code like this:<\/p>\n<pre>\/\/ Code in italics is wrong.\r\n<i>void NaiveInitializeAllTheThings()\r\n{\r\n    const INITIALIZER* initializer = &amp;firstInitializer + 1;\r\n    while (initializer &lt; &amp;lastInitializer) {\r\n      (*initializer++)();\r\n    }\r\n}<\/i>\r\n<\/pre>\n<p>From a language lawyer standpoint, this code is not valid because it dereferences a pointer beyond the end of an object, and because it compares two pointers which are not part of the same aggregate. We can fix this by switching to <code>uintptr_t<\/code> as our currency.<\/p>\n<pre>\/\/ Code in italics is still wrong.\r\n<i>void LessNaiveInitializeAllTheThings()\r\n{\r\n    auto begin = (uintptr_t)&amp;firstInitializer\r\n                 + sizeof(firstInitializer);\r\n    auto end = (uintptr_t)&amp;lastInitializer;\r\n    for (auto current = begin; current &lt; end;\r\n         current += sizeof(INITIALIZER)) {\r\n      auto initializer = *(const INITIALIZER*)current;\r\n      initializer();\r\n    }\r\n}<\/i>\r\n<\/pre>\n<p>The conversion between pointers and <code>uintptr_t<\/code> is implementation-defined (rather than undefined), so this avoids the undefined behavior problems of using pointers to walk between two global variables.<\/p>\n<p>But the code is still not right, because it fails to take into account another detail of linker sections: intra-section padding.<\/p>\n<p>The linker will add padding after a fragment in order to satisfy any alignment requirements of the subsequent fragment. That&#8217;s expected.<\/p>\n<p>What most people aren&#8217;t aware of is that the linker is permitted but not required to add padding after each fragment, up to the section&#8217;s alignment. In practice, you are likely to see this &#8220;unnecessary&#8221; padding when using <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/build\/reference\/incremental-link-incrementally\"> incremental linking<\/a>.<\/p>\n<p>In all cases, the padding bytes (if any) will be zero.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"2\"><code>mydata$a<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>firstInitializer<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>main.obj<\/code><\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"4\"><code>mydata$g<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>DoThisSooner3<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file3.obj<\/code><\/td>\n<td style=\"border: solid black; border-width: 1px 0px;\" rowspan=\"4\">unspecified<br \/>\norder<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>DoThisSooner4<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file4.obj<\/code><\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"6\"><code>mydata$m<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>Function2<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file2.obj<\/code><\/td>\n<td style=\"border: solid black; border-width: 1px 0px;\" rowspan=\"6\">unspecified<br \/>\norder<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>Function1<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file1.obj<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>Function3<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file3.obj<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"4\"><code>mydata$t<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>DoThisLater2<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file2.obj<\/code><\/td>\n<td style=\"border: solid black; border-width: 1px 0px;\" rowspan=\"4\">unspecified<br \/>\norder<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\"><code>DoThisLater4<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>file4.obj<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black;\" rowspan=\"2\"><code>mydata$z<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>lastInitializer<\/code><\/td>\n<td style=\"border: solid 1px black;\"><code>main.obj<\/code><\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px black; text-align: center;\" colspan=\"2\">Optional padding<\/td>\n<td style=\"border: none;\">\u00a0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>To accommodate padding, we need to skip over any possible null pointers.<\/p>\n<pre>void InitializeAllTheThings()\r\n{\r\n    auto begin = (uintptr_t)&amp;firstInitializer\r\n                 + sizeof(firstInitializer);\r\n    auto end = (uintptr_t)&amp;lastInitializer;\r\n    for (auto current = begin; current &lt; end;\r\n         current += sizeof(INITIALIZER)) {\r\n      auto initializer = *(const INITIALIZER*)current;\r\n      <span style=\"color: blue;\">if (initializer)<\/span> initializer();\r\n    }\r\n}\r\n<\/pre>\n<p>We&#8217;ll look at another consequence of padding <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20181109-00\/?p=100175\"> next time<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nulls can show up in unexpected places.<\/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,131],"class_list":["post-100165","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code","tag-linker"],"acf":[],"blog_post_summary":"<p>Nulls can show up in unexpected places.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100165","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=100165"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100165\/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=100165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=100165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=100165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}