title: TASM addressing off by one
body: <p>I'm currently implementing Snake for university, and we have to use TASM for that.</p>
  <p>My main game data is laid out like this (using C syntax):</p>
  <pre class="lang-c prettyprint-override"><code>struct GameLine {
      uint8_t direction_bits[10];  // 2 bits per entry, the first entry is invalid since valid x positions start at one
      uint8_t collision_bits[5];  // 1 bit per entry, the first entry is again invalid but has to stay zero
      uint8_t aux;  // padding such that GameLine is 16 bytes big, also used to store other information at times.
  };
  
  struct GameData {
      struct GameLine lines[23];
  } PHYSICAL_GAME_DATA;
  </code></pre>
  <p>The issue is that writing the direction bits each frame overwrites the read collision bits for large x positions (38 is the maximum position, but it happens earlier). I say &quot;read collision bits&quot; because I wasn't able to verify where the <code>physical_game_data</code> actually resides because I don't know how to instruct the assembler (<code>tasm</code>) and/or linker (<code>tlink</code>) and/or debugger (<code>td</code>) to show me that.</p>
  <p>The declarations in my code are:</p>
  <pre><code>physical_game_data   DB 368 DUP (0)
  ; ..., Some `EQU`s for `aux` data I'm using to store other information
  game_data EQU (offset physical_game_data) - 16  ; Since 1 &lt;= y &lt;= 23, this allows addressing a line via `game_data + (y &lt;&lt; 4)`
  </code></pre>
  <p>The <code>mov</code>s that I'm most worried about here (there are a few more, but these are the two that make the bug visible) are these two:</p>
  <pre><code>; This one is for writing a new direction
  mov     BYTE [ds:game_data + bx],   dh
  ; ...
  ; This one is for reading a collision bit to check if the player lost
  mov     dl,     [ds:game_data + 10 + si]
  </code></pre>
  <p>Looking at those in <code>td</code> however yields this:</p>
  <pre><code>mov [bx+05AF],dh
  ; ...
  mov dl,[si+05B8]
  </code></pre>
  <p>The difference between 0x05AF and 0x05B8 however is 9, not 10. I've currently &quot;fixed&quot; the issue by adding 11 in the source code instead, which means the bug doesn't occur, but I'd rather fix this issue properly.</p>
  <p>I'm assuming that this is me misunderstanding something about TASM or x86/x86-16 assembly, but I don't know what exactly that misunderstanding is.</p>
  <p>Here's a complete file that exhibits this issue:</p>
  <pre><code>
      .model  tiny
      .286
  
  .data
  datastart:
  physical_game_data  DB 368 DUP (0)
  ; ..., Some `EQU`s for `aux` data I'm using to store other information
  game_data           EQU (offset physical_game_data) - 16  ; Since 1 &lt;= y &lt;= 23, this allows addressing a line via `game_data + (y &lt;&lt; 4)`
  
  .code
  
          ORG 100h
  start:
          mov         ax,                         seg datastart
          mov         ds,                         ax
  
          ; This one is for writing a new direction
          mov         BYTE [ds:game_data + bx],   dh
          ; ...
          ; This one is for reading a collision bit to check if the player lost
          mov         dl,                         [ds:game_data + 10 + si]
  
          ; Exit
          mov         ax,                         4C00h
          int         21h
  end start
  </code></pre>
  <p>Compiled using <code>tasm MRE.ASM</code>, <code>tlink MRE.OBJ</code> and opened with <code>td</code> using <code>td MRE.EXE</code>, the decompiled code reads:</p>
  <pre><code>mov ax,48AF
  mov ds,ax
  mov [bx+0103],dh
  mov dl,[si+010C]
  mov ax,4C00
  int 21
  </code></pre>
  <p>Where, again, 0x10C - 0x103 is 9.</p>
  <p>If it is of interest, I'm running this code under Dosbox.</p>
  <p>Thanks!</p>