|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||||||||||||||||||||||||||||||||||||
| 25.06.2013, 15:16 [ТС] | ||||||||||||||||||||||||||||||||||||||||
|
Графика в DOS. Эффект след от водомерки на поверхности воды Этап первый
Этап второй . Усложняем программу. Теперь у нас водомерка на поверхности воды и след от рыбы, которая пытается поймать водомерку
Заключительный этап Довольно загадочный, для непосвященных, но простой, эффект. В основе лежит, все тот же Blur. Я выбрал 8-пиксельный блюр, так как он дает более красивую картинку.Установим палитру так:
Далее описывается последовательность, которую надо проделать, для расчета очередного кадра:
Как же нам добиться эффекта искажения, из-за преломления лучей света на границе двух разнородных сред? Сейчас подумаем. Берем в руки учебник физики, ищем раздел "Оптика" и находим формулу расчета угла преломленного луча. Применив знания, полученные на уроках геометрии, выведем формулу, с помощью которой будем находить смещение, относительно текущего пикселя, по которому находиться пиксель, который и надо вывести на экран вместо текущего:
Нужно искать тангенс арксинуса синуса, да еще расчет нормали к поверхности, плюс это надо разложить на нахождение смещения по X и Y, сложновато... ![]() Конечно, можно воспользоваться табличным разложением, но таблица получиться слишком уж большой. Как же быть? Взглянем еще раз на нашу формулу и подумаем, нельзя ее как нибудь сократить. Допустим, что наш тангенс арксинуса синуса, есть величина величина постоянная и равная, например 0.25. (Воспользуемся калькулятором). Опыт показал, что такое допущение вполне возможно, если ширина волны небольшая. Тогда формула значительно упроститься и будет выглядеть так: D=h/4 Теперь, чтобы найти координаты нужного пикселя, надо прибавить к текущим, D:x'=x+D; y'=y+D; В наш алгоритм добавиться пункт 2.5.2.5. Делим результат на 4, полученное значение прибавляем к текущим X и Y. Если X, больше максимально допустимого значения, то X приравняем максимальному допустимому значению. Аналогичную проверку надо сделать и для Y. Считываем по этим координатам из массива pics, число и записываем по текущим координатам в screen_end. Теперь модифицируем этот алгоритм чтобы получить более реалистичное изображение. Недостаток описанного выше метода - смещение не зависит от наклона нормали к поверхности воды. Как исправить этот недостаток, не усложняя алгоритм? Довольно просто. Достаточно знать куда наклонена нормаль, тогда сможем смещать координаты в соответствии с этим направлением. Для того чтобы найти смещения по x и y, используем следующие формулы:
4
|
||||||||||||||||||||||||||||||||||||||||
| 25.06.2013, 15:16 | |
|
Ответы с готовыми решениями:
65
Организация тем в разделе Assembler, MASM, TASM Полезные макросы для MASM и TASM |
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||
| 25.06.2013, 15:16 [ТС] | ||||||
|
Графика DOS. Падающий снег в 3D Размер COM-файла 187 байт. Во вложении исходный текст и СОМ-файл
3
|
||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||
| 25.06.2013, 15:16 [ТС] | ||||||
|
Графика в DOS. Эффект RADIAL BLUR Если вы захотите подставить какую-нибудь другую картинку, то проделайте следующую последовательность действий:
intel.bmp Выберем центр нашего блюра, пусть это будет, для простоты, центр экрана. Допустим разрешение экрана 320x200. Тогда центр экрана придется на точку с координатами (160,100). Сместим начало координат в эту точку: x'=x-160; y'=y-100. Теперь рассмотрим точку М с координатами, например, (185,65), эта точка будет нашей текущей точкой, на примере ее я расскажу как выбирать вторую точку, чтобы сблюрить их цвета. Координаты в нашей новой системе координат, у этой точки будут M'(25,-35). Вектор этой точки тоже будет иметь координаты (25,-35). Теперь надо решить, как находить вектор, по которому мы будем находить вторую точку. Есть два варианта:
Вычислим по ней координаты вектора N, округляя до целого: N.x= 4, N.y= -6. Тогда координаты искомой точки P будут находиться так: P(x'-N.x,y'-N.y). То есть, P(21,-29). Теперь осталось сблюрить точки M и P, и записать получившиеся значение в точку M. Осталось рассказать в каком порядке надо обрабатывать точки, чтобы получить правильное, радиально-сблюренное изображение. Разобьем экран на четыре сектора: Рассмотрим сектор #1: По такому же принципу надо поступать и в других секторах: обрабатывать сектор по строкам, начиная с ближней к центру блюра, а в строке тоже двигаться от центра блюра. Естественно, линии с координатами центра блюра надо тоже обработать. Ну вот и все, загляните в прилагаемые исходники, что бы посмотреть, как можно прооптимизировать этот эффект. Взято здесь, текст программы немного переделан, в результате СОМ-файл уменьшился с 1242 байт до 810 байт
2
|
||||||
|
232 / 102 / 5
Регистрация: 18.04.2010
Сообщений: 294
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 16.07.2013, 00:20 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Анимация в DOS. Часть первая. В данной статье рассмотрим создание простой анимации в графическом режиме 13H. Использовать будем TASM. Результатом будет небольшая COM-программа.Подробно про графические режимы в DOS и рисование написал Mikl___ здесь: https://www.cyberforum.ru/post4641789.html В данной статье рисовать будем напрямую в видеопамять, так как это удобнее и быстрее. Самый простой способ нарисовать развевающийся флаг — рисовать его вертикальными полосами, координата Y которых зависит от времени и координаты X. Формулу лучше всего проверить, написав пример на каком-нибудь высокоуровневом языке(C, Wolfram Mathematica, Delphi). Так можно быстро протестировать формулу и получить нужный результат. Я для начала написал простую программу с использованием Delphi 7. Формула вышла следующей:
Как стало ясно из вышеприведённой статьи (я надеюсь), чтобы нарисовать пиксель на экране в режиме 13H, нужно загрузить цвет пикселя (1 байт) по определённому адресу в массив пикселей. Адрес вычисляется по просто форумуле:
Сразу следует оговориться: анимация нужна плавная, без мерцаний, поэтому необходимо использовать пару простых приёмов: двойная буферизация и вертикальная синхронизация. Двойная буферизация — принцип, согласно которому части изображения записываются не сразу в видеопамять, а сначала в промежуточный буфер (обычный массив), который потом сразу копируется в видеопамять. Если рисование занимает некоторое время, то изображение на экране может прорисовываться не сразу, а частями, т.к. данные из видеопамяти считываются быстрее, чем алгоритм рисования заполнит видеопамять новыми данными. Двойная буферизация сокращает время заполнения видеопамяти до времени копирования массива. Вертикальной синхронизация — принцип, согласно которому заполнение видеопамяти происходит в специальный момент времени, в который данные из видеопамяти не считываются. Раньше в кинескопах поток электронов (луч), подсвечивал специальное вещество (люминофор), нанесенное на стекло. Если рассказывать примитивно, то луч построчно перемещался от начала дисплея до его конца и потом необходимо было его установить опять в начало. Для этого необходимо было некоторое время, которое называли обратным ходом луча. Пока луч шел обратно, его необходимо было гасить, для чего передавались специальные гасящие сигналы. Существует два вида таких сигналов: от конца строки до начала (горизонтальный или строчный импульс) и от конца кадра до его начала (вертикальный или кадровый импульс). Пока луч был погашен и перемещался в начало дисплея, можно было записать необходимую информацию в видеопамять, так как отображаться промежуточная информация не будет. Хотя в современных мониторах отсутствует именно такая система, но название осталось. Сочетание этих двух принципов позволяет получить достаточно плавную анимацию, без мерцаний. Обычно для рисования анимации применяется следующий подход: в цикле последовательно выполняются следующие действия:
Так как требуется завершать программу по нажатию Enter, нужно также добавить проверку нажатия клавиши, и если нажат Enter, выходить из цикла. Для этого есть две функции прерывания 16H:
Так как необходимо нарисовать ещё и надпись вверху экрана, то придется опять прибегнуть к хитростям ![]() Нарисовать текст может всё та же функция 9 прерывания 21h, но постоянно её вызывать — издержки, которых можно избежать, так как текст не изменяется со временем и ещё записывается сразу в видеопамять. Ещё одна проблема — текст рисуется белыми буквами на чёрном фоне, поэтому фон нужно будет заменить. Функцию рисования заголовка нужно вызвать всего один раз, полоса текста занимает высоту всего 8 пикселей, однако при копировании буфера в видеопамять, первые восемь строк копироваться не будут, чтобы не перезаписать текст.
Рассмотрим также другие вспомогательные функции: DELAY, CLR_BUFF, COPY_BUFF Функция задержки очень проста — это вызов функции 86h прерывания 15h В CX : DX располагается количество микросекунд, на которое нужно остановить программу (прерывание запускает цикл на это время) Ничего сложного в ней нет.
Всего в данной функции два цикла. Проверяет, идет ли на данный момент этот несуществующий луч обратно, и если он идет, то необходимо дождаться его завершения. Это необходимо, так как возможно луч уже почти дошел до начала и начнет рисоваться кадр и буфер скопироваться не успеет (представьте, что лыжник поднимается на подъёмнике, чтобы потом спуститься с холма, с подножья холма можно узнать только занят ли сейчас подъёмник или нет, а кто-то решил очистить холм от препятствий (и успеет пока лыжник поднимается от начала) — для этого ему нужно дождаться пока лыжник поднимется до вершины на подъёмнике (потому что он не знает где лыжник на данный момент находится), съедет с горы и опять начнет подъём).
Осталось самое главное — рисование самого флага. Для этого реализуем несколько дополнительных функций:
В репозитории находится также makefile. Для полной компиляции достаточно написать:
5
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
232 / 102 / 5
Регистрация: 18.04.2010
Сообщений: 294
|
||||||||||||||||||||||||||||||||||||
| 16.07.2013, 09:47 | ||||||||||||||||||||||||||||||||||||
|
Анимация в DOS. Часть вторая. В продолжение предыдущей статьи про анимацию, в этой статье мы рассмотрим другой вид анимации в режиме 13h. Программа опять будет написана под TASM и представлять из себя COM-файл.Особенность данной анимации в том, что видеопамять заполняется лишь единожды. Соответственно, ни двойная буферизация, ни вертикальная синхронизация не нужны, так как информация больше не будет меняться. Изображением будет состоять из последовательных элементов (например, линий), но полностью разных цветов. Меняться будет палитра цветов, в которой находится информация о цвете каждого кода (код тех байтов, которые заносятся в видеопамять). Достаточно в цикле сдвигать цвета в палитре, чтобы создать простую и красивую анимацию. Основная часть программы практически такая же, как и в предыдущей статье, только убраны некоторые ненужные части и изменены функции, управляющие анимацией.
Горизонтальная прямая легко рисуется используя STOSB, так как пиксели располагаются в памяти один за одним.
Нужно заметить, что рисование вертикальных линий идёт с опережением, так как их высота меньше и Y-координата меньше.
В репозитории находится также makefile. Для полной компиляции достаточно написать:
2
|
||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||
| 20.08.2013, 17:17 [ТС] | ||||||
|
Графика DOS. Эффект дождь Размер COM-файла 701 байт. Во вложении исходный текст, картинка в формате PCX и COM-файл
3
|
||||||
|
4187 / 1835 / 220
Регистрация: 06.10.2010
Сообщений: 4,123
|
||||||||||||||||||||||||||||||||||||
| 01.09.2013, 09:37 | ||||||||||||||||||||||||||||||||||||
|
Заставка дождь. Продолжаем разговор на тему "Эффект след от водомерки на поверхности воды". DOS - это конечно хорошо, но мы живём в эпоху AMD64, а не X86. В этой статье я опишу процесс создания программы-заставки под Windows с использованием инструкций SSE и FMA3, ну и конечно прикрутим шейдеры. Программа заставка - это обычный PE с расширением scr. Но небольшие различия всё-таки есть
Я буду использовать тот же алгоритм, что описал Mikl___, но для получения более крупных волн карта высот будет в 16 раз меньше текстуры. Генерация капли. В связи с особенностями реализации капля не должна падать слишком близко к краям экрана (не ближе радиуса волны) иначе волна будет уходить за правый край и выходить с левого. Экспериментально я установил, что радиус волны приблизительно равен 50 пикселям. Проинициализируем регистры перед основным циклом.
Размытие карты высот Тут проще
Окончательный рендер За расчёт смещений отвечает несложный шейдер
ссылки: Описание инструкций CPU ARB Fragment Program Соглашение fastcall x64 Использование регистров в fastcall x64
6
|
||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||
| 03.09.2013, 04:14 [ТС] | ||||||
|
Графика DOS - эффект "линза" + сталкивающиеся шары Если линза на экране - окружность (x0,y0,r0), то в точках (x,y), для которых (x-x0)2+(y-y0)2Размер COM-файла 1030 байт. Исходный текст, СОМ-файл, картинка в формате pcx во вложении
Результат
4
|
||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||||||||||||||||||
| 10.09.2013, 12:36 [ТС] | |||||||||||||||||||||||||||||||||||||
|
Что такое стек и для чего он нужен? Стек — специально отведенная программе область памяти для хранения временных данных, содержимого регистров или адресов команд, следующих за командами call (при вызове процедур). На вершину стека (т.е. последнее записанное значение) указывает пара регистров ss:sp (или ss:esp для 32-разрядных программ). При записи слова (или двойного слова) в стек (командами push, call), оно записывается в память по адресу ss:[sp-2] (или ss:[sp-4], в зависимости от разрядности записываемого значения), а затем из регистра sp/esp вычитается 2 (или 4), то есть стек "растет" в сторону младших адресов памяти. При извлечении значения из стека (командами pop, ret) происходит обратная операция. Для чего это нужно? Предположим, Вам необходимо сохранить значение регистра (допустим, ax), которое понадобиться через несколько команд. Для этого надо выполнить команду push ax, а в том месте, где это значение понадобится — pop ax (или, скажем, pop dx, если Вам необходимо записать это значение в регистр dx). Но! Важно помнить, что запись в стек производится по принципу LIFO (Last In, First Out — последним зашел, первым вышел). Нельзя делать так: push ax ... call ... pushf, а затем pop ax ... popf ... ret, так как в этом случае в регистр ax будут занесено значение регистра флагов, в регистр флагов — адрес возврата из процедуры, а после выполнения команды ret управление перейдет по адресу, который будет взят из сохраненного регистр ax. Таким образом, данные записываются последовательно, а не каждый регистр по определенному адресу! В стек может быть записано как 16-битное, так и 32-битное значение, но не 8-битное. Соответственно, при записи 16-битных значений будет записано 2 байта, а при записи 32-битных значений - 4 байта. Но есть одно исключение: при записи в стек сегментных регистров (ds, es, cs, ss, fs или gs) 32-битные программы (например, программы, работающие под Windows) будут заносить не 2, а 4 байта(!), несмотря на то, что размер сегментных регистров составляет 16 бит. При этом на процессорах Pentium и выше старшее записываемое слово будет содержать нулевое значение. Что же касается команд типа call и ret, то они работают со значениями, размер которых соответствует размеру сегмента кода (то есть 16 бит для DOS-программ, 32 бита — для Win32). Компиляторы ассемблера предлагают несколько модификаций одних и тех же команд, работающих со стеком. Например, команды pusha/popa предназначены для сохранения и восстановления всех (восьми) регистров общего назначения (16-битных значений ax, cx, dx, bx, sp, bp, si и di либо 32-битных eax, ecx и так далее в зависимости от разрядности сегмента кода), а их модификации pushaw/popaw и pushad/popad — 16- и 32-битных соответственно независимо от разрядности сегмента. Что же касается команд ret и retf, то они не имеют модификаций и всегда вынимают из стека столько байт, сколько соответствует текущему размеру сегмента, то есть соответственно 2 и 4 для 16-битных сегментов кода и 4 и 8 для 32-битных. Похожая команда iret имеет модификации iretw и iretd в TASM и только iretd в MASM, причем MASM интерпретирует команду iret как 16-битную (даже в 32-битных программах), а iretd — как 32-битную. Аналогичная ситуация с командами pushf/popf и pushfw/popfw, pushfd/popfd. Записать в стек можно как значение регистра, так и значение из памяти (например, push es:[bx]) и число (push 4000h)Что такое процедуры и зачем они нужны? Процедура — некоторая область кода, которая вызывается специальным образом. Механизм вызова отделяет этот код от остального кода. Прежде чем дать определение процедуре, следует рассмотреть ее свойства. Процедура вызывается инструкцией CALL1. При этом в стеке сохраняется адрес возврата (адрес следующей за ветвлением инструкции) и управление передается на процедуру. При возврате инструкцией RET адрес извлекается из стека и на него выполняется переход, при этом из стека может удалится N байт, если инструкция имела вид RET NВ процедуре могут использоваться локальные переменные. Это некоторая область в стеке, "выше" начала которой адрес дна стека не может быть увеличен без возврата из процедуры и разрушения локальных переменных. Для адресации локальных переменных используется регистр ЕВР. Так как архитектура NT требует сохранения в процедурах регистров EBX, ESI, EDI и EBP, то вначале процедуры в стеке сохраняется регистр EBP, затем в этот регистр загружается текущее значение ESP, в стеке аллоцируется пространство под локальные переменные. Далее в пределах процедуры до возврата из нее, значение в регистре EBP не изменяется. Таким образом, этот регистр адресует предыдущее значение регистра EBP (предыдущей процедуры), ниже в стеке рассположены локальные переменные и значения регистров, которые процедура сохранила в стеке при входе и восстановит при выходе, выше адрес возврата из процедуры, еще выше — аргументы переданные процедуре, если у функции есть аргументы, либо локальные переменные принадлежащие "материнской" процедуры, которая вызывала "нашу" процедуру. Начало прцедуры выглядит следующим образом:
lp = STACK_FRAME.Next.lp[ebp] Такой проход по цепочке стековых фреймов называется бэктресом (back trace). Он может выполняться по достижению последнего стекового фрейма, при этом ссылка на следующий фрейм инвалидна (указывает за пределы стека3)Относительно начала цепочки стековых фреймов (текущий фрейм, ссылка на который находится в регистре ЕВР контекста) у каждого фрейма есть свой номер. Этот номер определяет, сколько итераций бэктрейса необходимо выполнить для достижения необходимого стекового фрейма и называется номером стекового фрейма (Stack Frame Number — SFN). Так как в пределах текущей процедуры значение ЕВР не меняется, то можно сказать, что код процедуры исполняется на некотором уровне относительно других процедур, от которого зависит SFN (этот уровень равен ΔSFN двух процедур). Этот уровень называется уровнем вложенности процедур (Nesting Level — NL)4. Важные свойства процедур:
Стековая маршрутизация Стековый фрейм содержит адрес возврата из текущей процедуры, следующий фрейм содержит адрес возврата из вызывающей процедуры и так далее, то можно заменить во фрейме адрес возврата. Тогда после снижения NL (SFN) до нулевого уровня (относительно текущей процедуры), из стека будет извлечен соответствующий процедуре фрейм и выполнен возврат на адрес, находящийся в этом фрейме. Так как он изменен, то возврат произойдет на новый адрес. Эта манипуляция называется процедурным post-редиректом или стековой маршрутизацией.________________________________________ ____ 1 Процедурное ветвление в текущем кодовом сегменте осуществляется инструкцией Call near. Межсегментное ветвление — Call far (селектор описывает кодовый сегмент, а не шлюз вызова) сохраняют в стеке помимо адреса возврата также и селектор кодового сегмента (CS:EIP), куда будет выполнен возврат инструкцией RETF. 2 Для формирования и удаления BP-фреймов предназначены инструкции enter и leave соответственно 3 База и лимит стека находятся в TIB, поля StackBase и StackLimit, смещения которых соответственно +4 и +8 (в ks386 описываются константы с префиксом Tb или Te). В Kernel mode TIB находится в начале PCR, в User mode — в начале TEB. Учитывая, что TEB и PCR адресуются через один и тот же регистр FS, то мод не имеет значения. FS:[+4] в обоих режимах будет адресовать базу стека. 4 По сути это уровень определяющий сколько раз был вызван участок кода через некоторый механизм вызова. В данном случае это процедурное ветвление. Примером не процедурного ветвления может быть ISR — хэндлер прерывания является процедурой, но вызывается через особые механизмы. Непосредственно через инструкции Int, либо косвенно, когда вектор прерывания вызывается при некотором событии (прерывания и исключения). Другим примером могут служить быстрые вызовы сервисных функций ядра посредством инструкций Sysenter. При этом используется совершенно другой механизм (использование MSR), в отличие от прерываний. Важной особенностью процедуры является наличие механизма возврата. Для процедурного ветвления используется инструкция Ret, для прерываний — Iret, для возврата из быстрых сервисных вызовов — инструкция Sysexit и т.д. Механизм вызова и возврата из процедуры не обязательно должен использовать стек (пример — Sysexit). Для ISR NL будет определяться рекурсивным обращением к IDT, например, возникновение #GP из хэндлера #GP увеличит NL 5 Все процедуры Bp-based, то есть формируют стековые фреймы.
5
|
|||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|
| 12.09.2013, 06:11 [ТС] | |
|
Кто и зачем до сих пор использует DOS. Какой смысл сейчас писать что-либо под эту ОС?
5
|
|
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||
| 19.09.2013, 06:17 [ТС] | |||||||||||||||||||||
|
Блокируем клавиатуру в Windows Для блокировки клавиатуры существует несколько путей
4
|
|||||||||||||||||||||
|
4187 / 1835 / 220
Регистрация: 06.10.2010
Сообщений: 4,123
|
||||||||||||||||||||||||||||||||||||
| 22.09.2013, 09:08 | ||||||||||||||||||||||||||||||||||||
|
Особенности кодинга под x64 Программирование под x64 не сильно отличается от уже привычного x86, но некоторые отличия всё-же имеются. Как всегда для того, чтобы узнать все эти мелочи приходится собирать инфу в нескольких источниках. Я попытаюсь собрать воедино эти мелочи из руководств Intel, MSDN и руководства FASM.По части инструкций Запилено:
Выпилено:
Ограничения:
Соглашение fastcall x64 Передача параметровПервые 4 параметра передаются через регистры rcx, rdx, r8, r9, остальные параметры передаются в обратном порядке через стек. При этом в стеке резервируется дополнительно 32 байта для первых 4 параметров даже если у функции вообще нет параметров. Параметры с плавающей точкой передаются через регистры xmm0, xmm1, xmm2, xmm3. Если параметр занимает больше 8 байт, он передаётся через указатель. Стек освобождается вызывающей стороной. Выравнивание стека Перед вызовом функции rsp должен быть кратен 16. Таким образом если ваша функция имеет чётное количество параметров и количество параметров больше 4, при передаче ей управления rsp будет кратен 8, иначе rsp кратен 16. В FASM макросы .code/.end автоматически добавляют "sub rsp,8" в точке входа для выравнивания стека. Не изменяемые регистры Функции не должны изменять содержимое регистров rsi, rdi, rbp, rbx, r12-r15, xmm6-xmm15. Общие рекомендации
9
|
||||||||||||||||||||||||||||||||||||
|
Эксперт быдлокодинга
2094 / 528 / 70
Регистрация: 04.11.2010
Сообщений: 1,314
|
||||||
| 22.09.2013, 23:25 | ||||||
|
murderer,
0
|
||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 23.09.2013, 05:04 [ТС] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Особенности кодинга под x64 За основу взята статья Крис Касперски "Архитектура x86-64 под скальпелем ассемблерщика"(часть вторая) За подробным описанием x86-64 архитектуры лучше всего обратится к фирменной документации "AMD64 Technology - AMD64 Architecture Programmer's Manual Volume 1:Application Programming" (http://www.amd.com/us-en/asset... /24593.pdf). Мы ограничимся только беглым обзором основных нововведений. К восьми регистрам общего назначения добавилось еще восемь, в результате чего их общее количество достигло 16. Старые регистры, расширенные до 64-бит, получили имена RAX, RBX, RCX, RDX, RBP, RSI, RDI, RSP, RIP и RFLAGS. Новые регистры остались безымянными и просто пронумерованы от R8 до R15. Для обращения к младшим 8-, 16- и 32-битам новых регистров можно использовать суффиксы b, w и d соответственно. Например, R9 - это 64-разрядный регистр, R9b - его младший байт (по аналогии с AL), а R9w - младшее слово (то же самое, что AX в EAX). Прямых наследников AH, к сожалению, не наблюдается и для манипуляции со средней частью регистров приходится извращаться со сдвигами и математическими операциями. Регистры, доступные в x86-64 режиме Регистр-указатель команд RIP теперь адресуется точно так же, как и все остальные регистры общего назначения. Простейший пример: загрузить в регистр AL опкод следующей машинной команды. На x86 приходится поступать так. Если мы знаем адрес следующей команды, тогда это выглядит так
А теперь перепишем тот же самый пример на x86-64:
Загрузка опкода следующей машинной команды на x86-64. Только следует помнить, что RIP всегда указывает на следующую, а не на текущую инструкцию. К сожалению, ни Jx RIP, ни CALL RIP не работают. Таких команд в x86-64 просто нет. Исчезла абсолютная адресация. Если нам надо изменить содержимое ячейки памяти по конкретному адресу, на x86 мы поступаем приблизительно так:
Абсолютная адресация в классическом x86 Под x86-64 транслятор выдает ошибку ассемблирования, вынуждая нас прибегать к фиктивному базированию:
Использование фиктивного базирования на x86-64 для абсолютной адресации Есть и другие отличия от x86, но они не столь принципиальны. Важно то, что в режиме совместимости с x86 (Legacy Mode) ни 64-битные регистры, ни новые методы адресации недоступны! Никакими средствами дотянуться до них нельзя и прежде чем что-то сделать, необходимо перевести процессор в режим "long mode", который делится на два под-режима:
Реальная 64-битность обитает только в 64-bit long mode, о котором мы и будем говорить! Режимы работы процессора AMD-64 и их особенности "Hello world" на x86-64 Программирование под 64-битную версию Windows мало чем отличается от традиционного, только все операнды и адреса по умолчанию 64-разрядные, а параметры API-функций передаются через регистры, а не через стек. Первые четыре аргумента всех API-функций передаются в регистрах RCX, RDX, R8 и R9 (регистры перечислены в порядке следования аргументов, крайний левый аргумент помещается в RCX). Остальные параметры кладутся на стек. Все это называется x86-64 fast calling conversion (соглашение о быстрой передаче параметров для x86-64), подробное описание которой можно найти в статье "The history of calling conventions, part 5 amd64" (http://blogs.msdn.com/oldnewth... 58579.aspx). Также нелишне заглянуть на страничку бесплатного компилятора Free PASCAL и поднять документацию по способам вызова API: http://www.freepascal.org/wiki... /AMD64_API. В частности, вызов функции с пятью аргументами API_func(1,2,3,4,5) выглядит так:
Пример вызова API-функции с пятью параметрами по соглашению x86-64. Смещение пятого аргумента относительно верхушки стека требует пояснений. Почему оно равно 20h? Ведь адрес возврата занимает только 8 байт. Кто съел все остальные? Оказывается, они "резервируются" для первых четырех аргументов, переданных через регистры. "Зарезервированные" ячейки содержат неинициализированный мусор и называются "spill", что переводится как "затычка" или "потеря". Вот минимум знаний, необходимых для выживания в мире 64-битной Windows при программировании на ассемблере. Остается разобрать самую малость. Как эти самые 64-бита заполучить?! Для перевода FASM'а в x86-64 режим достаточно указать директиву "use64" и программировать, как обычно. Ниже идет пример простейшей x86-64 программы, которая не делает ничего, только возвращает в регистре RAX значение "ноль".
Никаких дополнительных аргументов командной строки указывать не надо, просто сказать
Дизассемблерный листинг простейшей 64-битной программы. Формально, это типичный com-файл Начиная с версии 1.64, ассемблер FASM поддерживает специальную директиву "format PE64", автоматически формирующую 64-разрядный PE-файл (директиву "use64" в этом случае указывать уже не нужно), а в каталоге EXAMPLES можно найти готовый пример PE64DEMO, в котором показано, как ее использовать на практике. Ниже приведен пример x86-64 программы "hello, world" с комментариями:
64-битное приложение "hello, world" под Windows на FASM'е
Дизассемблерный листинг 64-битного приложения "Hello, world!" приложение в стиле MASM. Никаких радикальных отличий не наблюдается:
64-битное приложение "Hello, world" под Windows на MASM'е Ассемблирование и линковка проходит так:
10
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|||||||||||||||||||||
| 23.09.2013, 18:05 [ТС] | |||||||||||||||||||||
|
Особенности кодинга под x64 Простое оконное приложение на Win64(часть третья)
Основной код программы написан — теперь осталось добавить функцию окна
В оконной функции нет необходимости выравнивать указатель стека на 16 байт, так как системная функция, которая вызывает оконную функцию, использует выровненный стек. Завершаем программу описанием импортируемых функций
5
|
|||||||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
|
| 29.09.2013, 09:31 [ТС] | |
|
Где скачать компилятор для ассемблера? Компиляторы языков высокого уровня (Си, Паскаль) в определенной степени совместимы между собой и хотя исходный текст, предназначенный для одного компилятора, не всегда без переделок транслируется на другом, синтаксис и прочие языковые концепции остаются неизменными, позволяя "летать" между MS VC, Intel C++, GCC, Open WATCOM, сравнивая полноту поддержки Стандарта, скорость трансляции, качество кодогенерации, популярность компилятора и вытекающее отсюда изобилие (недостаток) библиотек и компонентов к нему.С трансляторами ассемблера все обстоит иначе. Казалось бы, x86 ассемблер — он и в Африке ассемблер, но нет! Кроме поддержки мнемоник машинных команд, каждый транслятор обладает своим собственным набором директив и макросредств, зачастую ни с чем не совместимых. Ассемблерный листинг под MASM, бесполезно переносить на FASM, поскольку возможности, предоставляемые макросредствами, у них неодинаковые. Человеку, упорно игнорирующего существование Linux/BSD, абсолютно все равно, на какое количество платформ был перенесен данный транслятор. А для кого-то это вопрос первостепенной важности! Тем не менее, существует ряд основополагающих критериев, существенных для всех категорий программистов. Начнем с генерации отладочной информации, без которой отладка программы сложнее, чем "hello, word", превращается в настоящую пытку. Кое-кто попытается возразить, что ассемблерам, в отличии от языков высокого уровня, отладочная информация не нужна, ведь мнемоники машинных команд, что в листинге, что в отладчике — одни и те же. А метки?! А структуры?! А имена функций?! Уберите их — и код станет совершенно не читаемым! Можно воспользоваться отладочной печатью (просто вставлять макрос, выводящий значение регистров/переменных на экран/файл в указанных местах). Еще можно отлаживать программу, держа перед носом распечатку исходных текстов. Проблема в том, что формат отладочной информации не стандартизован и различные трансляторы используют различные форматы, что ограничивает в выборе отладчиков или вынуждает использовать конвертеры сторонних производителей, FASM вообще не генерирует отладочной информации. Если формат отладочной информации — это, скорее, проблема для профессионалов, то формат выходных файлов касается всех. Обыкновенный obj, из которого с помощью линкера можно изготовить все, что угодно — от exe до dll. Объектные файлы делятся на
Другой немаловажный критерий — количество поддерживаемых процессорных архитектур, которых в линейке x86 набралось уже больше десятка. Конечно, недостающие команды можно реализовать с помощью макросов или запрограммировать непосредственно в машинном коде через директиву DB, но... если так рассуждать, то зачем вообще нужны ассемблеры, когда есть hex-редакторы?! Особое внимание следует обратить на платформы AMD x86-64 и Intel IA64. 64-разрядные архитектуры вытесняют x86, поэтому учиться программировать под них обязательно, так что поддержка со стороны транслятора должна быть обеспечена уже сейчас! Ни один из трансляторов не поддерживает набор команд x86-процессоров в полном объеме. Например, на MASM'е невозможно написать jmp 0007h:00000000h и приходится прибегать к различным ухищрениям: либо реализовать команду через DB, что ненаглядно и неудобно, либо заталкивать в стек сегмент/смещение, а потом делать retf, но это длинно и к тому же воздействует на стек, которого у нас может и не быть. Программирование на смеси 16- и 32-разрядного кода с кратковременным переходом в защищенный режим и возвращением обратно в реальный — на MASM'е скорее умрешь, чем такое запрограммируешь, но большинству программистов подобное трюкачество просто не нужно! А вот что реально нужно большинству — так это интеграция в мировое сообщество. Свои собственные оси обычно пишут новички, только что начитавшиеся Юрова/Зубкова и открывшие для себя защищенный режим с его безграничными возможностями. В учебном плане это очень даже хорошо, но коммерческим программистам обычно приходится программировать под уже существующие системы — ту же Windows, например. И, если в состав DDK входит MASM в кучей исходных текстов драйверов, то пытаться собрать их под другим транслятором означает впустую убивать время. Опять-таки, если компилятору Microsoft Visual C++ задать ключ /FA, то он выдаст ассемблерный листинг в стиле MASM, точно так же поступит и IDA Pro, Borland C++ выберет TASM, а GCC - GNU Assembler (он же GAS). Вот это и называется интеграцией в среду программирования. Чистый ассемблер сам по себе мало кому интересен и практически всегда становится приложением к чему-то еще. Если вы пишите драйвера под Windows на Microsoft Visual C++, то разумнее всего остановить свой выбор на MASM'е, поклонникам же Borland C++ лучше TASM'а ничего не найти. Под Linux/BSD рулит GAS (GNU Assembler) уже хотя бы за счет того, что ассемблерные программы можно транслировать с помощью компилятора GCC, используя Си-сопроцессор с одной стороны и освобождаясь от головной боли с поиском стартового кода и библиотек, однако GAS использует AT&T-синтаксис, являющийся полной противоположностью Intel-синтаксису, которого придерживаются MASM, TASM, FASM, NASM/YASM. Разработчики вирусов и просто маленьких ассемблерных программ, написанных из любви к искусству, намного меньше ограничены в своем выборе и могут использовать все, что им по душе, вне зависимости от степени "поддержки". Качество документирования играет весьма важную роль и еще важнее — кому принадлежит проект. Трансляторы, созданные энтузиастами-одиночками, могут умереть в любой момент, поэтому закладываться на них в долговременной перспективе не стоит. Коммерческие ассемблеры крупных компаний выглядят намного более стабильными и непоколебимыми, однако никаких гарантий, что в один "прекрасный" момент компания не забросит на своей продукт, у нас нет (достаточно вспомнить историю с TASM'ом). Открытые трансляторы, поддерживаемые независимой группой лиц, наиболее живучи. Стоило коллективу NASM'а чуть-чуть приостановить его развитие, как тут же появился YASM — "позаимствовавший" исходные тексты и добавивший все необходимое (поддержку x86-64, формат отладочной информации CodeView и так далее). Последнее, на чем хотелось бы заострить внимание — это макросредства. Отношение к ним у программистов двоякое. Одни во всю пользуются плодами прогресса, программируя на смеси ассемблера, бейсика и препроцессора Си (существует даже проект HLA: High Level Assembler — Ассемблер Высокого Уровня), другие — презирают их, ратуя за чистоту ассемблерного кода. Макросы упрощают программирование, зачастую позволяя невозможное (например, шифровать код программы еще на стадии ассемблирования!), но переносимость программы от этого резко ухудшается и переход на другой транслятор становится труднореализуемым. Но как бы там ни было, поддержка макросов совсем не обязывает этими макросами пользоваться!
16
|
|
|
435 / 246 / 43
Регистрация: 05.08.2013
Сообщений: 1,670
|
|||||||||||
| 06.10.2013, 18:27 | |||||||||||
|
сортировка вставками.
4
|
|||||||||||
|
193 / 188 / 18
Регистрация: 06.10.2013
Сообщений: 357
|
|||||||||||||||||||||
| 13.11.2013, 12:24 | |||||||||||||||||||||
|
Как известно, ml64.exe не имеет встроенного макроса invoke, поэтому код сильно разбухает из-за необходимости передавать аргументы функций вручную. Представляю макрос, который облегчит труд программиста.
Addr и offset можно использовать как для глобальных переменных, так и для стековых. Добавлено через 1 час 21 минуту Макросы, позволяющие обработать исключение на проблемном участке код, устанавливающие и снимающие обработчик SEH. Условие многократного использования одного обработчика исключений - наличие глобальной переменной, для записи смещения, на которое будет передано управление после обработки исключения. Макрос except должен находиться вне процедуры, в которой может возникнуть исключение.
5
|
|||||||||||||||||||||
|
193 / 188 / 18
Регистрация: 06.10.2013
Сообщений: 357
|
||||||||||||||||
| 21.11.2013, 10:26 | ||||||||||||||||
|
Тема на одном из форумов натолкнула меня на написание драйвера, позволяющего установить глобальный хук на всё время работы системы до перезагрузки. В данном случае будет изменена функция MessageBoxA из библиотеки user32.dll. Это пример для Windows x32, но и на х64 можно сделать подобное. Требуется только цифровая подпись драйвера.
Кликните здесь для просмотра всего текста
Макрос unis для х64.
4
|
||||||||||||||||
|
Ушел с форума
16371 / 7683 / 1080
Регистрация: 11.11.2010
Сообщений: 13,757
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 17.12.2013, 06:18 [ТС] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
.По синтаксису встроенный ассемблер Visual C++ частично совпадает с MASM. Например, как и в MASM можно строить выражения с операндами и использовать offset с глобальными переменными. Как и в MASM, можно использовать глобальные метки и принудительно определять короткие переходы. Однако определить локальную метку с помощью @@ во встроенном ассемблере Visual C++ не получится – замена lab: на @@lab: в предыдущем примере вызовет ошибку компиляции. Есть и другие отличия от MASM. Например, во встроенном ассемблере Visual C++ нет никаких средств для объявления переменных, поэтому о привычных DB, DW, DD, DQ, DT, DF, DUP и THIS можно забыть. Зато можно использовать переменные, объявленные в программе на C++. Во встроенном ассемблере также нельзя объявлять структуры — директивы STRUC, RECORD, WIDTH и MASK недопустимы. Вместо этого можно использовать структуры, объявленные в программе на C++. Кроме того, в ассемблере можно использовать комментарии и HEX-числа в стиле C++. В принципе, все отличия подробно описаны в MSDN (идет в комплекте с Visual Studio). Обычно в Visual C++ ассемблер используется для написания функций. Как правило, функции, написанные на ассемблере, объявляют с использованием директивы _stdcall. В этом случае параметры передаются в функцию на стеке в обратном порядке, а результат работы возвращается в eax. Для примера рассмотрим функцию, которая находит длину ASCIIZ-строки:
Во-вторых, нужно быть осторожным с регистрами и стеком. В середине ассемблерных вставок нельзя менять регистры ds, ss, sp, bp и флаги. Если эти регистры все-таки меняются, перед выходом из ассемблерной вставки их нужно обязательно восстановить. Что касается стека, то тут нужно соблюдать правило, которое гласит: если в ассемблерной вставке нечто ложится на стек, то в той же ассемблерной вставке это «нечто» должно со стека сниматься. Рассмотрим, например, такой код:
6
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 17.12.2013, 06:18 | |
|
Помогаю со студенческими работами здесь
40
Видеоуроки по Ассемблеру MASM/TASM (для DOS) на русском языке MASM, TASM, FASM: что выбрать для программирования в ядре Есть ли компиляторы Tasm или Masm для 64-разрядных систем Подскажите ссылки на FAQ для разделов Assembler, MASM, TASM Assembler Переделать из TASM в masm Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
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 .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|
Фото: Daniel Greenwood
kumehtar 13.11.2025
|