【问题标题】:TASM addressing off by oneTASM 减一
【发布时间】:2025-12-07 02:00:02
【问题描述】:

我目前正在为大学实施 Snake,为此我们必须使用 TASM。

我的主要游戏数据是这样排列的(使用 C 语法):

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;

问题是每帧写入方向位会覆盖大 x 位置的读取冲突位(38 是最大位置,但它发生得更早)。我说“读取冲突位”是因为我无法验证 physical_game_data 的实际位置,因为我不知道如何指示汇编器 (tasm) 和/或链接器 (tlink) 和/或调试器 (td) 向我展示。

我的代码中的声明是:

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 <= y <= 23, this allows addressing a line via `game_data + (y << 4)`

我在这里最担心的movs(还有一些,但这是使错误可见的两个)是这两个:

; 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]

查看td 中的内容会产生以下结果:

mov [bx+05AF],dh
; ...
mov dl,[si+05B8]

0x05AF 和 0x05B8 之间的差异是 9,而不是 10。我目前通过在源代码中添加 11 来“修复”该问题,这意味着该错误不会发生,但我宁愿修复此问题正确发出。

我假设这是我对 TASM 或 x86/x86-16 程序集的一些误解,但我不知道究竟是什么误解。

这是一个展示此问题的完整文件:


    .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 <= y <= 23, this allows addressing a line via `game_data + (y << 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

使用tasm MRE.ASMtlink MRE.OBJ编译,使用td打开td MRE.EXE,反编译代码如下:

mov ax,48AF
mov ds,ax
mov [bx+0103],dh
mov dl,[si+010C]
mov ax,4C00
int 21

同样,0x10C - 0x103 是 9。

如果有兴趣,我在 Dosbox 下运行这段代码。

谢谢!

【问题讨论】:

  • 您需要显示完整的源代码以及用于构建它的命令。如有必要,将您的问题减少到minimal reproducible example
  • @RossRidge 我已经添加了它,尽管我认为从上下文来看该示例的外观非常明显;还应该考虑到我认为这不太可能是实际的错误编译,因此看起来我误解了有关 x86-16 或 TASM 的一些东西。
  • 您提供源和选项比我们猜测它们是什么并自己提供要容易得多。特别是您是否使用理想模式并不明显。

标签: assembly memory x86-16 tasm off-by-one


【解决方案1】:

您的问题是 BYTE 关键字。在 MASM 模式下,BYTE 关键字计算为 BYTE 的大小:1。这被添加到方括号 [] 中的表达式中,因为方括号主要用作 MASM 模式中的加法运算符。您需要改写 BYTE PTR [ds:game_data + bx],尽管您的下一条说明表明您也可以将其省略。

【讨论】: