Современные решения

для защиты Windows приложений

и восстановления исходного кода

Разрешение проблем в ассемблере NASM

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

10.1 Общие проблемы

10.1.1 Генерация NASM неэффективного кода

Я получаю много сообщений об ошибках, в которых говорится, что NASM генерирует неэффективный или неверный (при использовании инструкций типа ADD ESP, 8) код. Это преднамеренная особенность дизайна, связанная с предсказуемостью вывода: видя инструкцию типа "ADD ESP, 8", NASM генерирует команду, оставляющую место для 32-битного смещения. Если вы хотите использовать оптимизированную по размеру инструкцию, то должны использовать "ADD ESP, BYTE 8". Это не ошибка, это просто моя точка зрения.

10.1.2 Мои "JUMPы" вне диапазона

Также люди жалуются, что когда они используют переходы по условию (которые являются типа SHORT по умолчанию), которые пытаются перейти слишком далеко, то NASM сообщает "SHORT JUMP OUT OF RANGE", вместо использования более длинного перехода.

Это снова частичная проблема предсказуемости, имеющая также практическую причину. NASM не имеет возможности узнать, для какого типа процессора будет использоваться этот код, так что он не может решить сам использовать переход типа NEAR, потому что не знает, что программа предназначается для процессора 386 и выше. Аналогично, NASM может заменить инструкцию JNE типа SHORT, которая пыталась бы выйти за диапазон, на более короткую команду JE, использующей JUMP NEAR — это разумное решение для процессоров ниже 386, но не эффективное для процессоров, имеющих хорошее предсказание перехода и в состоянии осуществить JMP NEAR. Так что, повторяю — это пользователю, а не ассемблеру решать, какие команды должны быть сгенерированы.

Люди, пишущие загрузочный сектор в двоичном формате, часто жалуются, что ORG работает не так, как им хотелось бы: чтобы поместить сигнатуру 0xAA55 в конец 512-ти байтного загрузочного сектора, те, кто привык к MASM, имеют тенденцию делать следующее

          ORG 0 
          ; код загрузчика 
          ORG 510 
          DW 0xAA55

В NASM ORG не предназначена для этого. Правильный способ заключается в использовании директивы TIMES:

          ORG 0 
          ; код загрузчика 
          TIMES 510-($-$$) DB 0 
          DW 0xAA55

Директива TIMES вставит необходимое количество нулей в код вплоть до 510-го байта. Еще одно преимущество этого метода в том, что если вы выйдете за допустимые размеры загрузочного сектора, то NASM перехватит эту ошибку еще во время ассемблирования и сообщит об этом, так что вам не придется "доводить" программу дизассемблированием и поиском ошибки.

10.1.4 TIMES не работает

Другая обычная проблема с вышеупомянутым кодом бывает у тех, кто пишет

          TIMES 510-$ DB 0

полагая, что $ - это просто число (как и 510), и что разница тоже будет числом и эту разницу можно спокойно преподнести TIMES.

NASM — модульный ассемблер: различные составляющие части разработаны так, чтобы их было легко повторно использовать по отдельности, так что они не обмениваются информацией без необходимости. В последствии, даже зная, что выходной двоичный формат имеет ORG 0 (и секция .text будет начинаться с 0), эта информация не поступит назад к оценщику выражений. Так что, с точки зрения оценщика, $ — не просто число, а адрес, включающий смещение от базы (основы) сегмента. Поэтому разница между $ и 510 тоже будет включать значение смещения от базы сегмента (0х1234:0х5678 вместо 0х5678, например). Значение, включающее смещение, нельзя передавать в качестве параметра директиве TIMES.

Решение можно увидеть в предыдущем примере:

          TIMES 510-($-$$) DB 0

Здесь $ и $$ содержат смещения относительно одного и того же сегмента, так что их разница — простое число. Это решит проблему и будет сгенерирован правильный код.

10.2 Дефекты (ошибки)

