Директива ASSUME с использованием masm

Я пытался написать ассемблерный код с использованием ASSUME, но продолжаю получать ошибки, причины которых я не смог выяснить. Вот пара примеров: Пример 1

.286
.model medium, c
pproc typedef ptr proc
.data
dummy db ?
.code
assume bx:ptr pproc
call [bx]
end

при сборке ошибок не возникает.

Если я изменяю .286 на .386, то получаю следующую ошибку:
Error A2158: type is wrong size for register.
Эта ошибка возникает для строки: Assume bx:ptr proc

Почему это происходит? Что нужно изменить в ПРЕДПОЛОЖЕНИИ, чтобы исправить ошибку?

Примечание: я заметил, что pproc определяется ассемблером как указатель FAR. ЗАЧЕМ?


пример 2:

.286
.model medium
.data
dummy db ?
.code
assume bx:near ptr 
call [bx]
call near ptr [bx[
end

Теперь, если я просто заменю .286 на .386, я получу следующую ошибку ассемблера:
assume bx:near ptr
A2158: Type is wrong size for register

Почему я получаю эту ошибку? Это ближний сегмент. Обратите внимание, что инструкция, которая делает то же самое, не использует Assume.


пример 3

.286
.model medium, c
.data
dummy db ?
.code
assume bx:ptr byte
mov [bx],12h
mov byte ptr [bx],12h
end

Теперь, если я просто поменяю .286 на .386, я получаю следующие ошибки при попытке собрать его.

для строки: assume bx:ptr byte я получаю сообщение об ошибке
A2158: Type is wrong size for register
Почему это происходит? Что нужно изменить в ПРЕДПОЛОЖЕНИИ, чтобы исправить ошибку?

для строки: mov [bx],12h
возникает следующая ошибка: error 2070 :invalid instruction operands.

Почему я получаю эту ошибку? Это ошибка? Это должно сработать, я пытаюсь сохранить 12h в [bx]. Обратите внимание, что инструкция, которая делает то же самое, не использует Assume.


person StillLearning    schedule 25.05.2019    source источник
comment
mov [bx],12h - неоднозначный размер операнда. Ассемблер не знает, нужен ли вам размер операнда в байтах, словах или двойных словах для этого хранилища. (Сообщение об ошибке, к сожалению, ужасное. Используйте mov word ptr [bx], 12h, если это то, что вам нужно, или byte ptr.   -  person Peter Cordes    schedule 25.05.2019
comment
Для assume .386 подразумевает 32-битные указатели, а BX по-прежнему является 16-битным регистром. Это может также означать плоскую модель памяти, IDK.   -  person Peter Cordes    schedule 25.05.2019
comment
Над инструкцией mov [bx],12h есть инструкция ASSUME, которая указывает размер байта. Я спрашиваю о том, почему ASSUME выдает мне сообщение об ошибке?   -  person StillLearning    schedule 25.05.2019
comment
Вы заметили, что инструкция с ПРЕДПОЛАГАЕМЫМ над ними выдавала сообщение об ошибке. А та же инструкция без ПРЕДПОЛАГАЕМОГО - нет. Что нужно изменить в ПРЕДПОЛОЖЕНИИ, чтобы избавиться от сообщения об ошибке?   -  person StillLearning    schedule 25.05.2019
comment
Из вашего вопроса не было ясно, когда эта строка выдавала/не выдавала ошибку. Или даже то, что на него повлияло изменение других линий. Я не знаю MASM (в основном NASM и GAS), я не знал, что assume может делать что-либо, кроме сообщения ассемблеру, на какую базу сегментов вы собираетесь установить DS или ES. Кажется, что лучший стиль IMO, чтобы сделать размер явным, где вы используете регистр, даже если существует синтаксис, который подразумевает его из какой-то другой строки. Но в любом случае, вы уверены, что это ptr byte вместо byte ptr?   -  person Peter Cordes    schedule 25.05.2019
comment
@PeterCordes: .386 не означает плоскую модель. Вы можете использовать .386 с моделями реального режима, и это позволит вам сгенерировать 386 инструкций в реальном режиме.   -  person Michael Petch    schedule 25.05.2019
comment
Также ОП правильный. Предположим, что директивы используют ptr xxxx, а не xxxx ptr при связывании типов с регистрами.   -  person Michael Petch    schedule 25.05.2019
comment
Я добавил в свой ответ важный раздел, который может пролить свет на вашу проблему с NEAR и FAR, когда она связана с JMP/CALL в косвенной ссылке на память.   -  person Michael Petch    schedule 26.05.2019


Ответы (5)


документация по MASM 6.1 — хороший ресурс для написания сегментированный код (модели без FLAT). На страницах 43-47 есть хорошая информация о ПРЕДПОЛОЖЕНИИ и размерах слов сегментов. То, с чем вы столкнулись, является побочным эффектом довольно тонкого способа, которым ASSUME будет работать в зависимости от где вы поместите директиву .386 относительно директивы .MODEL. Это тонкое поведение описано в разделе Установка размера слова сегмента (только 80386/486):

Установка размера слова сегмента (только 80386/486)

Тип использования в директиве SEGMENT определяет размер слова сегмента в процессорах 80386/486. Размер слова сегмента определяет размер операнда и адреса по умолчанию для всех элементов в сегменте. Атрибут размера может быть USE16, USE32 или FLAT. Если вы указываете директиву .386 или .486 перед директивой .MODEL, по умолчанию используется USE32. Этот атрибут указывает, что элементы в сегменте адресуются с 32-битным смещением, а не с 16-битным смещением. Если .MODEL предшествует директиве .386 или .486, по умолчанию используется USE16. Чтобы сделать USE32 директивой по умолчанию, поставьте .386 или .486 перед .MODEL. Вы можете переопределить атрибут USE32 по умолчанию с помощью атрибута USE16 или наоборот.

С чем вам нужно быть осторожным, так это с тем, где вы размещаете .386. Вы поместили его перед .model, поэтому ассемблер предполагает, что все разделы по умолчанию равны USE32. Похоже, вы пишете код, который будет работать в 16-битном реальном режиме (возможно, с использованием 386 инструкций и регистров), поэтому я полагаю, что вы захотите убедиться, что USE16 является значением по умолчанию при использовании директив .code и .data. Чтобы получить желаемое поведение, я думаю, вы могли бы подумать об изменении:

.386
.model medium, c

To:

.model medium, c
.386

И наблюдайте, что происходит.


Это вторая проблема, с которой, как я полагаю, вы столкнулись. В MASM 5.1 была добавлена ​​эта дополнительная информация, которая может пролить свет на вашу проблему с FAR PTR и NEAR PTR . Он гласит:

Оператор PTR

Оператор PTR можно использовать для указания размера регистра косвенного операнда для инструкции CALL или JMP. Однако размер не может быть указан с помощью NEAR или FAR. Вместо этого используйте WORD или DWORD. (В 32-битных сегментах 80386 используйте DWORD или FWORD.) Примеры показаны ниже:

      ; 8086, 80826, or 80386 16-bit mode

      jmp  WORD PTR [bx]        ; Legal near jump
      call NEAR PTR [bx]        ; Illegal near call
      call DWORD PTR [bx]       ; Legal far call
      jmp  FAR PTR [bx]         ; Illegal far jump

      ; 80386 32-bit mode only

      jmp  DWORD PTR [bx]       ; Legal near jump
      call NEAR PTR [bx]        ; Illegal near call
      call FWORD PTR [bx]       ; Legal far call
      jmp  FAR PTR [bx]         ; Illegal far jump

Это ограничение применяется только к регистрации косвенных операндов. NEAR или FAR можно применять к операндам, связанным с метками. Примеры показаны ниже:

      jmp  NEAR PTR pointer[bx] ; Legal
      call FAR PTR location     ; Legal

В разделе USE32, если вы хотите сделать непрямой FAR JMP/CALL, используйте:

pproc typedef ptr fword

Если вы хотите сделать почти непрямой вызов в разделе USE32, сделайте:

pproc typedef ptr dword

В разделе USE16, если вы хотите сделать непрямой FAR JMP/CALL, используйте:

pproc typedef ptr dword

Если вы хотите сделать почти непрямой вызов в разделе USE16, сделайте:

pproc typedef ptr word
person Michael Petch    schedule 25.05.2019
comment
Спасибо. Ты прав. Так почему же ASSUME заботится о том, use16 или use32? Его должно волновать только то, что размер используемого регистра равен ‹= указанному размеру, который будет использоваться? Причина, по которой я говорю это, заключается в том, что если вы укажете размер для использования в инструкции, ей все равно, является ли сегмент use16 или use32. Это только усложняет написание кода. - person StillLearning; 26.05.2019
comment
@StillLearning Собираетесь ли вы смешивать 32-битные и 16-битные инструкции? Например, почему вы хотите использовать .386, а не .286? Возможно, у вас возникла проблема XY . Что вы пытаетесь сделать, используя .386.. Чего вы хотите добиться с его помощью? - person Michael Petch; 26.05.2019
comment
Чтобы примеры кода, которые вы дали: для работы оператора PTR, вставьте ASSUME BX: Word перед всеми ними, и тогда все они действительны. - person StillLearning; 05.06.2019
comment
@StillLearning: у вас есть способы понять. Сгенерированный код для непрямых вызовов (фактически испускаемые байты) различается между use32 и use16. Вы были так сосредоточены на том, чтобы ассемблер скомпилировался без ошибок, но просмотрел сгенерированные коды операций, которые различаются в зависимости от того, в каком режиме (16- или 32-битный код) находится раздел. У меня есть подозрение, что это что-то вроде [проблема XY] (en.wikipedia.org/wiki/XY_problem_ здесь, что побудило меня спросите, почему вы используете директиву .386. - person Michael Petch; 05.06.2019

Во всех примерах вы говорите MASM считать bx указателем на что-то1 (сначала процедуру, затем что-то близкое, затем байт), и во всех случаях эти указатели являются близкими (что неявно, если не указано иное). заявлено).

Если вы укажете .286, MASM создаст сегмент данных по умолчанию, который, как предполагается, будет иметь 16-битную адресацию, аналогично сегменту кода по умолчанию (размер операнда/адреса по умолчанию — 16-бит).
Если вы используете .386, 32-битный создаются версии.

Ближние указатели на 16-битный сегмент данных являются 16-битными, а ближние указатели на 32-битные сегменты данных — 32-битными.
Вместо этого регистр bx всегда 16-битный.
Таким образом, .386 с ASSUME BX: PTR <SOMETHING> не может работать. .


1 Я предполагаю, что это полезно для некоторых уродливых высокоуровневых смешиваний, таких как предупреждение вас, если вы загружаете/сохраняете другой тип или позволяете вам получить доступ к членам структуры.
ASSUME полезно/необходимо с сегментом регистрируется в среде сегмента, официальная документация кажется катастрофически неполным, если полностью его скрыть.

person Margaret Bloom    schedule 25.05.2019
comment
Тогда почему я могу создать ту же самую инструкцию, используя в инструкции явный размер (слово ptr), и это работает, но не работает в инструкции ASSUME? Обратите внимание, что ошибка возникает ТОЛЬКО при использовании ASSUME. - person StillLearning; 25.05.2019
comment
В тех примерах, которые я привел, на мой взгляд, таких ошибок быть не должно. Причина в том, что одна и та же инструкция может быть создана с использованием явных спецификаторов размера PTR внутри инструкции. - person StillLearning; 25.05.2019
comment
@StillLearning: в этом ответе говорится, что .386 позволяет использовать assume только с 32-битными регистрами указателей, такими как EBX или EAX. Проблема не в ширине данных, а в ширине указателя. mov byte ptr [bx], 12h является действительной кодируемой инструкцией x86 даже в 32-битном режиме, поэтому MASM по-прежнему позволяет вам написать ее явно, но это не поможет вам написать ее, потому что 16-битные режимы адресации, вероятно, являются ошибкой для 32-битный код. (По крайней мере, это рассуждение объясняет поведение MASM здесь.) - person Peter Cordes; 25.05.2019
comment
@MichaelPetch: ваше редактирование вставило некоторый текст вместо фактического URL-адреса руководства. - person Peter Cordes; 26.05.2019
comment
@PeterCordes Спасибо, я отменил изменение, так как указал этот URL в своем ответе. - person Michael Petch; 26.05.2019
comment
@StillLearning ASSUME сообщает MASM, какой тип данных вы храните в регистре. Если, например, вы скажете ему, что bx содержит указатель на байт, то MASM не позволит вам получить доступ к слову и позволит вам не указывать размер операнда перемещения, даже если такая инструкция неоднозначна. - person Margaret Bloom; 26.05.2019

Майкл:

Вот пример кода, который создает 16-битный код:

.Model small,c ;since cpu instruction is after .Model it causes USE16 to be used
.286
.code
assume bx:word
call bx
end

Поскольку действует use16, это создает 16-битный сегмент, а .286 указывает ему использовать 16-битные инструкции. Когда приведенный выше код собран, он создает коды операций FF D3 для инструкции Call bx. Инструкции «вызов NEAR PTR bx» или «вызов NEAR16 PTR bx» также создают одинаковые коды операций.

Вот еще один пример кода, который создает 32-битный код:

.Model small,c ;since cpu instruction is after .Model it causes USE16 to be used
.386
.code
assume ebx:dword
call ebx
end

Поскольку действует use16, это создает 16-битный сегмент, а .386 указывает ему использовать 32-битные инструкции. Когда приведенный выше код собран, он создает коды операций 66 FF D3 для инструкции Call ebx. Инструкции «вызов NEAR PTR ebx», «вызов NEAR32 PTR ebx» или «вызов FAR16 ptr ebx» также создают одинаковые коды операций. Ассемблер распознает, что 386 инструкций используются в 16-битном сегменте, поэтому ассемблер вставляет перед каждой 386 инструкцией 66 в шестнадцатеричном формате. Обратите внимание, что код операции для 16-битной и 32-разрядной версии одинаков, единственное отличие состоит в наличии префикса кода операции. Если был создан 32-битный сегмент и используется 16-битная инструкция, то перед 16-битными кодами операций ставится тот же код префикса 66 в шестнадцатеричном коде. Обратите внимание, что байт префикса есть или нет, это единственная разница. Код префикса операции (66) помещается туда только в том случае, если размер использования сегмента (use16 или use32) не соответствует размеру инструкции процессора (16-бит или 32-бит). Правила должны быть одинаковыми для ASSUME с использованием 16-битных или 32-битных регистров, но их нет в MASM.

person StillLearning    schedule 06.06.2019

Какова цель MASM Assume Directive? отличный обзор использования директивы ASSUME. В былые времена также было обычным делом видеть, что он используется для указания списка регистров сегментов. Это использование в значительной степени устарело на современных процессорах.

person David A. Gray    schedule 25.05.2019
comment
Спасибо Дэвид за ссылку, но она не ответила ни на один из моих вопросов. - person StillLearning; 25.05.2019

После тщательного тестирования я обнаружил «правила» для оператора ASSUME в следующем формате: Регистр ASUME: размер PTR

Разрешенные настройки для "ASSUME reg: PTR {Size}"

Cases where cpu instruction is BEFORE .MODEL or no cpu instruction before .MODEL:

                             |user supplied |  condition
                             |   values     |
                             |  reg  | size |
.286 instruction or less is  |8-bit  | BYTE |can only use BYTE, no PTR     |
before tiny,small or medium  |16-bit | WORD |if <WORD or >WORD requires PTR|
.MODEL or no cpu instruction 
before tiny,small or medium
.MODEL. Causes internal use16. 

                             |user supplied |  condition
                             |   values     |
                             |  reg  | size |
.286 instruction or less is  |8-bit  | BYTE |can only use BYTE, no PTR     |
before compact,large,or huge |16-bit | WORD |can only use WORD, no PTR     |
.MODEL or no cpu instruction 
before compact,large or huge
.MODEL. Causes internal use16. 

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.386 instruction or greater is |8-bit  | BYTE |can only use BYTE, no PTR       |
before tiny,small or medium    |16-bit | WORD |can only use WORD, no PTR       |
.MODEL. Causes internal use32. |32-bit |DWORD |if <DWORD or >DWORD requires PTR|

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.386 instruction or greater is |8-bit  | BYTE |can only use BYTE, no PTR       |
before compact,large,or huge   |16-bit | WORD |can only use WORD, no PTR       |
.MODEL. Causes internal use32. |32-bit |DWORD |if <DWORD or >DWORD requires PTR|

Cases where cpu instruction is AFTER .MODEL 

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.286 instruction or less is    |8-bit  | BYTE |can only use BYTE, no PTR     |
after tiny,small or medium     |16-bit | WORD |if <WORD or >WORD requires PTR|
.MODEL. Causes internal use16. 

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.286 instruction or less is    |8-bit  | BYTE |can only use BYTE, no PTR     |
after compact,large,or huge    |16-bit | WORD |can only use WORD, no PTR     |
.MODEL. Causes internal use16.

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.386 instruction or greater is |8-bit  | BYTE |can only use BYTE, no PTR     |
after tiny,small or medium     |16-bit | WORD |if <WORD or >WORD requires PTR|
.MODEL. Causes internal use16. |32-bit |DWORD |can only use DWORD, no PTR    |

                               |user supplied |  condition  
                               |   values     |
                               |  reg  | size |
.386 instruction or greater is |8-bit  | BYTE |can only use BYTE, no PTR       |
after compact,large,or huge    |16-bit | WORD |can only use WORD, no PTR       |
.MODEL. Causes internal use16. |32-bit |DWORD |if <DWORD or >DWORD requires PTR|

THIS IS THE WAY IT SHOULD BE:

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.286 instruction or less is    |8-bit  | BYTE |can only use BYTE, no PTR     |
before any .MODEL instruction  |16-bit | WORD |if <WORD or >WORD requires PTR|
or no cpu instruction before
.MODEL. Causes internal use16.

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.386 instruction or greater is |8-bit  | BYTE |can only use BYTE, no PTR       |
before any .MODEL instruction. |16-bit | WORD |if <WORD or >WORD requires PTR  |
Causes internal use32.         |32-bit |DWORD |if <DWORD or >DWORD requires PTR|


                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.286 instruction or less is    |8-bit  | BYTE |can only use BYTE, no PTR     |
after any .MODEL instruction   |16-bit | WORD |if <WORD or >WORD requires PTR|
Causes internal use16.

                               |user supplied |  condition
                               |   values     |
                               |  reg  | size |
.386 instruction or greater is |8-bit  | BYTE |can only use BYTE, no PTR       |
after any .MODEL instruction.  |16-bit | WORD |if <WORD or >WORD requires PTR  |
Causes internal use16.         |32-bit |DWORD |if <DWORD or >DWORD requires PTR|
person StillLearning    schedule 03.06.2019