{"id":107050,"date":"2022-08-25T07:00:00","date_gmt":"2022-08-25T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107050"},"modified":"2022-11-29T09:32:45","modified_gmt":"2022-11-29T17:32:45","slug":"20220825-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220825-00\/?p=107050","title":{"rendered":"The AArch64 processor (aka arm64), part 22: Other kinds of classic prologues and epilogues"},"content":{"rendered":"<p>Last time, we looked at traditional classic function prologues in Windows on AArch64. But there are variations.<\/p>\n<p>For variadic functions, there is a small adjustment to the traditional prologue: The top of the register save area contains spill space for the variadic register parameters. The variadic register parameters are at the top so that they nestle directly against the stack-based parameters, so that the entire variadic parameter list can be accessed uniformly in memory.<\/p>\n<p>For example, a function whose prototype is<\/p>\n<pre>int something(int a, int b, ...);\r\n<\/pre>\n<p>could have a prologue that goes something like<\/p>\n<div id=\"p20220825_head\" style=\"display: none;\">\u00a0<\/div>\n<pre>    ; return address protection\r\n    pacibsp\r\n\r\n    ; saving registers + variadic parameters\r\n    stp     fp, lr, [sp, #-0x50]!\r\n    str     x19, [sp, #0x10]\r\n    stp     x2, x3, [sp, #0x20]     ; variadic registers go here\r\n    stp     x4, x5, [sp, #0x30]     ; variadic registers go here\r\n    stp     x6, x7, [sp, #0x40]     ; variadic registers go here\r\n\r\n    ; establishing frame chain\r\n    mov     fp, sp\r\n\r\n    ; initializing <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/build\/reference\/gs-buffer-security-check\">GS cookie<\/a>\r\n    bl      __security_push_cookie\r\n\r\n    ; local variables and outbound parameters\r\n    sub     sp, sp, #0x80\r\n<\/pre>\n<p>for a combined stack layout of<\/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 gray; border-top: none; text-align: center;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td rowspan=\"6\">\u00a0<\/td>\n<td rowspan=\"6\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; 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 gray; text-align: center;\" rowspan=\"2\">previous <var>fp<\/var><\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: solid none none solid; line-height: 50%;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\">\u22ee<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\">stack param<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\"><var>r7<\/var> param<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; border-left: none;\" rowspan=\"11\">\u00a0<\/td>\n<td rowspan=\"11\" valign=\"center\">saved<br \/>\nregister<br \/>\narea<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\"><var>r6<\/var> param<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\"><var>r5<\/var> param<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\"><var>r4<\/var> param<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\"><var>r3<\/var> param<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\"><var>r2<\/var> param<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\">saved <var>x19<\/var><\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border-left: solid 1px gray;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\">return address<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: 1px gray; border-style: none none solid solid; line-height: 50%;\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\" rowspan=\"2\">previous <var>fp<\/var><\/td>\n<td rowspan=\"2\">\u2190 <var>fp<\/var> (frame chain)<\/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 gray; text-align: center;\">\u00a0<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; border-left: none;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\" valign=\"center\">GS<br \/>\narea<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center;\">GS cookie<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center; height: 4em;\">local<br \/>\nvariables<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; border-left: none;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\" valign=\"center\">local<br \/>\nstack<br \/>\narea<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center; height: 4em;\">outbound<br \/>\nstack<br \/>\nparameters<\/td>\n<td valign=\"bottom\">\u2190 <var>sp<\/var><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>There is no change to the epilogue because variadic inbound register parameters don&#8217;t need to be preserved across the call.<\/p>\n<p>Another type of function that has a different prologue and epilogue is the lightweight leaf function. This is a function that does not catch any exceptions, does not use any stack (beyond the stack space provided by inbound stack-based parameters), and does not modify any nonvolatile registers. These functions do not need to set up a stack frame or declare exception unwind codes. Conversely, the operating system assumes that any function that lacks exception unwind codes is a lightweight leaf function.\u00b9 If the operating system needs to unwind an exception that occurs in a lightweight leaf function, it just unwinds to the address held in the <var>lr<\/var> register without updating any registers.<\/p>\n<p>A third category of function is the shrink-wrapped function. This function starts out with a minimal stack frame (possibly none, posing as a lightweight leaf function), but conditionally optionally expands to a full stack frame. This is typically used for functions that have a fast early-exit.<\/p>\n<p>And of course, for any of these functions, the <code>RET<\/code> could turn into a <code>B<\/code> or <code>BR<\/code> if a tail call optimization is in effect. Since the calling convention is caller-clean with many register-based parameters, tail call optimization doesn&#8217;t require the tail-called function to have an identical signature as the calling function. The tail call is in play as long as the tail-called function&#8217;s stack parameter size is less than or equal to the stack parameter size of the calling function.<\/p>\n<p>Okay, so that&#8217;s the prologue and epilogue. Next time, we&#8217;ll look at some code patterns you&#8217;ll see in the function body itself.<\/p>\n<p>\u00b9 This clause always catches out people who are trying to write Windows programs in assembly language. If you fail to declare unwind codes, then the operating system assumes you are a lightweight leaf function: It assumes that the return address is in the <var>lr<\/var> register, and it will continue stack walking at whatever address happens to be in that register, with whatever stack happens to be active, and with whatever values happen to be in the nonvolatile registers. This prevents the exception handlers installed by outer frames from running, or at least from running correctly. If you&#8217;re lucky, the program is declared &#8220;corrupted, possible malware&#8221; by the kernel when it notices that the frame chain is nonsense. If you&#8217;re not lucky, the handler is called with invalid registers and an invalid stack, and things spiral out of control. And if you&#8217;re super-unlucky, an attacker may be able to use this for a remote code execution attack.<\/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(\"p20220825_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>Taking shortcuts, or maybe adding steps.<\/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":[2],"class_list":["post-107050","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Taking shortcuts, or maybe adding steps.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107050","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=107050"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107050\/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=107050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107050"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}