assemblycross-platform68000amiga

VASM cross-assembler issue (m68k)


I'm wondering if anyone can help me with an annoying issue I face using VASM assembler to compile MC68000 binaries for Amiga. The problem lies in buggy (I think) implementation of labels' addresses manipulations.
Here are the details:

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

What I'm trying to do in the code above is to split screen address into most significant word and less significant word in order to feed chip registers with screen data address (or vector if you wish).

However, compilation of code in this shape gives me the "illegal relocation" error 39.

I tried many ways to get rid of this, as I supposed that since screen address is long (i.e. not word) the result of "screen>>16" might remain long and therefore I cannot put such a value into word-wide place.

What's interesting, the following code compiles with no errors, but both values in resulting binary are compiled to a value of 0:

...
dc.w $e0,0 + screen>>16 & $ffff
dc.w $e2,0 + screen&$ffff
...

As a temporal dirty workaround I calculate those values at runtime somewhere at the beginning of code:

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

but that is obviously ridiculous and totally wrong.

Any help appreciated.


Solution

  • The problem lies in the way the assembler (and linker) works:

    Some assemblers already know at which address some code will later be placed while other assemblers write object files and the linker will decide where the data will be placed.

    In the object file an instruction like dc.w 1234 + screen>>16 & $ffff will be stored as dc.w 1234 and an additional information is stored that the high 16 bits of screen must be added to 1234 as soon as the address of screen is known.

    Unfortunately there are two problems:

    Possible work-around:

    If you have a label in the same section and you definitely know the address of that label you can do the following.

    Let's assume you know that the label xyz will be loaded into address $1234 in the memory later.

    Now you can do the following:

    xyz:
        ...
        dc.w $e0, 0 + (screen - xyz + $1234) >> 16 & $ffff
        ...
    screen:
    

    However if you don't know the "final" address of any label you'll have a problem...