2

我正在尝试为 Game Boy 购物车生成墨盒标题校验和。磁带头校验和定义为类似 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字符串中使用了十六进制转义序列。这实际上不起作用,因为\xGNU 无法识别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

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

4

1 回答 1

1

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

如果您想要在汇编时计算某些东西,我认为您可以使用GAS来完成,该GAS在更新汇编器变量的汇编时表达式中使用其 arg,作为..macro.byte

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

在这种情况下,转换为使用类似
byte_cksum_accum 0xce,0xed,0x66,0x66,0xcc,0x0d,0x00, ....

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

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

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

更好的选择?

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

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

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