{"id":98505,"date":"2018-04-13T07:00:00","date_gmt":"2018-04-13T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=98505"},"modified":"2019-03-13T00:45:54","modified_gmt":"2019-03-13T07:45:54","slug":"20180413-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180413-00\/?p=98505","title":{"rendered":"The MIPS R4000, part 10: Trampolines and stubs"},"content":{"rendered":"<p>We saw earlier that the relative branch instructions have a reach of &plusmn;128<a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20090611-00\/?p=17933\">KB<\/a>, but what if the function you want to call is further away than that? <\/p>\n<p>The linker detects that the branch target is too far away and creates a trampoline stub, the same way <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20170807-00\/?p=96766\">the Alpha AXP compiler did<\/a>. The branch instruction is then rewritten to be a branch to the trampoline, and the trampoline performs another jump to the final destination. <\/p>\n<pre>\n    BAL     dest_trampoline ; was \"BAL dest\"\n...\ndest_trampoline:\n    J       dest\n    NOP                     ; branch delay slot\n<\/pre>\n<p>The limited reach of the relative branch instructions means that a single function cannot be larger than 256KB. <\/p>\n<p>On the other hand, the existence of the <code>JAL<\/code> instruction means that the compiler doesn&#8217;t really need to use <code>BAL<\/code> at all. Trampolines come into play only with conditional calls, and those are relatively rare. <\/p>\n<p>If a function is <a HREF=\"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20060721-06\/?p=30433\">na&iuml;vely-imported<\/a>, then the compiler will generate a normal branch-and-link instruction, and the import library will provide a stub that in turn jumps indirectly through the import table. Doing this requires a scratch register, and that&#8217;s where the <var>at<\/var> register once again enters the picture: <\/p>\n<pre>\n    BAL     imported_function_stub\n...\n\nimported_function_stub:\n    LUI     at, XXXX\n    LW      at, YYYY(at)    ; load from import address table\n    JR      at              ; and jump there\n    NOP                     ; branch delay slot\n<\/pre>\n<p>Where <code>XXXX<\/code> and <code>YYYY<\/code> are computed in the usual way, namely, so that <code>(XXXX &lt;&lt; 16) + (int16_t)YYYY<\/code> is the address of the import address table entry. <\/p>\n<p>If you are unlucky enough that you are calling an imported function na&iuml;vely, <i>and<\/i> the imported stub is beyond the reach of the <code>BAL<\/code> instruction, then you will have to bounce through two trampolines! The first was generated by the linker to help you reach the stub, and the second came from the import library to get you from the stub to the final destination. <\/p>\n<p>This double-trampoline could also happen on the Alpha AXP, but it was less common because the Alpha AXP&#8217;s relative branch instructions have a reach of &plusmn;4MB, as opposed to the MIPS R4000&#8217;s relative branch instructions, which can reach only &plusmn;128KB. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>You can&#8217;t get there from here, at least not in one go.<\/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-98505","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>You can&#8217;t get there from here, at least not in one go.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98505","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=98505"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/98505\/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=98505"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=98505"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=98505"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}