【问题标题】:How can I generate a checksum for this cartridge header?我怎样才能为这个墨盒头生成校验和?
【发布时间】:2020-07-08 15:18:33
【问题描述】:

我正在尝试为 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 字符串中使用了十六进制转义序列。这实际上不起作用,因为\x 无法被 GNU as 识别。

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

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

【问题讨论】:

    标签: assembly gnu gnu-assembler gameboy


    【解决方案1】:

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

    如果您想要在汇编时计算某事,我认为您可以使用 a GAS .macro 在更新汇编器变量的汇编时表达式中使用其 arg, 作为.byte的操作数。

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

    在这种情况下,转换为使用像
    byte_cksum_accum 0xce,0xed,0x66,0x66,0xcc,0x0d,0x00, ... 这样的宏可能会带来更多麻烦。

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

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

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

    更好的选择?

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

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

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

    【讨论】:

    • 我想更多的是一个读取文件并一次性写入校验和的 C 程序。
    • @S.S.Anne:这只有在 C 程序读取 asm 源而不是目标文件(或您使用 objcopy 或其他东西创建的平面二进制文件)时才有可能。否则,您需要汇编一次以获得 C 程序的二进制输入。
    • 我在想 C 程序可以读写该校验和的二进制文件。它们都按顺序存储(根据墨盒标头规范)。
    • @S.S.Anne:啊,是的,如果你只留下一个占位符字节,这可能会起作用。或者查看我的更新:让 C 程序为 incbin 写出标题 + 校验和。您的想法可能会更好,因为您可以将该程序重复用于不同的墨盒。
    • 这很奇怪。我之前使用了十六进制转义,他们在生成的目标文件中插入了文字文本 \x...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-12
    相关资源
    最近更新 更多