{"id":109095,"date":"2023-12-04T07:00:00","date_gmt":"2023-12-04T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109095"},"modified":"2023-12-04T13:46:06","modified_gmt":"2023-12-04T21:46:06","slug":"20231204-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231204-00\/?p=109095","title":{"rendered":"What is a static chain pointer in the context of calling convention ABI?"},"content":{"rendered":"<p>Buried deep in the System V Application Binary Interface document for the AMD64 Architecture, there is a footnote on page 24 that says, &#8220;<code>%r10<\/code> is used for passing a function&#8217;s static chain pointer.&#8221; What is a static chain pointer?<\/p>\n<p>Some languages, such as Pascal, supported nested functions such that the nested function is permitted to access variables from its parent.<\/p>\n<pre>function Outer(n: integer) : integer;\r\n    var i: integer;\r\n\r\n    procedure Inner(m: integer);\r\n    begin\r\n        i := i + m\r\n    end;\r\n\r\n(* Outer body begins here *)\r\nbegin\r\n    i := 0;\r\n    Inner(n);\r\n    Outer := i\r\nend;\r\n<\/pre>\n<p>The <code>Outer<\/code> function doesn&#8217;t do anything useful, but it does it in an interesting way.<\/p>\n<p>It begins with a local variable declaration for <code>i<\/code>, and then defines a local procedure <code>Inner<\/code> which adds its parameter <code>m<\/code> to the <code>Outer<\/code> variable <code>i<\/code>. The <code>Outer<\/code> function then initializes <code>i<\/code> to zero, calls <code>Inner(n)<\/code> (which adds <code>n<\/code> to <code>i<\/code>), and then returns the modified value of <code>i<\/code>.<\/p>\n<p>This is just the identity function, but it calculates the result with the help of an inner function.<\/p>\n<p>The way this works is that the <code>Inner<\/code> function receives a hidden parameter that tells it where the <code>Outer<\/code> procedure&#8217;s local variables are.<\/p>\n<p>In practice, what is passed is a pointer to the <code>Outer<\/code> procedure&#8217;s stack frame.<\/p>\n<p>Now, if the containing function or precedure happens itself to be nested, then you can use the parent&#8217;s frame to access the local variables of the grandparent.<\/p>\n<pre>function Outer(n: integer) : integer;\r\n    var i: integer;\r\n\r\n    procedure Inner(m: integer);\r\n\r\n        <span style=\"border: solid 1px currentcolor; border-bottom: none;\">procedure MoreInner<\/span>\r\n        <span style=\"border: 1px currentcolor; border-style: none solid;\">begin\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span>\r\n        <span style=\"border: 1px currentcolor; border-style: none solid;\"> \u00a0\u00a0\u00a0i := i + m\u00a0\u00a0\u00a0\u00a0 <\/span>\r\n        <span style=\"border: solid 1px currentcolor; border-top: none;\">end\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span>\r\n    begin\r\n        MoreInner\r\n    end;\r\n\r\n(* Outer body begins here *)\r\nbegin\r\n    i := 0;\r\n    Inner(n);\r\n    Outer := i\r\nend;\r\n<\/pre>\n<p>In this case, the <code>MoreInner<\/code> receives a hidden pointer to <code>Inner<\/code>&#8216;s stack frame, which lets it access the <code>m<\/code> parameter from <code>Inner<\/code>. But <code>Inner<\/code> is itself a nested procedure and therefore received a pointer to <code>Outer<\/code>&#8216;s stack frame. Therefore, <code>MoreInner<\/code> can use that pointer to access <code>Outer<\/code>&#8216;s local variable <code>i<\/code>.<\/p>\n<p>Here&#8217;s what it looks like in a diagram:<\/p>\n<div id=\"p20231204_head\" style=\"display: none;\">\u00a0<\/div>\n<div id=\"p20231204_defs\" style=\"height: 0;\">\u00a0<\/div>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" title=\"A frame for the MoreInner procedure holds only a chain pointer which points to the frame for the Inner procedure. The frame for the Inner procedure holds the variable m and has a chain pointer which points to the frame for the Outer procedure. The frame for the Outer procedure holds the variables n and i.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>MoreInner<\/td>\n<td>&nbsp;<\/td>\n<td>Inner<\/td>\n<td>&nbsp;<\/td>\n<td>Outer<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">chain<\/td>\n<td>\u279d<\/td>\n<td style=\"border: solid 1px currentcolor;\">chain<\/td>\n<td>\u279d<\/td>\n<td style=\"border: solid 1px currentcolor;\"><code>n<\/code><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\"><code>m<\/code><\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\"><code>i<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This is called a <i>static<\/i> chain because the structure of the chain is based on lexical scoping, not dynamic scoping. You can see the difference in this example:<\/p>\n<pre>function Outer(n: integer) : integer;\r\n    var i: integer;\r\n\r\n    procedure Update(j: integer);\r\n    begin\r\n        i := i + j\r\n    end;\r\n\r\n    procedure Inner(m: integer);\r\n\r\n        procedure MoreInner;\r\n        begin\r\n            Update(m)\r\n        end;\r\n\r\n    (* Inner body begins here *)\r\n    begin\r\n        MoreInner\r\n    end;\r\n\r\n(* Outer body begins here *)\r\nbegin\r\n    i := 0;\r\n    Inner(n);\r\n    Outer := i\r\nend;\r\n<\/pre>\n<p>This version is even more useless than the previous one: <code>MoreInner<\/code> doesn&#8217;t update <code>i<\/code> directly, but instead asks <code>Update<\/code> (an uncle procedure) to do it.<\/p>\n<p>At the point that <code>MoreInner<\/code> calls <code>Update<\/code>, it does not pass its own stack frame as the static chain pointer. Instead, it passes <code>Outer<\/code>&#8216;s stack frame, because <code>Update<\/code>&#8216;s parent is <code>Outer<\/code>.<\/p>\n<p>The static chain does not match the dynamic call stack: The call stack says that <code>Update<\/code>&#8216;s caller is <code>MoreInner<\/code> but the static chain says that <code>Update<\/code>&#8216;s parent is <code>Outer<\/code>.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" title=\"A linked list of frames for Update, MoreInner, Inner, and Outer. The chain pointers in each frame do not match the frame pointers. Update's chain pointer points to Outer, bypassing MoreInner and Inner. MoreInner's chain pointer points to the frame for Inner, whose chain pointer points to the frame for Outer.\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>Update<\/td>\n<td>&nbsp;<\/td>\n<td>MoreInner<\/td>\n<td>&nbsp;<\/td>\n<td>Inner<\/td>\n<td>&nbsp;<\/td>\n<td>Outer<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">frame pointer<\/td>\n<td>\u279d<\/td>\n<td style=\"border: solid 1px currentcolor;\">frame pointer<\/td>\n<td>\u279d<\/td>\n<td style=\"border: solid 1px currentcolor;\">frame pointer<\/td>\n<td>\u279d<\/td>\n<td style=\"border: solid 1px currentcolor;\">frame pointer<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\">chain<\/td>\n<td id=\"p20231204_rarr5\" colspan=\"5\">\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d\u279d<\/td>\n<td style=\"border: solid 1px currentcolor;\"><code>n<\/code><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\">chain<\/td>\n<td>\u279d<\/td>\n<td style=\"border: solid 1px currentcolor;\">chain<\/td>\n<td style=\"position: relative;\"><span style=\"position: relative; top: -.5em;\">\u2b67<\/span><\/td>\n<td style=\"border: solid 1px currentcolor;\"><code>i<\/code><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\"><code>m<\/code><\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The authors of the Application Binary Interface document assume you are familiar with how nested functions are implemented and are just noting that the calling convention for nested functions is to pass the static chain in the <code>%r10<\/code> register.<\/p>\n<p><script>\nwindow.addEventListener(\"load\", function() {\n  var fullFF = getComputedStyle(document.body).fontFamily;\n  var simpleFF = fullFF.replace(\/ Emoji\/g, \"\");\n  \/\/ break up \"style\" to prevent wordpress from injecting random junk\n  document.getElementById(\"p20240530_head\").innerHTML =\n`<s` + `tyle>\nbody { font-family: ${simpleFF}; }\n.emoji { font-family: ${fullFF}; }\n.entry-content th { padding: 1px; } \/* stylesheet workaround *\/\n.entry-content td { padding: 1px; } \/* stylesheet workaround *\/\n<\/s` + `tyle>`;\n}); \/\/ wacky comment to prevent wordpress from injecting random junk\n(function() {\n  var svg = {\n    defs: `<svg width=\"0\" height=\"0\">\n <defs>\n  <marker id=\"arrowhead\" markerWidth=\"5\" markerHeight=\"5\" refX=\"-2\" refY=\"0\"\n    viewBox=\"-6 -6 12 12\" orient=\"auto\">\n    <polygon points=\"-2,0 -5,5 5,0 -5,-5\" fill=\"currentcolor\" stroke=\"currentcolor\"\n      stroke-dasharray=\"1 0\" \/>\n  <\/marker>\n  <path id=\"rarr5\" d=\"M3,10 L295,10\" stroke=\"currentcolor\"\n   marker-end=\"url(#arrowhead)\" \/>\n <\/defs>\n<\/svg>`,\n    rarr5: `<svg width=\"300\" height=\"20\"><use href=\"#rarr5\"\/><\/svg>`\n  };\n  Object.keys(svg).forEach(function (key) {\n    Array.prototype.forEach.call(document.querySelectorAll(\"#p20231204_\" + key),\n      function (e) {\n        e.innerHTML = svg[key];\n      });\n  });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Buried in the System V Application Binary Interface.<\/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-109095","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Buried in the System V Application Binary Interface.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109095","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=109095"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109095\/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=109095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}