Что такое макросы в MASM? - PullRequest
0 голосов
/ 06 января 2019

Почему в коде ниже используется макрос? Я не понимаю понятие макроса

Это код, который преобразует десятичную строку в восьмеричную строку (путем преобразования в / из целого числа):

prnstr macro msg
   mov ah, 09h
  lea dx, msg
   int 21h
endm

data segment
 buf1 db "Vuvedete desetichno chislo: $"
 buf2 db 0ah, "Nevalidno chislo...$"
 buf3 db 0ah, "Chisloto v osmichna broina sistema e : $"
 buf4 db 6
 db 0
 db 6 dup(0)
 multiplier db 0ah
data ends

code segment
assume cs:code, ds:data

start :
 mov ax, data
 mov ds, ax
 mov es, ax

 prnstr buf1
 mov ah, 0ah
 lea dx, buf4
 int 21h

 mov si, offset buf4 + 2
 mov cl, byte ptr [si-1]
 mov ch, 00h

subtract :

mov al, byte ptr [si]
cmp al, 30h
jnb cont1
prnstr buf2
 jmp stop
cont1 :

cmp al, 3ah
jb cont2
prnstr buf2
jmp stop
cont2 :

sub al, 30h
mov byte ptr [si], al
inc si
loop subtract

mov si, offset buf4 + 2
mov cl, byte ptr [si-1]
mov ch, 00h
mov ax, 0000h

calc :
mul multiplier
mov bl, byte ptr [si]
mov bh, 00h
add ax, bx
inc si
loop calc

mov si, offset buf4 + 2
mov bx, ax
mov dx, 0000h
mov ax, 8000h

convert :
mov cx, 0000h
conv :
 cmp bx, ax
 jb cont3
 sub bx, ax
 inc cx
jmp conv
cont3 :

   add cl, 30h
  mov byte ptr [si], cl
  inc si
  mov cx, 0008h
  div cx
  cmp ax, 0000h
 jnz convert

 mov byte ptr [si], '$'
prnstr buf3
prnstr buf4+2
stop :
 mov ax, 4c00h
 int 21h

code ends
end star

1 Ответ

0 голосов
/ 06 января 2019

Из Руководства программиста MASM 6.1:

A macro - это символическое имя, которое вы даете серии символов (a текстовый макрос) или одному или нескольким операторам (процедура макроса или функция).

Когда каждый раз, когда вы используете макрос в коде, как вы пишете prnstr buf2 в какой-то строке, он будет заменен на этапе сборки инструкциями из определения макроса, то есть, как вы бы написали в оригинальном источнике три строки :

   mov ah, 09h
   lea dx, buf2    ; argument `msg` was replaced by `buf2` value
   int 21h

Таким образом, хороший макрос избавит вас от необходимости набирать текст и может несколько помочь с удобочитаемостью исходного кода.

Теперь я обычно не одобряю использование макросов в сборке, особенно новичками, и я попытаюсь объяснить причины этого в следующем тексте, но приведенная выше часть является ответом на ваш вопрос, и если это не так ответьте на свой вопрос, дайте мне знать в комментариях.

Макросы несколько запутывают машинный код, который будет сгенерирован, когда вы выполняете проверку кода какого-либо источника, и вы видите prnstr buf2, вы должны открыть также определение макроса, чтобы просмотреть, имеет ли смысл сгенерированный код в целом, т. е. если код не ожидал сохранения, например, значения в dx, а затем более поздний программист добавил prnstr, забыв, что он изменяет значение dx. Так что обзор становится более громоздким.

Эта тема продолжается и в отладчике, в отладчике вы видите разобранный фактический машинный код, поэтому вы увидите все эти настоящие инструкции вместо оригинального макроса, использованного в исходном коде. Что может затруднить быстрое понимание того, где вы находитесь (в исходном коде), какую часть вы отлаживаете и откуда пришли инструкции. Кроме того, если конкретная макро-инструкция не подходит и вам нужно «исправить» код, это может быть немного сложнее, чем изменение фактической инструкции в коде (поскольку любое изменение в макросе будет распространяться и на все другие места, где используется).

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

