{"id":40993,"date":"2004-01-20T07:00:00","date_gmt":"2004-01-20T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/01\/20\/ia64-misdeclaring-near-and-far-data\/"},"modified":"2004-01-20T07:00:00","modified_gmt":"2004-01-20T07:00:00","slug":"ia64-misdeclaring-near-and-far-data","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040120-00\/?p=40993","title":{"rendered":"ia64 &#8211; misdeclaring near and far data"},"content":{"rendered":"<p>As I mentioned yesterday,\nthe ia64 is a very demanding architecture.\nToday I&#8217;ll discuss another way that lying to the compiler will\ncome back and bite you.<\/p>\n<p>\nThe ia64 does not have an absolute addressing mode.\nInstead, you access your global variables through the r1\nregister, nicknamed &#8220;gp&#8221; (global pointer).\nThis register always points to your global variables.\nFor example, if you had three global variables, one\nof them might be kept at [gp+0], the second at [gp+8]\nand the third at [gp+16].\n<\/p>\n<p>\n(I believe the Win32 MIPS calling convention also used this technique.)\n<\/p>\n<p>\nOn the ia64,\nthere is a limitation in the &#8220;addl&#8221; instruction: You can only\nadd constants up to 22 bits, which comes out to 4MB.\nSo you can have only 4MB of global variables.\n<\/p>\n<p>\nWell, it turns out that some people want more than 4MB of\nglobal variables.  Fortunately, these people don&#8217;t have\none million DWORD variables.  Rather, they have a few\nreally big global arrays.\n<\/p>\n<p>\nThe ia64 compiler solves this problem by splitting global\nvariables into two categories, &#8220;small&#8221; and &#8220;large&#8221;.\n(The boundary between &#8220;small&#8221; and &#8220;large&#8221; can be set by\na compiler flag. I believe the default is to treat anything\nlarger than 8 bytes as &#8220;large&#8221;.)\n<\/p>\n<p>\nThe code to access a &#8220;small&#8221; variable goes like this:\n<\/p>\n<pre>\n        addl    r30 = -205584, gp;; \/\/ r30 -&gt; global variable\n        ld4     r30 = [r30]         \/\/ load a DWORD from the global variable\n<\/pre>\n<p>\n(The gp register actually points into the middle of your global\nvariables, so that both positive and negative offsets can be used.\nIn this case, the variable happened to live at a negative offset\nfrom gp.)\n<\/p>\n<p>\nBy comparison, &#8220;large&#8221; global variables are accessed through a\ntwo-step process.  First, the variable itself is allocated in a\nseparate section of the file.  Second, a pointer to the variable\nis placed into the &#8220;small&#8221; globals variables section of the\nmodule.  As a result, accessing a &#8220;large&#8221; global variable requires\nan added level of indirection.\n<\/p>\n<pre>\n        addl    r30 = -205584, gp;; \/\/ r30 -&gt; global variable forwarder\n        ld8     r30 = [r30];;       \/\/ r30 -&gt; global variable\n        ld4     r30 = [r30]         \/\/ load a DWORD from the global variable\n<\/pre>\n<p>\nIf you leave the size of an object unspecified, like<\/p>\n<pre>\nextern BYTE b[];\n<\/pre>\n<p>then the compiler plays it safe and assumes the variable is large.\nIf it turns out that the variable is small,\nthe forwarder pointer will still be there, and the code will\ndo the double-indirection to fetch something that could have\nbeen accessed with a single indirection.\nThe code is slightly less efficient, but at least it still works.\n<\/p>\n<p>\nOn the other hand,\nif you misdeclare the object as being small when it is actually\nlarge, then you end up in trouble.\nFor example, if you write<\/p>\n<pre>\n    extern BYTE b;\n<\/pre>\n<p>in one file, and<\/p>\n<pre>\n    extern BYTE b[256];\n<\/pre>\n<p>in another, then files that include the first header will think\nthe object is small and generate &#8220;small&#8221; code to access it, but\nfiles that include the second header will think it is large.\nAnd if the object turns out to be large after all, the code that\nused the first header file will fail pretty spectacularly.\n<\/p>\n<p>\nSo don&#8217;t do that. When you declare a variable, make sure to declare\nit accurately. Otherwise the ia64 will catch you in a lie,\nand you will pay.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As I mentioned yesterday, the ia64 is a very demanding architecture. Today I&#8217;ll discuss another way that lying to the compiler will come back and bite you. The ia64 does not have an absolute addressing mode. Instead, you access your global variables through the r1 register, nicknamed &#8220;gp&#8221; (global pointer). This register always points to [&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-40993","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>As I mentioned yesterday, the ia64 is a very demanding architecture. Today I&#8217;ll discuss another way that lying to the compiler will come back and bite you. The ia64 does not have an absolute addressing mode. Instead, you access your global variables through the r1 register, nicknamed &#8220;gp&#8221; (global pointer). This register always points to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40993","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=40993"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40993\/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=40993"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=40993"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=40993"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}