CL65 在使用 .align 时不调整地址

CL65 doesn't adjust addresses when using .align

我正在尝试编写一个使用 .align 指令来确保数据不跨越页面边界的 asm 程序。

然而,虽然数据位于内存中的正确位置,但编译后的代码并没有使用正确的地址。

根据文档 (https://www.cc65.org/doc/ld65-5.html)

If an alignment is requested, the linker will add enough space to the output file, so that the new segment starts at an address that is dividable by the given number without a remainder. All addresses are adjusted accordingly. To fill the unused space, bytes of zero are used, or, if the memory area has a "fillval" attribute, that value.

似乎没有发生这种调整。

为了重现,我有以下配置文件:(注意 'align' 在 DATA256 段上)

# Assembly configuration for R38

FEATURES {
    STARTADDRESS: default = 01;
}
SYMBOLS {
    __LOADADDR__: type = import;
# Putting "-u __EXEHDR__" on cl65's command line will add a BASIC RUN stub to your program.
#    __EXEHDR__:   type = import;
    __HIMEM__:    type = weak, value = F00;
}
MEMORY {
    ZP:       file = "", start = [=10=]22,  size = [=10=]80 - [=10=]22, define = yes;
    ZP2:      file = "", start = [=10=]A9,  size = 00 - [=10=]A9;
    LOADADDR: file = %O, start = %S - 2, size = [=10=]02;
    MAIN:     file = %O, start = %S,     size = __HIMEM__ - %S;
}
SEGMENTS {
    ZEROPAGE: load = ZP,       type = zp;
    EXTZP:    load = ZP2,      type = zp, optional = yes; # OK if BASIC functions not used
    LOADADDR: load = LOADADDR, type = ro;
    EXEHDR:   load = MAIN,     type = ro, optional = yes;
    CODE:     load = MAIN,     type = ro;
    LOWCODE:  load = MAIN,     type = ro, optional = yes;
    RODATA:   load = MAIN,     type = ro;
    DATA:     load = MAIN,     type = rw;
    DATA256:  load = MAIN,     type = rw, align = 0;
    DATA4k:   load = MAIN,     type = rw, align = 00;
    BSS:      load = MAIN,     type = bss,                define = yes;
}
FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = ONCE;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}

用asm作为

   .org 01                  ; Assembled code should start at 01
                                ; (where BASIC programs start)
                                ; The real program starts at 10 = 2064

; 10 SYS 2064
    .byte [=11=]C,               ; 0C - pointer to next line of BASIC code
    .byte [=11=]A, [=11=]              ; 2-byte line number ([=11=]0A = 10)
    .byte E                   ; SYS BASIC token
    .byte                    ; [space]
    .byte , , ,     ; ="2",="0",="6",="4"
    .byte [=11=]                   ; End of Line
    .byte [=11=], [=11=]              ; This is address 0C containing
                                ; 2-byte pointer to next line of BASIC code
                                ; ([=11=]00 = end of program)
    .byte [=11=], [=11=]              ; Padding so code starts at 10
    cld

    stp
    lda testdata
    rts


.segment "DATA256"
testdata:
    .byte , , , 

使用以下命令行构建:

cl65 --verbose -o build.prg --cpu 65c02 -t cx16 -C asm.cfg -Ln labels.txt -m map.txt -T main.asm

这是编译后的.prg。您可以看到 'lda testdata' 从 $0816 读取,这不是对齐地址。 $01、$02、$03 的填充显示数据对齐。

这在调试器中得到确认。

我做错了什么?或者这是链接器中的错误?

不要使用 .org 指令。配置文件设置该地址:STARTADDRESS: default = 01.

此外,该指令告诉汇编器告诉链接器“不要重定位以下代码”。这会阻止 .segment 指令执行我们期望的操作。