我想知道是否有人可以帮助我解决使用 VASM 汇编程序为 Amiga 编译MC68000二进制文件时遇到的烦人问题。问题在于标签地址操作的错误(我认为)实现。
以下是详细信息:
copper_scr:
dc.w $e0, (screen>>16) & $ffff
dc.w $e2, screen & $ffff
...
screen:
dcb.w screen_size ; screen_size value does not matter here
我在上面的代码中尝试做的是将屏幕地址拆分为最重要的单词和不太重要的单词,以便向芯片寄存器提供屏幕数据地址(如果您愿意,也可以向量)。
但是,以这种形状编译代码会给我"非法重定位"错误 39。
我尝试了很多方法来摆脱这种情况,因为我认为由于屏幕地址很长(即不是单词),"screen>>16"的结果可能会保持长,因此我无法将这样的值放入单词范围的位置。
有趣的是,以下代码编译没有错误,但生成的二进制文件中的两个值都编译为值 0:
...
dc.w $e0,0 + screen>>16 & $ffff
dc.w $e2,0 + screen&$ffff
...
作为一种临时的肮脏解决方法,我在运行时在代码开头的某个地方计算这些值:
move.l #screen,a0
move.l a0,d7
lsr.l #4,d7
lsr.l #4,d7
lsr.l #4,d7
lsr.l #4,d7
andi.l #$ffff,d7
move.w d7,copper_scr+2
move.l a0,d7
andi.l #$ffff,d7
move.w d7,copper_scr+6
但这显然是荒谬的,完全错误的。
任何帮助表示赞赏。
不错的解决方法可能是:
move.l #screen,d0
move.w d0,scrptr_low+2
swap d0
move.w d0,scrptr_high+2
...
scrptr_high: dc.w $e0,0
scrptr_low: dc.w $e2,0
或
scrptr: dc.l screen
...
move.l scrptr,d0
<then the same>
这样,链接器和exe-loader-relocator将处理通常的32位地址,它们知道如何正确重新定位。
问题在于汇编程序(和链接器)的工作方式:
一些汇编程序已经知道某些代码稍后将放置在哪个地址,而其他汇编程序编写对象文件,链接器将决定将数据放置的位置。
在目标文件中,像dc.w 1234 + screen>>16 & $ffff
这样的指令将存储为dc.w 1234
,并存储一个附加信息,即一旦知道screen
的地址,必须将高 16 位screen
添加到1234
。
不幸的是,有两个问题:
并非所有体系结构都支持所有类型的信息。例如,Sparc CPU的目标文件支持"将地址的低10位添加到值"的信息(因为此类CPU具有使用地址的低10位的指令),而m68k的目标文件不支持">地址的低10位"信息类型。
不幸的是,m68k 对象文件也不支持">地址的高 16 位"信息类型。(至少如果你使用 GNU 工具,则不会 - 我不确定 VASM。
汇编程序是愚蠢的。它们不会检测到
screen>>16 & $ffff
等于">地址的高 16 位"。因此,即使您的文件格式(例如 PowerPC 对象文件)支持该类型的信息,汇编程序也会遇到问题。
可能的解决方法:
如果您在同一部分中有一个标签,并且您肯定知道该标签的地址,则可以执行以下操作。
假设您知道标签xyz
稍后将加载到内存中的地址$1234
中。
现在,您可以执行以下操作:
xyz:
...
dc.w $e0, 0 + (screen - xyz + $1234) >> 16 & $ffff
...
screen:
但是,如果您不知道任何标签的"最终"地址,那么您将遇到问题......