{"id":110595,"date":"2024-12-02T07:00:00","date_gmt":"2024-12-02T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110595"},"modified":"2024-12-01T20:29:15","modified_gmt":"2024-12-02T04:29:15","slug":"20241202-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241202-00\/?p=110595","title":{"rendered":"An analogy about register preservation rules in calling conventions"},"content":{"rendered":"<p>A common problem beginning programmers have with assembly language is understanding calling conventions and register preservation rules, because those are not rules imposed by the architecture, but are rather created by convention.<\/p>\n<p>Imagine that you are an instructor at a university. In the United States, classrooms are typically not dedicated to a single class or a single instructor, but rather, classes and instructors are assigned to rooms on a case-by-case basis, and it is common for instructors to have to teach classes in multiple rooms.<\/p>\n<p>The convention at the school might be that the instructor is free to use the chalkboard however they like, and they are allowed to erase any content left on the chalkboard when they arrive for the start of class, with no responsibility to return the chalkboard to its original state when the class ends.<\/p>\n<p>On the other hand, the convention is that the desks and chairs in the classroom must be returned to their original places at the end of class. The instructor is permitted to move the desks and chairs during class, but they have to put them back in the original locations when the class is over.<\/p>\n<p>The chalkboard is like the registers we call &#8220;scratch&#8221; or &#8220;volatile&#8221;: You are welcome to use them all you want, and you are not under any obligation to restore them to their original values when you are done.<\/p>\n<p>The desks and chairs are like the registers we call &#8220;preserved&#8221; or &#8220;non-volatile&#8221;: You are welcome to use them all you want, but you are required to put them &#8220;back where you found them&#8221; when you are done. This is typically done by saving their initial state somewhere when you start (for desks and chairs, maybe by marking their locations with tape on the floor; for registers, by saving their values to memory) and restoring them at before you finish (moving the desks and chairs back to the markers; for registers, reloading the values from memory).<\/p>\n<p>There might be some fixtures in the classroom that may not be moved at all. You cannot unscrew the light bulbs or disable the fire alarm. These are &#8220;immutable&#8221; registers, which you aren&#8217;t allowed to modify, not even temporarily.<\/p>\n<p>Now, maybe your class is a lab class that has been given a dedicated room for an entire week, so you don&#8217;t have to reset the room after each session and can instead just resume from where the previous session left off. But you don&#8217;t have class on Wednesday, so for Wednesday, another class uses the room. What can you expect?<\/p>\n<p>Well, the conventions say that the chalkboard is available for use. So don&#8217;t leave anything important on the chalkboard at the end of the Tuesday class, because it will be gone when you come back on Thursday.<\/p>\n<p>On the other hand, the conventions also say that the desks should be returned to their original locations, so the desk clumps you created for your lab class will still be there. The desks may very well be moved around by the Wednesday class, but they will return them to the original positions before they are done.<\/p>\n<p>Now, the school may have other conventions regarding the classroom. For example, maybe in addition to the convention that says that you have to restore the desks to their original locations, they also say that if you do move any desks, you have to take a photo of the classroom to show the original desk positions, and you have to post the photo on the bulletin board next to the door (and take it away when your class is over). The school requires this because your class might be cancelled after the Thursday session, so you won&#8217;t be around on Friday to reset the desks. The facilities staff needs to use that photo you took in order to restore the desks to their original positions for the class that had the room before you.<\/p>\n<p>When people write code in assembly language, they often forget about the conventions about taking photos of things before you move them because those photos (<a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/build\/exception-handling-x64?view=msvc-170\">unwind codes<\/a>) are not explicitly in the code itself, but are instead stored in another part of the executable, to be consulted only in the (hopefully rare) case that the system needs to <a title=\"Microspeak: to reason over\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170307-00\/?p=95675\"> reason over<\/a> the stacks of active threads. This primarily happens during exception handling.\u00b9 But since the unwind codes are not immediately visible, people usually forget that they need them.<\/p>\n<p><b>Related reading<\/b>: <a title=\"Zero-cost exceptions aren't actually zero cost\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220228-00\/?p=106296\"> Zero-cost exceptions aren&#8217;t actually zero cost<\/a>.<\/p>\n<p>\u00b9 You might say, &#8220;But my code doesn&#8217;t throw exceptions, why do I need to worry about exception handling?&#8221; The system internally uses exceptions for normal everyday activities. For example, <a title=\"A closer look at the stack guard page\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220203-00\/?p=106215\"> guard page exceptions<\/a> are used to indicate that the stack needs to grow. Also, debug messages like those generated by <code>Output\u00adDebug\u00adString<\/code> are communicated by raising an exception and immediately catching it, with the expectation that if a debugger is connected, it will intercept and handle the exception.<\/p>\n<p>If you fail to declare unwind codes for your function, the system assumes that you are a lightweight leaf function. This means that all nonvolatile registers and the stack pointer are unchanged from their function entry, and that the return address is in its default location (on the top of the stack for x86 family systems, in the link register for branch-and-link architectures). If you don&#8217;t follow the rules for a lightweight leaf function (for example, if you push registers onto the stack), then the lightweight leaf function unwinding produces invalid values, and if you&#8217;re lucky, the systems terminates your process immediately for having a corrupted stack. If you&#8217;re unlucky, the system unwinds the stack incorrectly, and a function higher up the stack runs with corrupted registers and behaves unpredictably. This is not just bad for your program (which no longer operates predictably), but also bad for your users (because an attacker might induce a stack unwind and control enough of the unintended execution to gain remote code execution).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>And tying it back to unwind codes.<\/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-110595","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>And tying it back to unwind codes.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110595","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=110595"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110595\/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=110595"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110595"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110595"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}