Наконец, макросы являются особенностью конкретного ассемблера (если поставщик ассемблера намеренно не пытается быть совместимым с другим вендором, например, TASM способен компилировать почти все источники MASM и использует его в промо-текстах как «точку продажи»), в то время как инструкции определяются центральным процессором, поэтому в случае, если на вашей целевой платформе (CPU + OS) имеется много конкурирующих ассемблеров, источники без макросов могут быть более совместимыми между различными ассемблерами (хотя часто есть и небольшие кусочки несовместимости синтаксиса, делающие «портирование» "задача, требующая ручного редактирования исходного кода любым способом).

Конкретный prnstr кажется мне разумным, хотя, если бы я приводил какой-то пример для начинающих, я бы все-таки писал эти инструкции каждый раз в коде - он используется 5 раз, 5 + 5 строк против 5x3 = 15 строк = источник всего на 5 строк короче, IMO не стоит, так как «написание кода» обычно составляет всего около 10-20% времени разработки и экономии на записи, что также не спасает чтение / просмотр кода и исправление ошибок + обслуживание (эти две часто в разы больше времени разработки, чем написание), в конце концов, ухудшает ситуацию.

Распространенный шаблон использования макросов (неправильных) для начинающих - принимать их за процедуры. Для процедур процессор x86 имеет встроенную поддержку в виде инструкций, таких как call и ret, поэтому в случае более длинных фрагментов кода вы можете использовать их вместо макросов, что делает чтение кода немного легче, как в каждом x86 asm-кодер должен знать их, и они видны при разборке в отладчике так же, как был написан источник.

Теперь макросы - это, конечно, большая часть того, что делает MASM отличным инструментом для программистов, поэтому они, безусловно, также имеют свои преимущества:

  • производительность по сравнению с вызовом процедуры ... пара инструкций call+ret требует крошечного времени для выполнения, в то время как макрос вводит инструкции непосредственно в исходный поток. Если мы говорим о каком-то интенсивном коде внутреннего цикла, выполняемом миллионы раз в секунду, то макрос вместо call может иметь какое-то измеримое значение, иногда делая результат лучше (или хуже). Но в других случаях это беспокойство бессмысленно в современных x86, поскольку они будут выполнять call/ret в течение минимального времени, а более короткий двоичный файл может принести преимущества не столько засорения кэша команд, сколько раздутого расширенного кода.

  • хороший способ создания разных вариантов кода для разных типов сборок. Вы можете скрыть в макросе, например, другую логику кода LOG(..), будучи пустым в производственном процессе, но создавая журнал отладки в сборках отладки или помещая третий аргумент для вызовов процедур в rcx или rdx, в зависимости от целевой архитектуры и т. Д. ...

  • использование новых командных кодов команд (пока не поддерживается ассемблером) удобным способом

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

Опять же, если вам нужен язык ассемблера сегодня, он чаще всего нужен для настройки производительности. Это означает переписать крошечный кусочек другого кода, написанного на языке программирования высокого уровня, обрабатывающего большой объем данных (узкое место, обнаруженное при профилировании исходного кода), и в этот момент вам обычно не нужны какие-либо функции «среднего уровня», поскольку вам нужно просто точно создать «горячую» часть кода внутреннего цикла, возможно, размером в несколько десятков / сотен строк сборки, и соединить ее с исходным кодом, и вы, вероятно, не найдете интенсивного использования макросов в такой случай.

Я также могу представить множество случаев, когда макросы могли бы помочь (если вы, например, пишете несколько микропроцессоров, и каждый цикл тестирования имеет определенные идентичные части, но вы не хотите, чтобы они были частью «процедуры», тогда макросы идеально подходят) и т.д ...

Но если вы только изучаете основы сборки, вам вообще не нужны макросы, а просто потратьте время на изучение теории компьютерных архитектур и изучение самой сборки.

...