{"id":109126,"date":"2023-12-11T07:00:00","date_gmt":"2023-12-11T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109126"},"modified":"2023-12-11T09:20:16","modified_gmt":"2023-12-11T17:20:16","slug":"20231211-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231211-00\/?p=109126","title":{"rendered":"The mysterious second parameter to the x86 <CODE>ENTER<\/CODE> instruction"},"content":{"rendered":"<p>The x86 instruction set has an <code>ENTER<\/code> instruction which builds a stack frame. It is almost always used with a zero as the second parameter.<\/p>\n<pre>        enter   n, 0\r\n<\/pre>\n<p>This is functionally equivalent to<\/p>\n<pre>        push    ebp\r\n        mov     ebp, esp\r\n        sub     esp, n\r\n<\/pre>\n<p>But what happens if you increase that second parameter beyond zero?<\/p>\n<p>Values greater than zero for the second parameter are intended for languages like Pascal which support nested functions that can access the local variables of their lexical parents. <a title=\"What is a static chain pointer in the context of calling convention ABI?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231204-00\/?p=109095\"> We learned about these functions a short time ago<\/a>. But the designers of the x86 instruction set had a different design in mind for how a function can access the variables of its lexical parent: Instead of receiving a pointer to the start of a linked list of lexical parent frames, they receive an <i>array<\/i> of pointers to lexical parent frames.<\/p>\n<p>In its full generality, the<\/p>\n<pre>    enter n, k + 1\r\n<\/pre>\n<p>instruction goes like this:<\/p>\n<div id=\"p20231211_head\" style=\"display: none;\">\u00a0<\/div>\n<pre>    push    ebp\r\n    mov     internal_register, esp\r\n   <span style=\"border: solid 1px currentcolor; border-bottom: none;\"> sub     ebp, 4 <\/span> \u23b1 <span style=\"position: relative; top: 1ex;\"><var>k<\/var> times<\/span>\r\n   <span style=\"border: solid 1px currentcolor; border-top: none;\"> push    [ebp]  <\/span> \u23b0\r\n    push    internal_register\r\n    mov     ebp, internal_register\r\n    sub     esp, n\r\n<\/pre>\n<p>If you ignore the order of operations and worry just about the final state, then you can reinterpret it like this, which I think captures the essence of the instruction better:<\/p>\n<pre>    push    ebp\r\n   <span style=\"border: solid 1px currentcolor; border-bottom: none;\"> push    [ebp-4]   <\/span>\r\n   <span style=\"border: 1px currentcolor; border-style: none solid;\"> push    [ebp-8]   <\/span> <span style=\"position: relative; top: 1ex;\"><var>k<\/var> pushes<\/span>\r\n   <span style=\"border: 1px currentcolor; border-style: none solid;\"> :                 <\/span>\r\n   <span style=\"border: solid 1px currentcolor; border-top: none;\"> push    [ebp-4*<var>k<\/var>] <\/span>\r\n    lea     ebp, [esp + 4*<var>k<\/var>]    ; where we pushed the previous ebp\r\n    push    ebp\t\t        ; add our own frame to the array\r\n    sub     esp, n\r\n<\/pre>\n<p>Let&#8217;s look at our example function again.<\/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>On entry to <code>Outer<\/code>, the stack looks like this:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>n<\/code> parameter<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor; text-align: center;\">return address<\/td>\n<td>\u2190 <var>esp<\/var><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The <code>Outer<\/code> function establishes its stack frame by performing an <code>enter 4, 1<\/code>. The extra <code>1<\/code> at the end means that this is the outermost of a chain of nested functions. In our cookbook, <var>k<\/var> is zero, so the functional equivalent is<\/p>\n<pre>    push    ebp\r\n                                ; no pointers copied from parent\r\n    lea     ebp, [esp+0]        ; equivalently, \"mov ebp, esp\"\r\n    push    ebp                 ; pointer to our own frame\r\n    sub     esp, 4\r\n<\/pre>\n<p>and we wind up with this stack frame for <code>Outer<\/code>:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"text-align: center;\"><code>Outer<\/code> frame<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>n<\/code> parameter<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\">return address<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<td rowspan=\"2\">\u2190 <var>ebp<\/var><\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>i<\/code><\/td>\n<td>\u2190 <var>esp<\/var><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>That extra <code>,1<\/code> caused us to push the address of where we saved the previous <code>ebp<\/code>, which I&#8217;ve called the <code>Outer<\/code> frame pointer. That value isn&#8217;t really useful to us right now, since we already have that value in the <var>ebp<\/var> register. But it comes in handy when we call <code>Inner<\/code>.<\/p>\n<p>On entry to <code>Inner<\/code>, the stack looks like this:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>m<\/code> parameter<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\">return address<\/td>\n<td>\u2190 <var>esp<\/var><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The <code>Inner<\/code> function performs an <code>enter 0, 2<\/code>. The 0 means that <code>Inner<\/code> has no local variables, and the <code>2<\/code> means that we are now the second level in a chain of nested functions.<\/p>\n<p>The functional equivalent now has one extra memory push before we push a pointer to our own frame:<\/p>\n<pre>    push    ebp\r\n   <span style=\"border: solid 1px currentcolor;\"> push    [ebp-4]  <\/span>           ; one pointer copied from parent\r\n    lea     ebp, [esp+4]\r\n    push    ebp                 ; pointer to our own frame\r\n    sub     esp, 4\r\n<\/pre>\n<p>Before pushing the address of its own frame, the <code>enter<\/code> instruction also copies one pointer from the parent&#8217;s frame, namely the <code>Outer<\/code> frame pointer.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"text-align: center;\"><code>Inner<\/code> frame<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>m<\/code> parameter<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"text-align: center;\"><code>Outer<\/code> frame<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\">return address<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>n<\/code> parameter<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<td rowspan=\"2\">\u2190 <var>ebp<\/var><\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">return address<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<td style=\"border-bottom: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Inner<\/code> frame pointer<\/td>\n<td rowspan=\"2\">\u2190 <var>esp<\/var><\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>i<\/code><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Now things are interesting.<\/p>\n<p>The <code>Inner<\/code> function has access to its own frame, via the <var>ebp<\/var> register (and redundantly via the <code>Inner<\/code> frame pointer on its stack). It also has access to the <code>Outer<\/code> frame through its local copy of the <code>Outer<\/code> frame pointer.<\/p>\n<p>The next thing that happens is that <code>Inner<\/code> calls <code>More\u00adInner<\/code> with no parameters. This time <code>More\u00adInner<\/code> uses <code>enter 0, 3<\/code> where the 0 means that <code>More\u00adInner<\/code> has no local variables, and the <code>3<\/code> means that it is a nested function three levels deep, so it should copy <i>two<\/i> frame pointers from its parent.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"text-align: center;\"><code>MoreInner<\/code> frame<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\">return address<\/td>\n<td style=\"border-right: solid 1px currentcolor;\">\u00a0<\/td>\n<td style=\"border-top: solid 1px currentcolor;\">\u00a0<\/td>\n<td style=\"border-top: solid 1px currentcolor;\">\u00a0<\/td>\n<td style=\"border-top: solid 1px currentcolor; text-align: center;\"><code>Inner<\/code> frame<\/td>\n<td style=\"border-top: solid 1px currentcolor;\">\u00a0<\/td>\n<td style=\"border-left: 1px currentcolor solid;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<td style=\"border-right: solid 1px currentcolor;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>m<\/code> parameter<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border-left: solid 1px currentcolor;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: 1px currentcolor solid;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">return address<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border-left: solid 1px currentcolor;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>n<\/code> parameter<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px currentcolor; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Inner<\/code> frame pointer<\/td>\n<td style=\"border-bottom: solid 1px currentcolor; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border-left: solid 1px currentcolor;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">return address<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px currentcolor; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>MoreInner<\/code> frame pointer<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border-left: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<td style=\"border: 1px currentcolor; border-style: none solid solid none; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border-left: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Inner<\/code> frame pointer<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><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>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The frame for <code>MoreInner<\/code> contains its own parameters and local variables (nothing), plus pointers to both parent frames, plus a pointer to its own frame (which <code>More\u00adInner<\/code> doesn&#8217;t use, but which is ready for any nested function to use).<\/p>\n<p>The code generation for <code>MoreInner<\/code> therefore reads the value of <code>m<\/code> by following the <code>Inner<\/code> frame pointer and then reading the <code>m<\/code> parameter from the <code>Inner<\/code> frame&#8217;s parameter space.<\/p>\n<p>After <code>More\u00adInner<\/code> calls <code>Update<\/code>, the <code>Update<\/code> function starts with an <code>enter 0, 2<\/code> because it is a level-2 nested function. This copies only the <code>Outer<\/code> frame pointer to <code>Update<\/code>&#8216;s frame, resulting in this:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"text-align: center;\"><code>Update<\/code> frame<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>j<\/code> parameter<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"text-align: center;\"><code>Outer<\/code> frame<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\">return address<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>n<\/code> parameter<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<td rowspan=\"2\">\u2190 <var>ebp<\/var><\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">return address<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<td style=\"border-bottom: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u25b6\ufe0e<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\">previous <var>ebp<\/var><\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: 1px currentcolor solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: 1px currentcolor; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Update<\/code> frame pointer<\/td>\n<td rowspan=\"2\">\u2190 <var>esp<\/var><\/td>\n<td style=\"border: 1px currentcolor; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\" rowspan=\"2\"><code>Outer<\/code> frame pointer<\/td>\n<\/tr>\n<tr>\n<td style=\"line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; text-align: center;\"><code>i<\/code><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>I didn&#8217;t draw it, but the &#8220;previous <var>ebp<\/var>&#8221; in the <code>Update<\/code> frame points to the <code>More\u00adInner<\/code> frame.<\/p>\n<p>The <code>Update<\/code> function reads <code>j<\/code> from its own parameter space and uses to update the <code>i<\/code> variable in <code>Outer<\/code>&#8216;s frame by following the <code>Outer<\/code> frame pointer.<\/p>\n<p>The result is the same as the <a title=\"What is a static chain pointer in the context of calling convention ABI?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20231204-00\/?p=109095\"> System V Application Binary Interface static chain pointer<\/a>, but it&#8217;s done in a different way. Instead of passing the head of a linked list of frames, the <code>enter<\/code> instruction copies an entire array of pointers to frames. This reduces the number of instructions required in order to access faraway frames, but it increases the cost of a function call due to the extra copying.<\/p>\n<p>I wonder if anybody uses the Intel design for nested functions. I suspect it&#8217;s silicon on the CPU that is completely wasted.<\/p>\n<p>\n<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(\"p20231211_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});\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>For an ABI that probably nobody uses.<\/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-109126","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>For an ABI that probably nobody uses.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109126","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=109126"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109126\/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=109126"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109126"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109126"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}