{"id":106144,"date":"2022-01-11T07:00:00","date_gmt":"2022-01-11T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106144"},"modified":"2022-01-11T06:26:58","modified_gmt":"2022-01-11T14:26:58","slug":"20220111-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220111-00\/?p=106144","title":{"rendered":"Jumping into the middle of an instruction is not as strange as it sounds"},"content":{"rendered":"<p>Reuben Harris and Monte Davidoff spent time <a href=\"http:\/\/altairbasic.org\/\"> disassembling Bill Gates&#8217;s original Altair BASIC<\/a>. In an interview with <i>The Register<\/i>, Harris was impressed with the code, noting with some admiration, &#8220;<a href=\"https:\/\/www.theregister.com\/2001\/05\/15\/could_bill_gates_write_code\/\">I found a jump instruction that jumped to the middle of another instruction<\/a>.&#8221;\u00b9<\/p>\n<p>You can find the targets of those jumps <a href=\"http:\/\/altairbasic.org\/int_dis_4.htm\"> in the error handling code<\/a>: Search for &#8220;Three common errors.&#8221;<\/p>\n<p>The trick here is that the 8080 uses variable-length instructions. The instruction sequence in question goes like this:<\/p>\n<pre>01CD    1E0C    OutOfMemory:    MVI E,0C\r\n01CF    01                      LXI B,....\r\n\r\n01D0    1E02    SyntaxError:    MVI E,02\r\n01D2    01                      LXI B,....\r\n\r\n01D3    1E14    DivideByZero:   MVI E,14\r\n<\/pre>\n<p>The 8080 processor has 8-bit registers named <code>A<\/code>, <code>B<\/code>, <code>C<\/code>, <code>D<\/code>, <code>E<\/code>, <code>H<\/code>, and <code>L<\/code>. Six of these registers can be paired up to create 16-bit pseudo-registers: <code>BC<\/code>, <code>DE<\/code> and <code>HL<\/code>.<\/p>\n<p>The <i>load extended immediate<\/i> <code>LXI<\/code> instruction is a three-byte instruction which loads a 16-bit immediate value into a register pair. The first byte specifies the opcode and the destination register pair (in the above example, the <code>BC<\/code> register pair), and the second and third bytes form the 16-bit immediate.<\/p>\n<p>The <i>move immediate<\/i> <code>MVI<\/code> instruction is a two-byte instruction which loads an 8-bit immediate value into a single 8-bit register. The first byte specifies the opcode and the destination register (in the above example, the <code>E<\/code> register), and the second byte is the 8-bit immediate.<\/p>\n<p>Let&#8217;s write out the byte stream that results from jumping to the three labels:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>Address<\/td>\n<td>Code byte<\/td>\n<td><code>JMP<br \/>\nOutOfMemory<\/code><\/td>\n<td><code>JMP<br \/>\nSyntaxError<\/code><\/td>\n<td><code>JMP<br \/>\nDivideByZero<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01CD<\/code><\/td>\n<td><code>1E<\/code><\/td>\n<td style=\"border: solid black 1px;\" rowspan=\"2\" valign=\"middle\"><code>MVI E,0C<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01CE<\/code><\/td>\n<td><code>0C<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01CF<\/code><\/td>\n<td><code>01<\/code><\/td>\n<td style=\"border: solid black 1px;\" rowspan=\"3\" valign=\"middle\"><code>LXI B,021E<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01D0<\/code><\/td>\n<td><code>1E<\/code><\/td>\n<td style=\"border: solid black 1px;\" rowspan=\"2\" valign=\"middle\"><code>MVI E,02<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01D1<\/code><\/td>\n<td><code>02<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01D2<\/code><\/td>\n<td><code>01<\/code><\/td>\n<td style=\"border: solid black 1px;\" rowspan=\"3\" valign=\"middle\"><code>LXI B,141E<\/code><\/td>\n<td style=\"border: solid black 1px;\" rowspan=\"3\" valign=\"middle\"><code>LXI B,141E<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01D3<\/code><\/td>\n<td><code>1E<\/code><\/td>\n<td style=\"border: solid black 1px;\" rowspan=\"2\" valign=\"middle\"><code>MVI E,14<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>01D4<\/code><\/td>\n<td><code>14<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If you jump to <code>01CD<\/code>, then the CPU performs a <code>MVI E,0C<\/code>, and then it interprets the <code>01<\/code> as the start of an <code>LXI B<\/code> instruction, and the next two bytes are treated as the 16-bit immediate operand. On the other hand, if you jump to <code>01D0<\/code>, then the bytes that used to be the 16-bit immediate operand of the <code>LXI B<\/code> instruction are now treated as an <code>MVI E,02<\/code> instruction.<\/p>\n<p>You see the same thing happen at <code>01D3<\/code>, which hides a two-byte instruction inside the 16-bit immediate operand of another <code>LXI B<\/code> instruction. If instruction falls through from above, then the CPU executes an <code>LXI B,141E<\/code>, but if you jump directly to <code>1D3<\/code>, then the CPU executes a <code>MVI E,14<\/code>.<\/p>\n<p>In both cases, the <code>LXI B<\/code> is just a garbage instruction. It loads some nonsense value into the <code>BC<\/code> register pair. The code doesn&#8217;t care; that register wasn&#8217;t holding anything useful anyway. The purpose of the instruction is to soak up the next two bytes and prevent them from being treated as another instruction.<\/p>\n<p>Harris expressed some surprise at finding this, but really, it is a pretty common trick when hand-writing assembly for processors with variable-length instructions: If you want to hide a 1-byte instruction, look for another instruction with a 1-byte immediate, and hide the instruction in the immediate. If you want to hide a 2-byte instruction, hide it inside an instruction with a 2-byte immediate.<\/p>\n<p>The &#8220;cloaking&#8221; instruction should do something harmless. Instructions like &#8220;compare with immediate&#8221; work great, since they typically affect only flags, and most of the time, there&#8217;s nothing interesting in the flags anyway. However, the 8080 does not have a &#8220;compare with 16-bit immediate&#8221; instruction, so we have to make do with &#8220;load 16-bit immediate&#8221; into a register we don&#8217;t care about.<\/p>\n<p>On the 6502, the typical instruction for soaking up one or two bytes is the <i>bit test<\/i> <code>BIT<\/code> instruction. The argument is the address of the memory to test (either a 1-byte zero page address or a 2-byte absolute address), and the rest of the test goes into the flags register. Executing a garbage <code>BIT<\/code> instruction therefore reads a byte from some garbage memory location and then sets flags according to the value read. If the flags are subsequently ignored, then this is basically a three-byte <code>NOP<\/code>.<\/p>\n<p>Microsoft 6502 BASIC had <a href=\"https:\/\/www.pagetable.com\/?p=774\"> a special macro <code>SKIP2<\/code><\/a> for generating the first byte of the <code>BIT<\/code> instruction.<\/p>\n<p>This hacky usage of the <code>BIT<\/code> instruction is arguably <a href=\"https:\/\/retrocomputing.stackexchange.com\/a\/11132\"> more popular than its designed purpose as a bit-testing instruction<\/a>!\u00b2 (Related: <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20041215-00\/?p=37003\"> The hunt for a faster syscall trap<\/a>.)<\/p>\n<p>One thing to watch out for is that the CPU does perform a load from the memory address that is the argument to the <code>BIT<\/code> instruction, so make sure that the two bytes, when reinterpreted as an address, don&#8217;t produce an address in an I\/O-mapped region. Otherwise, you&#8217;ll be issuing inadvertent hardware commands. (The 6502 has no memory manager, so you don&#8217;t have to worry about access violations.)<\/p>\n<p>The trick of &#8220;soaking up&#8221; bytes to generate multiple entry points to a function was employed in 16-bit Windows. For example, you had this sequence:<\/p>\n<pre>DelAtom:\r\n    mov     cl, 2\r\n    db      0BBh        ; mov bx, imm16\r\nAddAtom:\r\n    mov     cl, 1\r\n    db      0BBh        ; mov bx, imm16\r\nFindAtom:\r\n    mov     cl, 0\r\n    db      0BBh        ; mov bx, imm16\r\n<\/pre>\n<p>The three functions all have the same parameters, and they share a lot of code, so the entry points merely set up a function code in the <code>cl<\/code> register and all fall through to a common implementation.<\/p>\n<p>So, yeah, jumping into the middle of an instruction. It&#8217;s a cool trick, but it&#8217;s not novel. It was rather commonly employed in the early days of personal computing.<\/p>\n<p>\u00b9 For some reason, that quotation has made its way into online dictionaries as <a href=\"https:\/\/www.lexico.com\/definition\/jump_instruction\"> a citation for <i>jump instruction<\/i><\/a>.<\/p>\n<p>\u00b2 If you&#8217;ve done significant work on the 6502, the machine code for this instruction (<code>2C<\/code>) is probably burned into your brain.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s just another trick for saving space.<\/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-106144","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>It&#8217;s just another trick for saving space.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106144","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=106144"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106144\/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=106144"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106144"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106144"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}