Мы пока еще не выпускали ни одной версии NASM с дефектами, о которых мы знаем. Хотя это и не исключает наличия множества таких дефектов, о которых мы просто не знаем. О любом, найденном вами, вы должны сообщить по адресу hpa@zytor.com.

Прежде чем сообщать о дефекте, пожалуйста, внимательно прочитайте параграф 2.2, там перечислены преднамеренно созданные особенности, которые можно принять за ошибки в NASM. (Если же что-то не описано там и кажется вам ошибкой, то будем рады получить ваши подробные комментарии, а не просто письмо типа "Это - ошибка"). После этого прочитайте параграф 10.1, и не сообщайте об ошибке, если она уже там описана.

Если вы создаете отчет об ошибке, пожалуйста, сообщите нам всю нижеследующую информацию:

  • Под какой ОС вы запускаете NASM: DOS, Linux, NetBSD, Win16, Win32, VMS (я бы удивился :) ), какая-то еще.
  • Если вы запустили NASM из-под DOS или Win32, то сообщите, какой из компиляторов вы используете — стандартный из дистрибутива или откомпилированный вами. Если это "ваш" компилятор, то попробуйте воссоздать ошибку на "родном" из дистрибутива. Эта информация поможет нам быстрее исправить ошибку.
  • Какую версию NASM вы используете и подробности того, как вы вызвали сбой. Сообщите нам полностью командную строку и переменные окружения NASM (если есть).
  • Какие версии других программ вы используете и как вы их вызываете. Если сбой возникает во время линковки, то сообщите версию и название компоновщика, его командную строку. Если возникает проблема при линковке с объектным файлом, созданным другим компилятором, то сообщите нам, что за компилятор, версию и командную строку или опции, использованные вами. (Если вы использовали IDE, то попробуйте воспользоваться версией компилятора для командной строки).
  • Если это возможно, то вышлите нам исходный файл, вызывающий ошибку. Если же могут возникнуть проблемы связанные с авторским правом (например, вы можете воспроизвести ошибку в отдельном файле проекта), тогда имейте в виду следующее: во-первых, весь исходный код, высланный к нам, будет использоваться только для обнаружения и исправления ошибки NASM, и мы удалим все копии у себя; во-вторых, мы предпочли бы не получать большие куски кода. Чем меньше файл — тем лучше. Гораздо легче работать с файлом из трех строчек кода, показывающего ошибку, чем с полнофункциональной программой из десятков тысяч строк кода. (Конечно же, некоторые ошибки могут возникнуть в только большем файле, мы это понимаем).
  • Точное описание смысла проблемы. Просто "Это не работает" не сможет помочь! Пожалуйста, объясните точно - что вы хотели получить и не получили (или наоборот - получили то, чего не должно было быть). Например: "NASM показывает ошибку в 3-ей строке, а она в 5-ой"; "NASM сообщает об ошибке, а я уверен, что ее нет"; "NASM не сообщил об ошибке, которая точно есть"; "Объектный файл, созданный из этого кода, не подходит моему компоновщику"; "Девятый байт выходного файла равен 66, а я думаю, что должно быть 77".
  • Если вы уверены, что выходной файл не верен, то пошлите его нам. Это поможет нам определить, создаст ли наша собственная копия NASM такой же файл или проблема в переносимости между нашей платформой разработки и вашей. Мы можем принимать двоичные файлы в виде MIME-прикреплений, формате uuencode и даже BinHex. Так же мы можем предоставить вам ftp-сайт, на который вы сможете загрузить данный файл, но получить его по почте для нас было бы удобней.
  • Любую другую информацию или файлы, которые могут быть полезны. Если, например, проблема в том, что NASM не может сгенерировать объектный файл, в то время, как TASM создает его без проблем, то пошлите нам оба объектных файла, чтобы мы могли увидеть, что делает TASM в отличие от NASM.


Перейти на содержание