|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||||||
| 29.08.2014, 06:27 [ТС] | |||||||||||||||||||||||||||||||||||||||||
|
Так как ассемблер позволяет ссылаться на некоторые метки и константы перед тем, как они фактически определены, приходится прогнозировать значения этих меток и если есть даже подозрение, что прогноз окажется неверным хотя бы один раз, делается еще один проход, ассемблирующий весь код, и в это время делается лучший прогноз, базирующееся на значениях меток, полученных в предыдущий проход. Изменение значений меток может быть причиной того, что некоторые инструкции перекодируются с другими длинами и это снова повлечет изменение меток. И так как метки и константы ещё могут использоваться внутри выражений, которые влияют на поведение директив управления, весь блок инструкций в новый проход может ассемблироваться абсолютно по-другому. Поэтому ассемблер делает проходы снова и снова, каждый раз пытаясь создать лучшие прогнозы, чтобы приблизиться к финальному решению, когда все значения спрогнозированны правильно. Для прогнозов используются разные методы, которые выбираются с тем, чтобы найти с как можно меньшим количеством проходов решение наименьшей возможной длины для большинства программ. О некоторых ошибках, таких как непопадание значений в заданные границе, не сигнализируется во время этих промежуточных проходов, пока может случиться такое, что если какие-то значения будут спрогнозированы лучше, эти ошибки исчезнут сами собой. Однако, если ассемблер встречает какую-то недопустимую синтаксическую конструкцию или неизвестную инструкцию, он всегда останавливается немедленно. Такую же ошибку вызывает определение метки более, чем один раз, так как это делает прогнозы необоснованными. Если в коде встречается директива "display", фактически отображаются только сообщения, созданные в последний совершённый проход. В случае, если ассемблер остановился из-за ошибки, эти сообщения могут отражать спрогнозированные значения, которые еще не разрешены правильно. Разрешение иногда может не создаться и в таких случаях ассемблер никогда не сумеет создать правильные прогнозы - по этой причине существует предел количества походов, и когда ассемблер исчерпает этот лимит, он остановится отобразит сообщение, что невозможно сгенерировать корректный вывод. Рассмотрим следующий пример:
Предыдущий пример может быть создан как попытка определить метку, только если этого все ещё не сделано. Эти строк неправильны, поскольку оператор "defined" проверяет определена ли метка где-либо вообще, и это включает определение внутри этого условного блока. Однако есть способ обойти эту проблему:
Из этого примера вы можете заключить, что прогноз для оператора "defined" очень прямолинейный - метка прогнозируется как определенная только если она была определена в предыдущий проход (а если она была определена в текущий проход, прогноз не требуется). То же самое относится к оператору "used". Однако прогнозы для значений меток не так просты и вам никогда не следует полагать, что ассемблер работает таким способом. Все директивы препроцессора выполняются перед основным ассемблированием, и таким образом директивы управления на них никак не влияют. В это время также удаляются все комментарии. "include" включает указанный файл-исходник туда, где эта директива используется. За ней должно следовать в кавычках имя файла, который должен быть включен, например:
Путь, заключенный в скобки, может содержать окружающие переменные, заключенные в знаки "%", они будут заменены на их значения внутри пути. Знаки "\" и "/" трактуются как разделители пути. Если не указан абсолютный путь, сначала файл ищется в директории, содержащей файл, в который он включается, и, далее, если его там нет, в директории, содержащей главный файл-исходник (указанный в командной строке). Эти правила так же относятся к путям, которые указываются в директиве "file". Символьные константы отличаются от числовых констант тем, что перед процессом ассемблирования они заменяются на их значения во всех строках кода, следующих за их определением, и все может стать их значением. Определение символьных констант состоит из имени константы, за которой следует директива "equ". Все, что следует за этой директивой, станет значением константы. Если значение символьной константы содержит другие символьные константы, они заменяются на их значения перед присвоением значения новой константе. Например:
"restore" позволяет присвоить назад предыдущее значение переопределенной константы. За ней должно следовать одно или больше имен символьных констант, разделенных запятыми. Так, "restore d" после предыдущего переопределения вернет константе значение "edx", следующее применение этой директивы вернет ей значение "dword", а ещё одно применение восстановит первоначальное значение, как будто такая константа не определялась. Если не константа с заданным именем не определена, то "restore" не вызовет ошибку, а будет просто проигнорирована. Символьные константы могут использоваться для адаптации синтаксиса ассемблера к персональным предпочтениям. Например, следующие определения создают удобные ярлыки для всех операторов размера:
Символьные константы могут также быть определены директивой "fix", которая имеет такой же синтаксис, как "equ", но определяет константы высшего приоритета - они заменяются их символическим значением даже перед совершением директив препроцессора и макроинструкций. Исключением является сама директива "fix", которая имеет наивысший возможный приоритет, и поэтому допускает переопределение констант, заданных таким путем. Но если такие константы высшего приоритета находятся внутри значения, следующего за директивой "fix", они заменяются их значениями перед присвоением этого значения новой константе. Директива "fix" может использоваться для адаптирования директив препроцессора, что нельзя сделать директивой "equ". Например:
0
|
|||||||||||||||||||||||||||||||||||||||||
| 29.08.2014, 06:27 | |
|
Ответы с готовыми решениями:
50
Неофициальная разработка Flat assembler версии 2.0.0 Flat assembler ругается на PROC
|
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 29.08.2014, 06:30 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
"macro" позволяет вам определить собственный комплекс инструкций, называемых макроинструкциями. Их использование может существенно упростить процесс программирования. В своей простейшей форме директива похожа на описание символьной константы. Например, следующая строка определяет ярлык для инструкции "test al,0xFF":
Определение макроинструкции может состоять из нескольких строк, потому что знаки "{" и "}" не обязательно должны находиться на одной строке директивой "macro". Например:
Как и инструкции, которым требуются несколько операндов, для макроинструкции можно задать требование нескольких аргументов, разделяя их запятыми. Имена этих аргументов должны следовать за именем макроинструкции на строке с директивой "macro". В любом месте в макроинструкции, где эти имена появятся, они будут заменены соответствующими значениями, указанными там, где макроинструкция используется. Вот пример макроинструкции, которая делает выравнивание данных для двоичного формата вывода:
Если в определении макроинструкции встречается её же имя, то используется предыдущее значение этого имени. Таким образом могут быть сделаны полезные переопределения макросинструкций, например:
Если требуется создать макроинструкцию с аргументом, который содержит запятые, этот аргумент следует заключить между "<" и ">". Если он содержит больше одного знака "<", то для окончания его описания должно быть использовано такое же количество ">". "purge" позволяет отменить последнее определение указанной макроинструкции. За директивой должно следовать одно или больше имен макроинструкций, разделенных запятыми. Если указанная макроинструкция не определена, это не вызовет ошибку. Например, после расширения синтаксиса "mov" вышеуказанными макроинструкциями вы можете отключить синтаксис с тремя операндами, используя директиву "purge mov". Следующее "purge mov" отключит синтаксис для сегментных регистров, а дальнейшее применение этой директивы не возымеет эффекта. Если после директивы "macro" вы заключаете некоторую группу аргументов в квадратные скобки, это позволит при использовании макроинструкции задать данной группе аргументов больше значений. Любой следующий аргумент данный после последнего аргумента данной группы начнет новую группу и станет её первым членом. Поэтому после закрытия квадратных скобок не должно быть имен аргументов. Содержание макроинструкции будет обрабатываться для каждой такой группы аргументов отдельно. Простейший пример - это заключение одного имени аргумента в квадратные скобки:
"forward", "reverse" и "common" делят макроинструкцию на блоки, каждый из которых обрабатывается после окончания обработки предыдущего. Они различаются в поведении только если макроинструкция поддерживает много групп аргументов. Блок инструкций, следующий за "forward" будет обрабатываться для каждой группы аргументов от первой до последней, как блок по умолчанию (без этих директив). Блок, идущий за "reverse" будет обрабатываться для каждой группы аргументов в обратном порядке - от последней до первой. Блок за директивой "common" обрабатывается лишь один раз, просто для всех групп аргументов. Локальное имя, определенное в одном блоке, доступно во всех следующих блоках при обработке той же группы аргументов. Если оно было определено в блоке "common", оно доступно во всех следующих блоках, независимо от обрабатываемой группы. Вот пример макроинструкции, которая создает таблицу адресов строк и следующих за ними строк.
Первая инструкция, следующая за директивой, начинающей блок в макроинструкции, может идти с ней на той же строке, как на следующем примере:
0
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||||||
| 29.08.2014, 06:31 [ТС] | |||||||||||||||||||||||||||||||||||||||||
|
Внутри макроинструкции также может быть использован специальный оператор "#". Этот оператор сцепляет два имени в одно. Это может быть полезно, так как делается после того, как аргументы и локальные имена заменяются на свои значения. Следующая макроинструкция генерирует условный переход в зависимости от аргумента "cond":
Оператор "#" может также использоваться для объединения двух строк, заключенных в кавычки. Возможно преобразование имени в строку в кавычках с помощью оператора "`", который также может быть использован внутри макроинструкции. Он конвертирует следующее за ним имя в строку, заключенную в скобки, но имейте в виду, что если за ним следует аргумент, который заменяется на значение, содержащее больше, чем один символ, будет преобразован только первый из них, так как оператор "`" конвертирует только символ, идущиий непосредственно за ним. Здесь пример использования этих двух свойств:
Чтобы создать макроинструкцию, ведущую себя по-разному в зависимости от типа аргументов, например если это строки в кавычках, вы можете использовать оператор сравнения "eqtype". Вот пример его использования для отделения строки в кавычках от других типов аргументов:
Также возможно объявить макроинструкцию внутри другой макроинструкции, то есть один макрос может определить другой, но с такими определениями есть проблема, вызванная тем, что знак "}" не может появляться внутри макроинструкции, он всегда означает конец его определения. Чтобы обойти эту проблему, можно избавиться от мешающих символов. Это делается путем подстановки одного или больше обратных слэшей перед любыми другими символами (даже специальными знаками). Препроцессор видит эту последовательность как один символ, но каждый раз, когда он видит такой символ во время обработки макроса, он обрезает обратные слэши с его начала. Например, "\{" трактуется как один символ, но во время обработки макроса он станет символом "\{". Это позволит вам определить одну макроинструкцию внутри другой:
Если некоторые директивы, специфические для макроинструкций, такие как "local" или "common", требуются в некотором макросе, включенном таким образом, то их можно избежать таким же путем. Исключение символа больше чем одним обратным слэшем так же поддерживается, это позволяет допустить моножественные уровни вложения определений макросов. Другая техника определения макроинструкций внутри других состоит в использовании директивы "fix", которая становится полезной, когда некоторый макрос только начинает определение другого, без его закрытия. Например:
2.3.4 Структуры "struc" - это специальный вариант директивы "macro", который используется для определения структур данных. Макроинструкции, определенные директивой "struc", когда используются, должны предваряться меткой (как директивы определения данных). Эта метка будет также присоединена к началу каждого имени, начинающегося с точки, в содержании макроинструкции. Макроинструкция, определенная с использованием директивы "struc", может иметь такое же имя, как макросы, определенные с использованием директивы "macro". Структурная макроинструкция не будет мешать обычному макросу, выполняющемуся без метки перед ним и наоборот. Все правила и свойства, касающиеся стандартных макросов, применимы к структурным макроинструкциям. Вот пример структуры:
Если где-то в определении структуры находится имя, состоящие из одной лишь точки, оно заменяется на имя метки для данного примера структуры и эта метка таким образом не будет определена автоматически, позволяя полностью задать определение. Следующий пример использует это свойство, чтобы расширить определение директивы "db" с возможностью вычисления размера определяемых данных:
Определение структур данных, адресованных регистрами или абсолютными значениями может быть сделано структурными макроинструкциями с использованием директивы "virtual" (смотрите 2.2.3). "restruc" удаляет последнее определение структуры, так же как "purge" делает с макросами и "restore" с символьными константами. Директива имеет тот же синтаксис - за ней должно следовать одно или несколько имен структурных макросов, разделенных запятыми.
0
|
|||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
| 29.08.2014, 06:31 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||
|
2.3.5 Повторение макроинструкций Директива "rept" - это специальный вид макроинструкций, который делает заданное число дубликатов блока, заключенного в фигурные скобки. Простой синтаксис - число, следующее за "rept" (это не может быть выражение, так как препроцессор не совершает вычисления, если вам нужны повторения, базирующиеся на выражениях, вычисленных ассемблером, используйте одну из директив, обрабатываемых ассемблером, смотрите 2.2.2), и блок кода, заключенный между знаками "{" и "}". Простейший пример:
Итак, такой макрос:
"irp" итерирует один аргумент через данный список параметров. Синтаксис такой: за "irp" следует имя аргумента, далее запятая и далее список параметров. Параметры определяются таким же образом, как в вызове стандартного макроса, то есть они должны разделяться запятыми и каждый может быть заключен между знаками "<" и ">". Так же за именем аргумента может следовать "*" для обозначения того, что он не может иметь пустое значение. Такой блок:
0
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
| 01.09.2014, 06:00 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||
|
При применении директивы "match" некоторый блок кода обрабатывается препроцессором и передается ассемблеру, только если заданная последовательность символов совпадает с образцом. Образец идет первым, заканчивается запятой, далее идут символы, которые должны подходить под образец, и далее блок кода, заключенный в фигурные скобки, как макроинструкция. Есть несколько правил для построения выражения для сравнения, первое - это любые символьные знаки и строки в кавычках должны соответствовать абсолютно точно. В этом примере:
Чтобы соответствовать любому другому символу буквально, он должен предваряться знаком "=" в образце. Также чтобы привести в соответствие сам знак "=", или запятую должны использоваться конструкции "==" и "=,". Например, образец "=a==" будет соответствовать последовательности "a=". Если в образце стоит некоторый символ имени, он соответствует любой последовательности, содержащей по крайней мере один символ и его имя заменяется на поставленную в соответствие последовательность везде в следующем блоке, аналогично параметрам в макроинструкции. На пример:
Блок кода, определенный директивой "match" обрабатывается так же, как любая макроинструкция, поэтому здесь могут использоваться любые операторы, специфичные для макроинструкций. Что делает директиву "match" очень полезной, так это тот факт, что она заменяет символьные константы на их значения в поставленной в соответствие последовательности символов (то есть везде после запятой до начала блока кода) перед началом сопоставления. Благодаря этому директива может использоваться, например, для обработки некоторого блока кода в зависимости от выполнения условия, что данная символьная константа имеет нужное значение, например:
При сочетании разных свойств препроцессора важно знать порядок, в котором они обрабатываются. Как уже было отмечено, высший приоритет имеет директива "fix" и замены, ею определенные. Это полностью делается перед совершением любого другого препроцессинга, поэтому такой кусок кода:
Стандартный препроцессинг, который начинается после, на каждой строке начинается с распознавания первого символа. Сначала идет проверка на директивы препроцессора, и если ни одна из них не опознана, препроцессор проверяет, является ли первый символ макроинструкцией. Если макроинструкция не найдена, препроцессор переходит ко второму символу на строке, и снова начинает с проверки на директивы, список которых в этом случае ограничивается лишь "equ", так как только она может оказать вторым символом на строке. Если нет директивы, второй символ проверяется на структурную макроинструкцию, и если ни одна из этих проверок не дала положительного результата, символьные константы заменяются на их значения, и строка передается ассемблеру. Продемонстрируем это на примере. Пусть "foo" - это макрос, а "bar" - это структура. Эти строки:
Макроинструкции генерируют новые строки от их блоков определения, заменяя параметры на их значения и далее обрабатывая операторы "#" и "`". Оператор конверсии имеет высший приоритет, чем оператор сцепления. После завершения этого, заново сгенерированная строка проходит через стандартный препроцессинг, как описано выше. Хотя обычно символьные константы заменяются исключительно в строках, нет ни директив препроцессора, ни макроинструкций, встречается несколько особых ситуаций, где замены проводятся в частях строк, содержащих директивы. Первая - это определение символьной константы, где замены производятся везде после слова "equ" и результирующее значение присваивается новой константе (смотрите 2.3.2). Вторая такая ситуация - это директива "match", где замены производятся в символах, следующих за запятой перед сопоставлением их с образцом. Эти свойства могут использоваться, например, для сохранения списков, как,например, эта совокупность определений:
Есть ещё один особый случай - когда препроцессор собирается проверить второй символ и натыкается на двоеточие (что далее интерпретируется асемблером как определение метки), он останавливается в этом месте и заканчивает препроцессинг первого символа (то есть если это символьная константа, она развертывается) и если это все еще выглядит меткой, совершается стандартный препроцессинг, начиная с места после метки. Это позволяет поместить директивы препроцессора и макроинструкции после меток, аналогично инструкциям и директивам, обрабатываемым ассемблером, например:
0
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||||||||||||||||||||||
| 01.09.2014, 06:02 [ТС] | ||||||||||||||||||||||||||
|
"format" со следующим за ним идентификатором формата позволяет выбрать формат вывода. Эта директива должна стоять в начале кода. Формат вывода по умолчанию - это простой двоичный файл, он может быть также выбран директивой "format binary". "use16", "use32" и "use64" указывают ассемблеру генерировать 16-/32-битный или 64-битный код, пренебрегая настройкой по умолчанию для выбранного формата вывода. "use64" включает генерирование кода для длинного режима (long mode) процессоров x86. Ниже описаны разные форматы вывода со специфичными для них директивами. Чтобы выбрать формат вывода MZ, используйте директиву "format MZ". По умолчанию код для этого формата 16-битный.
Чтобы выбрать формат вывода PE, используйте директиву "format PE", за ней могут следовать дополнительные настройки формата: используйте "console", "GUI" или оператор "native", чтобы выбрать целевую субсистему (далее может следовать значение с плавающей точкой, указывающее версию субсистемы), "DLL" помечает файл вывода как динамическую связывающую библиотеку. Далее может следовать оператор "at" и числовое выражение, указывающее базу образа PE и далее опционально оператор "on" со следующей за ним строкой в кавычках, содержащей имя файла, выбирающей заглушку MZ для PE программы (если указанный файл не в формате MZ, то он трактуется как простой двоичный исполняемый файл и конвертируется в формат MZ). По умолчанию код для этого формата 32-битный. Пример объявления формата PE со всеми свойствами:
"stack" устанавливает размер стека для PE, далее должно следовать значение зарезервиронного размера стека, опционально может следовать отделенное запятой значение начала стека. Если стек не определен, ему присваивается размер по умолчанию, равный 4096 байт. "heap" выбирает размер дополнительного места для PE, далее должно следовать значение для зарезервированного для него места, опционально ещё может быть значение его начала, отделенное запятой. Если дополнительное место не определено, оно ставится по умолчанию равным 65536 байт, если не указано его начало, то оно устанавливается равным 0. "data" начинает определение специальных данных PE, за директивой должен следовать один из идентификаторов данных ("export", "import", "resource" или "fixups") или номер записи данных в заголовке PE. Данные должны быть определены на следующих строках и заканчиваться директивой "end data". Если выбрано определение настроек адресов, они генерируются автоматически, и никаких данных определять больше не требуется. То же самое относится к ресурсам, если за идентификатором "resourse" следует оператор "from" и имя файла в кавычках - в этом случае данные берутся из этого файла ресурсов. Чтобы выбрать COFF (Common Object File Format), используйте директиву "format COFF" или "format MS COFF", если вы хотите создать классический мелкософтофский файл COFF. По умолчанию код для этого формата 32-битный. Чтобы создать микросФтовский формат COFF для архитектуры x86-64, используйте установку "format MS64 COFF", в этом случае автоматически будет генерироваться код длинного режима.
Чтобы выбрать формат вывода ELF, используйте директиву "format ELF". По умолчанию код для этого формата 32-битный. Чтобы создать формат ELF для архитектуры x86-64, используйте установку "format ELF", в этом случае автоматически будет генерироваться код длинного режима. "section" определяет новую секцию, за директивой должна следовать строка в кавычках, определяющая имя новой секции, и ещё может следовать один или оба флага "executable" и "writeable", опционально также может идти оператор "align" со следующим за ним числом, определяющим выравнивание секции (это должна быть степень двойки), если выравнивание не указано, используется значение по умолчанию, которое равно 4 или 8, в зависимости от варианта выбранного формата. "extrn" и "public" имеют те же значения и синтаксис у них, как в случае формата COFF (описанного в предыдущем параграфе). Чтобы создать исполняемый файл, придерживайтесь директивы выбора формата со словом "executable".Это позволяет использовать директиву "entry" со следующим за ним значением, чтобы создать точку входа в программу. С другой стороны это делает недоступными директивы "extrn" и "public". За директивой "section" в этом случае может следовать только один или более флагов секций и начало секции будет выровнено по странице (4096 байт). Доступные флаги секций такие: "readable", "writable" и "executable".
0
|
||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 01.09.2014, 06:02 [ТС] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Версия FASM'а для Windows включает пакет стандартных файлов разработанных, чтобы помочь создавать программы для Windows. Этот пакет содержит заголовочные файлы для программирования под Win32/Win64 находящиеся в корневой папке а также спецализированные файлы находящиеся в поддиректориях. Вообще, заголовочные файлы Win32 включают все требуемые специализированные файлы для Вас, хотя иногда Вы могли бы предпочесть включать часть макросов самостоятельно (так как некоторые из них не включены в заголовочные файлы). Есть двенадцать заголовочных файлов Win32/Win64, которые Вы можете выбрать , с названиями, начинающимися с "win32/win64", и продолжающихся символом "a" чтобы использовать кодирование ASCII, или символом "w" для Unicode. win32a.inc, win32w.inc, win64a.inc и win64w.inc ― основные заголовочные файлы, win32ax.inc, win32wx.inc, win64ax.inc и win64wx.inc ― расширенные заголовочные файлы, они содержат более расширенные макросы, эти расширения будут обсуждены отдельно. Наконец win32axp.inc, win32wxp.inc, win64axp.inc и win64wxp.inc ― те же самые расширенные заголовочные файлы с особенностью проверки параметров при вызовах процедур. Вы можете включить заголовочные файлы, любым путем которые предпочитаете, указывая полный путь или используя переменную окружения, но самый простой метод состоит в том, чтобы определить переменную окружения INCLUDE, должным образом указывающую на каталог, содержащий заголовочные файлы и затем включить их например:
Основные заголовочные файлы win32a.inc, win32w.inc, win64a.inc и win64w.inc включают константы и структуры Win32/Win64 и обеспечивают стандартный набор макросов. Все заголовки допускают макрос "struct", который позволяет определять структуры более традиционно, подобно другим ассемблерам чем "struc" директива. Определение структуры должно быть начато с макроинструкции "struct" , сопровождаемой именем, и заканчиваться "ends". В строках определения структуры разрешены только метки, являющимися названиями для ее членов:
Сами структуры также могут быть в определениях структуры, так что структуры могут содержать некоторые другие структуры как члены:
Так как значение для каждого члена ― отдельный параметр в объявлении структуры, при инициализации вложенной структуры параметры для каждой из них должны быть сгруппированы в отдельную группу например:
Когда структура инициализируется данными меньшими чем размер соответствующего члена, она дополняется до размера неопределенными байтами (а когда большими, случается ошибка). Например:
В структурах также могут быть определены "union" ― объединения а также безымянные вложенные структуры. Определение объединения должно начаться с "union" и оканчиваться "ends", например:
Безымянные вложенные структуры объявляются также как "union", только начинаются со строки "struct" например:
Вложенные структуры и объединения могут быть вложены без пределов для глубины вложения:
0
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 01.09.2014, 06:04 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Макросы импорта помогают формировать данные импорта для PE файла (обычно составляющие отдельную секцию). Есть два макроса для этой цели.
Вместо символьной строки для названия процедуры, можно задать номер, чтобы определить импорт по ординалу, например:
Есть четыре макроинструкции для того, чтобы вызывать процедуры с параметрами, переданными в стек.
Название процедуры может также сопровождаться stdcall или ключевым словом, которое определит используемое соглашение о вызовах. Когда никакой такой тип не определен, значение по умолчанию используется, которое является эквивалентным STDCALL. Также ключевое слово uses может следовать, и после него, список регистров (разделенных пробелами), которые будут автоматически сохранены на входе в процедуру и восстановлены на выходе. В этом случае должна быть запятая между списком регистров и первым параметром. Так что полностью показанная инструкция процедуры могла бы выглядеть следующим образом:
ret помещенный где-нибудь в процедуре, генерирует заключительный код, необходимый, чтобы правильно выйти из процедуры, восстанавливая стековый фрейм и регистры, используемые процедурой. Если Вы должны произвести инструкцию возврата из подпрограммы, используйте мнемонику retn или ret с числовым операндом, что также заставляет это интерпретироваться как единственная инструкция. Полное определение процедуры может выглядеть следующим образом:
0
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 01.09.2014, 06:04 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
In 64-bit Windows there is only one calling convention, and thus only two macroin- structions for calling procedures are provided. The fastcall calls directly the proce- dure specified by the first argument using the standard convention of 64-bit Windows system. The invoke macro does the same, but indirectly, through the pointer labelled by the first argument. Parameters are provided by the arguments that follow, and they can be of any size up to 64 bits. The macroinstructions use RAX register as a temporary storage when some parameter value cannot be copied directly into the stack using the mov instruction. If the parameter is preceded with addr word, it is treated as an address and is calculated with the lea instruction ― so if the address is absolute, it will get calculated as RIP-relative, thus preventing generating a relocation in case of file with fixups. Because in 64-bit Windows the floating-point parameters are passed in a dierent way, they have to be marked by preceding each one of them with float word. They can be either double word or quad word in size. Here is an example of calling some OpenGL procedures with either double-precision or single-precision parameters:
It is possible to create a custom code for procedure framework when using proc macroin- struction. There are three symbolic variables, prologue@proc, epilogue@proc and close@proc, which define the names of macroinstructions that proc calls upon entry to the procedure, return from procedure (created with ret macro) and at the end of proce- dure (made with endp macro). Those variables can be re-defined to point to some other macroinstructions, so that all the code generated with proc macro can be customized. Each of those three macroinstructions takes five parameters. The first one provides a label of procedure entry point, which is the name of procedure aswell. The second one is a bitfield containing some ags, notably the bit 4 is set when the caller is supposed to restore the stack, and cleared otherwise. The third one is a value that specifies the number of bytes that parameters to the procedure take on the stack. The fourth one is a value that specified the number of bytes that should be reserved for the local variables. Finally, the fifth an last parameter is the list of comma-separated registers, which procedure declared to be used and which should therefore be saved by prologue and restored by epilogue. The prologue macro apart from generating code that would set up the stack frame and the pointer to local variables has to define two symbolic variables, parmbase@proc and localbase@proc. The first one should provide the base address for where the parameters reside, and the second one should provide the address for where the local variables reside ― usually relative to EBP/RBP register, but it is possible to use other bases if it can be ensured that those pointers will be valid at any point inside the procedure where parameters or local variables are accessed. It is также up to the prologue macro to make any alignments necessary for valid procedure implementation; the size of local variables provided as fourth parameter may itself be not aligned at all. The default behavior of proc is defined by prologuedef and epiloguedef macros (in default case there is no need for closing macro, so the close@proc has an empty value). If it is needed to return to the defaults after some customizations were used, it should be done with the following three lines:
The 64-bit headers provide an additional set of prologue/epilogue macros, which allow to define procedure that uses RSP to access parameters and local variables (so RBP register is free to use for any other by procedure) and также allocates the common space for all the procedure calls made inside, so that fastcall or invoke macros called do not need to allocate any stack space themselves. It is an eect similar to the one obtained by putting the code inside the procedure into frame block, but in this case the allocation of stack space for procedure calls is merged with the allocation of space for local variables. The code inside such procedure must not alter RSP register in any way. To switch to this behavior of 64-bit proc, use the following instructions:
Макроинструкция export создает экспорт данных для PE файла (она должно быть помещена в раздел, отмеченный как export, или в пределах блока экспорта данных). Первый параметр должен быть символьная строка, определяющая название библиотечного файла, а остальное должно быть парами параметров, сначала в каждой паре название процедуры, определенной где-нибудь в исходнике, и потом символьная строка, содержащей название, под которым эта процедура должна экспортироваться библиотекой. Этот пример
Макрос interface позволяет объявлять интерфейс для объекта типа СОМ, первый параметр ― название интерфейса, и затем последовательность из имен методов, как в этом примере:
Вы можете также использовать название интерфейса COM тем же самым способом как название структур, объявляя переменную, которая будет содержать хендл объекта данного типа например:
0
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 01.09.2014, 06:06 [ТС] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Есть два способа создать ресурсы, первый ― Вы должны включить внешний файл, сделанного любым компилятором ресурсов например:
макроинструкция directory должна быть помещена непосредственно в начале вручную написанных ресурсов, и это определит, какие типы ресурсов используются. Это должно сопровождаться парами значений, первый в каждой паре, является идентификатором типа ресурса, а второй метка подкаталога ресурсов данного типа. Это может выглядеть следующим образом:
Для определения ресурсов различных типов есть специализированные макроинструкции, которые должны быть помещены в секции ресурсов Точечные рисунки ― ресурсы с идентификатором типа RT_BITMAP. Объявляя растровый ресурс используют макроинструкцию bitmap с первым параметром, являющейся меткой ресурса (соответствующей входу в подкаталоге точечных рисунков) и вторым параметром символьной строкой, содержащей путь к bmp-файлу, например:
Курсоры объявляют очень похожим способом на значки, на сей раз с типами RT_GROUP_CURSOR и RT_CURSOR и макроинструкцией cursor, которая берет параметры, аналогичные принимаемые макрокомандой icon. Так что определение курсора может выглядеть следующим образом:
Дополнительный третий параметр menuitem определяет флажки ресурса меню. Есть два таких флажка
dialog может взять до одиннадцати параметров, минимум требуется семь.
Ресурсы типа RT_ACCELERATOR создаются с макроинструкцией accelerator. Первый параметр, традиционно является меткой ресурса, далее должны следовать за три параметра ― флажки акселератора, сопровождаемые кодом виртуальной клавиши или символом ASCII и значением идентификатора (который подобен идентификатору пункта меню). Простое определение акселератора может выглядеть следующим образом:
0
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||||||||||||||||||||||||||||||||||||||||||
| 01.09.2014, 06:06 [ТС] | ||||||||||||||||||||||||||||||||||||||||||||||
|
Макросы ресурсов используют du директиву, чтобы определить любые строки Unicode в ресурсах . Так как эта директива просто расширяет символы, обнуляя 16-разрядные значения, для строк содержащих некоторые символы не ASCII, du возможно, должна быть переопределена. Для части кодировок макросы, переопределяющие du, чтобы генерировать тексты должным образом в Unicode находятся в подкаталоге ENCODING. Например, если исходный текст закодирован с кодовой страницей Windows 1251 (русская кодовая страница в Windows), такая строка должна быть помещена где-нибудь в начале источника:
Расширенные заголовочные файлы win32ax.inc, win32wx.inc, win64ax.inc и win64wx.inc обеспечивают все функциональные возможности основных и включают еще несколько особенностей, вовлекающих более сложные макрокоманды. Также, если формат PE не объявлен прежде, чем включены расширенные заголовочные файлы, то они объявляют это автоматически. win32axp.inc, win32wxp.inc, win64axp.inc и win64wxp.inc ― варианты расширенных заголовочных файлов которые дополнительно выполняют проверку количества параметров при вызовах процедур. С расширенными заголовочными файлами макросы позволяют вызывать процедуры с большими типами параметров а не только с двойными словами. Прежде всего, когда символьная строка ― передается как параметр для процедуры, это используется, чтобы определить строковые данные, размещенные среди кода, и передать процедуре указатель на эту строку. Это позволяет легко определять символьные строки которые не должны многократно использоваться только в строке вызывающей процедуру которая требует указателей на эти строки, например:
Если параметру предшествует слово addr это означает, что это значение ― адрес двойного слова, и этот адрес нужно передать процедуре, даже если это не может быть сделано непосредственно ― как в случае локальных переменных, которые имеют адреса относительно регистра EBP, в таком случае, регистр EDX используется временно, чтобы вычислить значение адреса и передать его процедуре. Например:
Если параметру предшествует слово double, это будет обработано как значение на 64 бита и передано процедуре как два 32-разрядных параметра. Например:
Наконец, вызовы процедур могут быть вложены, когда одна процедура может использоваться как параметр для другой. В таком случае значение, возвращенное вложенной процедуре в EAX передают как параметр для процедуры, которая ее содержит. Пример такого вложения:
Расширенные заголовочные файлы включают некоторые макроинструкции, которые помогают с простым структурированием в программе. .data и .code ― только ярлыки для объявления разделов для данных и для кода. Макрос .end должен быть помещен в конце программы, с одним параметром, определяющим точку входа программы, и это также автоматически сгенерирует раздел импорта, используя все стандартные таблицы импорта. Макрос .if генерирует часть кода, который проверяет некоторое простое условие во время выполнения, и в зависимости от результата продолжает выполнение следующего блока или пропускает его. Блок должен быть закончен .endif, но ранее также макрос .elseif может использоваться один или более раз и начинать код, который будет выполнен при некотором дополнительном условии, когда предыдущие условия не были выполнены, и .else как последний блок перед .endif, который будет выполнен, когда все условия были ложные. Другой способ определить условие состоит в том, чтобы обеспечить два значения и оператор сравнения между ними ― один из =,<,>, <=, >=, и <>. Значения сравниваются как беззнаковое. Также, если Вы запишете только единственное значение как отдельный параметр, это будет проверено, на равенство нулю, и условие будет истинно, только если это не ноль. For example:
The simple conditions like above can be composed into complex conditional expressions using the &, | operators for conjunction and alternative, the ~ operator for negation, and parenthesis. For example:
Макрос .while генерирует команды, которые повторят выполнение данного блока (заканчивающегося .endw), пока условие истинно. Условие должно следовать за .while и может быть определено тем же самым способом что и для .if. Пара макроинструкций .repeat и .until определяет блок, который будет выполняться неоднократно, пока данное условие не будет выполнено ― на сей раз условие должно следовать за .until макрокомандой, помещенной в конце блока, подобно:
1
|
||||||||||||||||||||||||||||||||||||||||||||||
| 01.09.2014, 06:06 | |
|
Помогаю со студенческими работами здесь
51
Flat Assembler Ошибка в flat assembler flat assembler массив Массив в Flat Assembler Как использовать Flat Assembler в Free Pascal? Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта
Симптом:
После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
|
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
|
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
|
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут.
В век Веб все очень привыкли к дизайну Single-Page-Application .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|