我如何为这个墨盒头生成校验和?

How can I generate a checksum for this cartridge header?

我正在尝试为 Game Boy 购物车生成 cartridge header 校验和。磁带头校验和定义为类似 C 的伪代码:

unsigned char checksum = 0;
for(unsigned char *p = 0x0134; p < 0x014D; p++)
    x += ~*p;

或者:

unsigned char checksum = 0;
for(unsigned char *p = 0x0134; p < 0x014D; p++)
    x = x - *p - 1;

此数据从地址 0x0104 开始。地址0x0134对应title的开头。地址0x014D对应header_checksum的开头。

请注意,出于演示目的,我在 .ascii 字符串中使用了十六进制转义序列。这 实际上 不起作用,因为 GNU as.

无法识别 \x
nintendo_logo:
    # Nintendo logo. Must be present and unmodified.
    .ascii "\xce\xed\x66\x66\xcc\x0d\x00\x0b\x03\x73\x00\x83\x00\x0c\x00\x0d"
    .ascii "\x00\x08\x11\x1f\x88\x89\x00\x0e\xdc\xcc\x6e\xe6\xdd\xdd\xd9\x99"
    .ascii "\xbb\xbb\x67\x63\x6e\x0e\xec\xcc\xdd\xdc\x99\x9f\xbb\xb9\x33\x3e"
title:
    # Title. At most 11 characters and zero-padded if smaller.
    # GameBoys use 16 characters.
    TITLE_SIZE = 11
    .ascii "ABCDEF"
    .fill TITLE_SIZE-(.-title)
manufacturer:
    .ascii "ABCD"
cgb_f:
    # Color Game Boy flag. 0x80 means that the game supports
    # Color Game Boy functions, but still works on the original Game Boy.
    .byte 0x80
new_licensee:
    # Company or publisher ASCII code. 00 is none.
    .ascii "00"
sgb_f:
    # Super Game Boy flag. 3 means it has support for the SGB, 0 means no.
    # I might implement color for the SGB
    .byte 0x03
cart_type:
    # Memory bank controller used and any additional hardware.
    # 0x00 is rom-only.
    .byte 0x00
rom_size:
    # ROM size in terms of 32KB << B
    .byte 0x00
ram_size:
    # The amount of externam RAM in the catridge
    .byte 0x00
is_japan:
    # If the byte is 0x00 it's for Japan, if 0x01 anywhere else
    .byte 0x01
old_licensee:
    # hex value of company/publisher
    # Super Game Boy needs 0x33 to work
    .byte 0x33
version:
    # version of the game
    .byte 0x00
header_checksum:
    # TODO: How to calculate this?
    sum = add(title, version)
    .byte sum

如何计算这个校验和?如果可能的话,有没有办法使用汇编程序指令来做到这一点?

GAS 指令无法读取已发送到输出文件中的字节。

如果你想要assemble-time 计算 的东西,我想你可以用 a GAS .macro 来完成,它在assemble-time 表达式更新汇编程序变量, 作为 .byte.

的操作数

但是您需要在用作数字的表达式中执行此操作,这可能会排除方便的 .ascii 字符串文字。

在这种情况下,转换为使用像
这样的宏可能比值得更麻烦 byte_cksum_accum 0xce,0xed,0x66,0x66,0xcc,0x0d,0x00, ....

这样的宏可以使用 .set cksum, cksum + ~ 或类似的东西,以及 .byte 。循环多个 GAS 宏参数是通过编写递归 .macro 来完成的。所以我认为这是可能的。 GAS 还具有允许 i = i + 1.altmacro 语法。我自己没怎么用过 GAS 宏。

更好的选择:使用 C 程序 + 构建规则 + .incbin

  • 让您的来源使用 .incbin "checksum_file.bin directive
  • ... C 程序在阅读您的 .o
  • 后编写的
  • 在 Makefile 中,此 .o 的构建规则在外部组装/生成校验和 / re-assembles 以包含 正确的 校验和。 (在第一次组装之前触摸或截断或删除 checksum_file.bin,以最方便的方式确保它仍然可以组装,并且如有必要 包含陈旧的校验和字节.)

更好的选择?

  • 让你的 C 程序输出一个带有 数据 和校验和的平面二进制文件。 所以 header 字节仍然是在您的源代码中恰好出现在一个地方,在您的 C 程序的 uint8_t header[] = {...} 初始值设定项中。
  • .S 中使用 .incbin 来包含它。
  • 使用构建规则确保 cksummed-header.bin 是构建 .S
  • 的输入依赖项

或者写一个 C 程序修改一个二进制文件

  • 读取 header,更新二进制文件中的占位符 .byte 0
  • 将 header 数据与 asm 源的其余部分保持在一起
  • C 程序不需要为不同的购物车重新编译。