CL65 не корректирует адреса при использовании .align
Я пытаюсь написать программу asm, которая использует директиву .align, чтобы данные не пересекали границы страницы.
Однако, хотя данные находятся в правильном месте в памяти, скомпилированный код не использует правильный адрес.
Согласно документам ( https://www.cc65.org/doc/ld65-5.html )
Если требуется выравнивание, компоновщик добавит достаточно места в выходной файл, чтобы новый сегмент начинался с адреса, который делится на данное число без остатка. Все адреса настроены соответствующим образом. Для заполнения неиспользуемого пространства используются нулевые байты или, если область памяти имеет атрибут fillval, это значение.
Похоже, что этой корректировки не происходит.
Для воспроизведения у меня есть следующий файл конфигурации:
# Assembly configuration for R38
FEATURES {
STARTADDRESS: default = $0801;
}
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 = $9F00;
}
MEMORY {
ZP: file = "", start = $0022, size = $0080 - $0022, define = yes;
ZP2: file = "", start = $00A9, size = $0100 - $00A9;
LOADADDR: file = %O, start = %S - 2, size = $0002;
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 = $100;
DATA4k: load = MAIN, type = rw, align = $1000;
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 as
.org $0801 ; Assembled code should start at $0801
; (where BASIC programs start)
; The real program starts at $0810 = 2064
; 10 SYS 2064
.byte $0C, $08 ; $080C - pointer to next line of BASIC code
.byte $0A, $00 ; 2-byte line number ($000A = 10)
.byte $9E ; SYS BASIC token
.byte $20 ; [space]
.byte $32, $30, $36, $34 ; $32="2",$30="0",$36="6",$34="4"
.byte $00 ; End of Line
.byte $00, $00 ; This is address $080C containing
; 2-byte pointer to next line of BASIC code
; ($0000 = end of program)
.byte $00, $00 ; Padding so code starts at $0810
cld
stp
lda testdata
rts
.segment "DATA256"
testdata:
.byte $01, $02, $03, $04
Это скомпилированный .prg. Вы можете видеть, что lda testdata читает из $0816, который не является выровненным адресом. Отступы до $01, $02, $03 показывают, что данные выровнены.
Создан с использованием следующей командной строки:
cl65 --verbose -o build.prg --cpu 65c02 -t cx16 -C asm.cfg -Ln labels.txt -m map.txt -T main.asm
Это подтверждается в отладчике.
Что я делаю неправильно? Или это ошибка компоновщика?
1 ответ
Не используйте
.org
директива. Файл конфигурации устанавливает этот адрес:
STARTADDRESS: default = $0801
.
Кроме того, эта директива говорит ассемблеру сказать компоновщику: «Не перемещайте следующий код». Это предотвращает
.segment
директива от выполнения того, что мы от него ожидаем.