//: instructions that (immediately) contain an argument to act with :(before "End Initialize Op Names") put_new(Name, "05", "add imm32 to EAX (add)"); :(before "End Single-Byte Opcodes") case 0x05: { // add imm32 to EAX int32_t signed_arg2 = next32(); trace(Callstack_depth+1, "run") << "add imm32 0x" << HEXWORD << signed_arg2 << " to EAX" << end(); int32_t signed_result = Reg[EAX].i + signed_arg2; SF = (signed_result < 0); ZF = (signed_result == 0); int64_t signed_full_result = static_cast(Reg[EAX].i) + signed_arg2; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg2 = static_cast(signed_arg2); uint32_t unsigned_result = Reg[EAX].u + unsigned_arg2; uint64_t unsigned_full_result = static_cast(Reg[EAX].u) + unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); Reg[EAX].i = signed_result; trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); break; } :(code) void test_add_imm32_to_EAX_signed_overflow() { Reg[EAX].i = INT32_MAX; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 05 01 00 00 00 \n" // add 1 to EAX ); CHECK_TRACE_CONTENTS( "run: add imm32 0x00000001 to EAX\n" "run: SF=1; ZF=0; CF=0; OF=1\n" "run: storing 0x80000000\n" ); } void test_add_imm32_to_EAX_unsigned_overflow() { Reg[EAX].u = UINT32_MAX; Reg[EBX].u = 1; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 05 01 00 00 00 \n" // add 1 to EAX ); CHECK_TRACE_CONTENTS( "run: add imm32 0x00000001 to EAX\n" "run: SF=0; ZF=1; CF=1; OF=0\n" "run: storing 0x00000000\n" ); } void test_add_imm32_to_EAX_unsigned_and_signed_overflow() { Reg[EAX].i = INT32_MIN; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 05 00 00 00 80 \n" // add 0x80000000 to EAX ); CHECK_TRACE_CONTENTS( "run: add imm32 0x80000000 to EAX\n" "run: SF=0; ZF=1; CF=1; OF=1\n" "run: storing 0x00000000\n" ); } //: :(before "End Initialize Op Names") put_new(Name, "81", "combine rm32 with imm32 based on subop (add/sub/and/or/xor/cmp)"); :(code) void test_add_imm32_to_r32() { Reg[EBX].i = 1; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 0a 0b 0c 0d\n" // add 0x0d0c0b0a to EBX // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x0d0c0b0a\n" "run: subop add\n" "run: storing 0x0d0c0b0b\n" ); } :(before "End Single-Byte Opcodes") case 0x81: { // combine r/m32 with imm32 trace(Callstack_depth+1, "run") << "combine r/m32 with imm32" << end(); const uint8_t modrm = next(); int32_t* signed_arg1 = effective_address(modrm); const int32_t signed_arg2 = next32(); trace(Callstack_depth+1, "run") << "imm32 is 0x" << HEXWORD << signed_arg2 << end(); const uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits switch (subop) { case 0: { trace(Callstack_depth+1, "run") << "subop add" << end(); int32_t signed_result = *signed_arg1 + signed_arg2; SF = (signed_result < 0); ZF = (signed_result == 0); int64_t signed_full_result = static_cast(*signed_arg1) + signed_arg2; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg1 = static_cast(*signed_arg1); uint32_t unsigned_arg2 = static_cast(signed_arg2); uint32_t unsigned_result = unsigned_arg1 + unsigned_arg2; uint64_t unsigned_full_result = static_cast(unsigned_arg1) + unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); *signed_arg1 = signed_result; trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); break; } // End Op 81 Subops default: cerr << "unrecognized subop for opcode 81: " << NUM(subop) << '\n'; exit(1); } break; } :(code) void test_add_imm32_to_r32_signed_overflow() { Reg[EBX].i = INT32_MAX; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 01 00 00 00\n" // add 1 to EBX // ModR/M in binary: 11 (direct mode) 000 (subop add) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x00000001\n" "run: subop add\n" "run: SF=1; ZF=0; CF=0; OF=1\n" "run: storing 0x80000000\n" ); } void test_add_imm32_to_r32_unsigned_overflow() { Reg[EBX].u = UINT32_MAX; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 01 00 00 00\n" // add 1 to EBX // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x00000001\n" "run: subop add\n" "run: SF=0; ZF=1; CF=1; OF=0\n" "run: storing 0x00000000\n" ); } void test_add_imm32_to_r32_unsigned_and_signed_overflow() { Reg[EBX].i = INT32_MIN; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 c3 00 00 00 80\n" // add 0x80000000 to EBX // ModR/M in binary: 11 (direct mode) 011 (subop add) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x80000000\n" "run: subop add\n" "run: SF=0; ZF=1; CF=1; OF=1\n" "run: storing 0x00000000\n" ); } //: :(code) void test_add_imm32_to_mem_at_rm32() { Reg[EBX].i = 0x2000; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 03 0a 0b 0c 0d \n" // add 0x0d0c0b0a to *EBX // ModR/M in binary: 00 (indirect mode) 000 (subop add) 011 (dest EBX) "== data 0x2000\n" "01 00 00 00\n" // 1 ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: effective address is 0x00002000 (EBX)\n" "run: imm32 is 0x0d0c0b0a\n" "run: subop add\n" "run: storing 0x0d0c0b0b\n" ); } //:: subtract :(before "End Initialize Op Names") put_new(Name, "2d", "subtract imm32 from EAX (sub)"); :(code) void test_subtract_imm32_from_EAX() { Reg[EAX].i = 0x0d0c0baa; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d 0a 0b 0c 0d \n" // subtract 0x0d0c0b0a from EAX ); CHECK_TRACE_CONTENTS( "run: subtract imm32 0x0d0c0b0a from EAX\n" "run: storing 0x000000a0\n" ); } :(before "End Single-Byte Opcodes") case 0x2d: { // subtract imm32 from EAX const int32_t signed_arg2 = next32(); trace(Callstack_depth+1, "run") << "subtract imm32 0x" << HEXWORD << signed_arg2 << " from EAX" << end(); int32_t signed_result = Reg[EAX].i - signed_arg2; SF = (signed_result < 0); ZF = (signed_result == 0); int64_t signed_full_result = static_cast(Reg[EAX].i) - signed_arg2; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg2 = static_cast(signed_arg2); uint32_t unsigned_result = Reg[EAX].u - unsigned_arg2; uint64_t unsigned_full_result = static_cast(Reg[EAX].u) - unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); Reg[EAX].i = signed_result; trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << Reg[EAX].i << end(); break; } :(code) void test_subtract_imm32_from_EAX_signed_overflow() { Reg[EAX].i = INT32_MIN; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d 01 00 00 00 \n" // subtract 1 from EAX ); CHECK_TRACE_CONTENTS( "run: subtract imm32 0x00000001 from EAX\n" "run: SF=0; ZF=0; CF=0; OF=1\n" "run: storing 0x7fffffff\n" // INT32_MAX ); } void test_subtract_imm32_from_EAX_unsigned_overflow() { Reg[EAX].i = 0; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d 01 00 00 00 \n" // subtract 1 from EAX ); CHECK_TRACE_CONTENTS( "run: subtract imm32 0x00000001 from EAX\n" "run: SF=1; ZF=0; CF=1; OF=0\n" "run: storing 0xffffffff\n" ); } void test_subtract_imm32_from_EAX_signed_and_unsigned_overflow() { Reg[EAX].i = 0; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 2d 00 00 00 80 \n" // subtract INT32_MIN from EAX ); CHECK_TRACE_CONTENTS( "run: subtract imm32 0x80000000 from EAX\n" "run: SF=1; ZF=0; CF=1; OF=1\n" "run: storing 0x80000000\n" ); } //: void test_subtract_imm32_from_mem_at_rm32() { Reg[EBX].i = 0x2000; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b 01 00 00 00 \n" // subtract 1 from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) "== data 0x2000\n" "0a 00 00 00\n" // 0xa ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: effective address is 0x00002000 (EBX)\n" "run: imm32 is 0x00000001\n" "run: subop subtract\n" "run: storing 0x00000009\n" ); } :(before "End Op 81 Subops") case 5: { trace(Callstack_depth+1, "run") << "subop subtract" << end(); int32_t signed_result = *signed_arg1 - signed_arg2; SF = (signed_result < 0); ZF = (signed_result == 0); int64_t signed_full_result = static_cast(*signed_arg1) - signed_arg2; OF = (signed_result != signed_full_result); // set CF uint32_t unsigned_arg1 = static_cast(*signed_arg1); uint32_t unsigned_arg2 = static_cast(signed_arg2); uint32_t unsigned_result = unsigned_arg1 - unsigned_arg2; uint64_t unsigned_full_result = static_cast(unsigned_arg1) - unsigned_arg2; CF = (unsigned_result != unsigned_full_result); trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); *signed_arg1 = signed_result; trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *signed_arg1 << end(); break; } :(code) void test_subtract_imm32_from_mem_at_rm32_signed_overflow() { Reg[EBX].i = 0x2000; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b ff ff ff 7f \n" // subtract INT32_MAX from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) "== data 0x2000\n" "00 00 00 80\n" // INT32_MIN ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: effective address is 0x00002000 (EBX)\n" "run: effective address contains 0x80000000\n" "run: imm32 is 0x7fffffff\n" "run: subop subtract\n" "run: SF=0; ZF=0; CF=0; OF=1\n" "run: storing 0x00000001\n" ); } void test_subtract_imm32_from_mem_at_rm32_unsigned_overflow() { Reg[EBX].i = 0x2000; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b 01 00 00 00 \n" // subtract 1 from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) "== data 0x2000\n" "00 00 00 00\n" // 0 ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: effective address is 0x00002000 (EBX)\n" "run: effective address contains 0x00000000\n" "run: imm32 is 0x00000001\n" "run: subop subtract\n" "run: SF=1; ZF=0; CF=1; OF=0\n" "run: storing 0xffffffff\n" ); } void test_subtract_imm32_from_mem_at_rm32_signed_and_unsigned_overflow() { Reg[EBX].i = 0x2000; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 2b 00 00 00 80 \n" // subtract INT32_MIN from *EBX // ModR/M in binary: 00 (indirect mode) 101 (subop subtract) 011 (dest EBX) "== data 0x2000\n" "00 00 00 00\n" // 0 ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: effective address is 0x00002000 (EBX)\n" "run: effective address contains 0x00000000\n" "run: imm32 is 0x80000000\n" "run: subop subtract\n" "run: SF=1; ZF=0; CF=1; OF=1\n" "run: storing 0x80000000\n" ); } //: void test_subtract_imm32_from_r32() { Reg[EBX].i = 10; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " 81 eb 01 00 00 00 \n" // subtract 1 from EBX // ModR/M in binary: 11 (direct mode) 101 (subop subtract) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: combine r/m32 with imm32\n" "run: r/m32 is EBX\n" "run: imm32 is 0x00000001\n" "run: subop subtract\n" "run: storing 0x00000009\n" ); } //:: shift left :(before "End Initialize Op Names") put_new(Name, "c1", "shift rm32 by imm8 bits depending on subop (sal/sar/shl/shr)"); :(code) void test_shift_left_r32_with_imm8() { Reg[EBX].i = 13; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 e3 01 \n" // shift EBX left by 1 bit // ModR/M in binary: 11 (direct mode) 100 (subop shift left) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: operate on r/m32\n" "run: r/m32 is EBX\n" "run: subop: shift left by CL bits\n" "run: storing 0x0000001a\n" ); } :(before "End Single-Byte Opcodes") case 0xc1: { const uint8_t modrm = next(); trace(Callstack_depth+1, "run") << "operate on r/m32" << end(); int32_t* arg1 = effective_address(modrm); const uint8_t subop = (modrm>>3)&0x7; // middle 3 'reg opcode' bits switch (subop) { case 4: { // shift left r/m32 by CL trace(Callstack_depth+1, "run") << "subop: shift left by CL bits" << end(); uint8_t count = next() & 0x1f; // OF is only defined if count is 1 if (count == 1) { bool msb = (*arg1 & 0x80000000) >> 1; bool pnsb = (*arg1 & 0x40000000); OF = (msb != pnsb); } *arg1 = (*arg1 << count); ZF = (*arg1 == 0); SF = (*arg1 < 0); // CF undefined trace(Callstack_depth+1, "run") << "SF=" << SF << "; ZF=" << ZF << "; CF=" << CF << "; OF=" << OF << end(); trace(Callstack_depth+1, "run") << "storing 0x" << HEXWORD << *arg1 << end(); break; } // End Op c1 Subops default: cerr << "unrecognized subop for opcode c1: " << NUM(subop) << '\n'; exit(1); } break; } //:: shift right arithmetic :(code) void test_shift_right_arithmetic_r32_with_imm8() { Reg[EBX].i = 26; run( "== code 0x1\n" // op ModR/M SIB displacement immediate " c1 fb 01 \n" // shift EBX right by 1 bit // ModR/M in binary: 11 (direct mode) 111 (subop shift right arithmetic) 011 (dest EBX) ); CHECK_TRACE_CONTENTS( "run: operate on r/m32\n" "run: r/m32 is EBX\n" "run: subop: shift right by CL bits, while preserving sign\n" "run: storing 0x0000000d\n" ); } :(before "End Op c1 Subops") case 7: { // shift right r/m32 by CL, preserving sign trace(Callstack_depth+1, "run") << "subop: shift right by CL bits, while preserving sign" << end(); uint8_t count = next() & 0x1f; int32_t result = (*arg1 >> count); ZF = (*arg1 == 0); SF = (*arg1 < 0); // OF is only defined if count is 1 if (count == 1) OF = false; // CF
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - 038---literal_strings.cc</title>
<meta name="Generator" content="Vim/8.1">
<meta name="plugin-version" content="vim8.1_v1">
<meta name="syntax" content="cpp">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal-light">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #c6c6c6; }
body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; }
a { color:inherit; }
* { font-size:12pt; font-size: 1em; }
.LineNr { }
.Constant { color: #008787; }
.Comment { color: #005faf; }
.Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; }
.Special { color: #d70000; }
.Identifier { color: #af5f00; }
.Delimiter { color: #c000c0; }
.cSpecial { color: #008000; }
-->
</style>

<script type='text/javascript'>
<!--

/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
  var lineNum;
  lineNum = window.location.hash;
  lineNum = lineNum.substr(1); /* strip off '#' */

  if (lineNum.indexOf('L') == -1) {
    lineNum = 'L'+lineNum;
  }
  var lineElem = document.getElementById(lineNum);
  /* Always jump to new location even if the line was hidden inside a fold, or
   * we corrected the raw number to a line ID.
   */
  if (lineElem) {
    lineElem.scrollIntoView(true);
  }
  return true;
}
if ('onhashchange' in window) {
  window.onhashchange = JumpToLine;
}

-->
</script>
</head>
<body onload='JumpToLine();'>
<a href='https://github.com/akkartik/mu/blob/master/038---literal_strings.cc'>https://github.com/akkartik/mu/blob/master/038---literal_strings.cc</a>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr">  1 </span><span class="Comment">//: Allow instructions to mention literals directly.</span>
<span id="L2" class="LineNr">  2 </span><span class="Comment">//:</span>
<span id="L3" class="LineNr">  3 </span><span class="Comment">//: This layer will transparently move them to the global segment (assumed to</span>
<span id="L4" class="LineNr">  4 </span><span class="Comment">//: always be the second segment).</span>
<span id="L5" class="LineNr">  5 </span>
<span id="L6" class="LineNr">  6 </span><span class="Normal">void</span> <a href='038---literal_strings.cc.html#L6'>test_transform_literal_string</a><span class="Delimiter">()</span> <span class="Delimiter">{</span>
<span id="L7" class="LineNr">  7 </span>  <a href='011run.cc.html#L83'>run</a><span class="Delimiter">(</span>
<span id="L8" class="LineNr">  8 </span>      <span class="Constant">&quot;== code 0x1\n&quot;</span>
<span id="L9" class="LineNr">  9 </span>      <span class="Constant">&quot;b8/copy  \&quot;</span>test\<span class="Constant">&quot;/imm32\n&quot;</span>
<span id="L10" class="LineNr"> 10 </span>      <span class="Constant">&quot;== data 0x2000\n&quot;</span>  <span class="Comment">// need an empty segment</span>
<span id="L11" class="LineNr"> 11