Проблема кросс-ассемблера VASM (m68k)

Мне интересно, может ли кто-нибудь помочь мне с раздражающей проблемой, с которой я сталкиваюсь, используя ассемблер VASM для компиляции двоичных файлов MC68000 для Amiga. Проблема заключается в глючной (как мне кажется) реализации манипуляций с адресами меток.
Вот подробности:

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 «незаконное перемещение».

Я испробовал много способов избавиться от этого, так как предполагал, что, поскольку адрес экрана длинный (т.е. не слово), результат «экран >> 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

но это, очевидно, смешно и совершенно неправильно.

Любая помощь приветствуется.


person H_nk    schedule 25.01.2018    source источник
comment
Как вы строите? Какие аргументы вы передаете ассемблеру? Как перенести программу на Амигу?   -  person Some programmer dude    schedule 25.01.2018
comment
Вот командная строка, которую я использую для компиляции source.s в result.bin: vasmm68k_mot_win32.exe -Fhunkexe -o result.bin -nosym source.s Файл result.bin находится в папке, которую я установил в эмуляторе FS-UAE как жесткий диск, поэтому я могу напрямую запустить его под эмулятором - но это не главное. Моя проблема в том, что я даже не могу скомпилировать код, используя синтаксис, который я описал в вопросе. :/   -  person H_nk    schedule 25.01.2018


Ответы (2)


Проблема заключается в том, как работает ассемблер (и компоновщик):

Некоторые ассемблеры уже знают, по какому адресу позже будет размещен некоторый код, в то время как другие ассемблеры пишут объектные файлы, а компоновщик решает, куда будут помещены данные.

В объектном файле инструкция типа dc.w 1234 + screen>>16 & $ffff будет сохранена как dc.w 1234, а также сохранена дополнительная информация о том, что старшие 16 бит screen должны быть добавлены к 1234, как только станет известен адрес screen.

К сожалению есть две проблемы:

  • Не все архитектуры поддерживают все типы информации. Объектные файлы для ЦП Sparc, например, поддерживают информацию добавить младшие 10 бит адреса к значению (поскольку такие ЦП имеют инструкции, использующие младшие 10 бит адреса), в то время как объектные файлы для m68k не поддерживают поддерживают тип информации младшие 10 бит адреса.

    К сожалению, тип информации старшие 16 бит адреса также не поддерживается объектными файлами m68k. (По крайней мере, если вы используете инструменты GNU — я не уверен насчет VASM.)

  • Ассемблер тупой. Они не обнаружат, что screen>>16 & $ffff равно старшим 16 битам адреса. Таким образом, даже если ваш формат файла (например, объектные файлы PowerPC) поддерживает этот тип информации, у ассемблера возникнут проблемы.

Возможный обходной путь:

Если у вас есть ярлык в разделе такой же и вы точно знаете адрес этого ярлыка, вы можете сделать следующее.

Предположим, вы знаете, что метка xyz будет позже загружена в память по адресу $1234.

Теперь вы можете сделать следующее:

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

Однако, если вы не знаете окончательный адрес какой-либо метки, у вас возникнут проблемы...

person Martin Rosenau    schedule 25.01.2018
comment
Спасибо, Мартин, за подробное объяснение! У меня было ощущение, что это может иметь что-то общее с переносимым характером MC68000. Я отмечаю ваш вклад как ответ, так как он все четко объясняет. :) Однако, идя дальше, оказывается, что кросс-разработка, дружественная к ОС, не совсем возможна. Чего я действительно хотел, так это избежать назначения меток фиксированным адресам. Кажется, что единственным решением для этого является получение старших и младших слов адреса во время выполнения. Ваше здоровье! - person H_nk; 25.01.2018
comment
Это даже немного сложнее: абсолютное значение screen зависит от конечного адреса загрузки вашей программы и не может быть окончательно определено даже компоновщиком. Компоновщик просто оставит некоторую информацию для перемещающего загрузчика, что этот адрес имеет определенное смещение от начала программы. И возможности перемещающего загрузчика ограничены исправлением этих помеченных адресов конечными адресами загрузки (то есть он ограничен простым добавлением базового адреса и этого смещения) - person tofro; 04.02.2018

Хороший обходной путь может быть:

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

or

scrptr: dc.l screen
...
move.l  scrptr,d0
<then the same>

Таким образом, компоновщик и exe-loader-relocator будут иметь дело с обычными 32-битными адресами, которые они знают, как правильно перемещать.

person lvd    schedule 26.01.2018