Быстрый поиск
Введите фрагмент названия статьи для поиска
Полезные функции для работы с датами на Ассемблере
05.06.2014 | Категория: Образ мышления: Assembler | Автор: ManHunter
Полезные функции для работы с датами на Ассемблере
Из разных источников насобирал различные полезные функции для работы с датами на Ассемблере. Преимущества их в том, что они работают очень быстро, хорошо оптимизированы и позволяют обходиться вообще без вызова системных функций. Все функции самодостаточные и не требуют для работы каких-либо дополнительных данных.
Читать статью целиком »
Просмотров: 8537 | Комментариев: 4
Преобразование вещественного числа в строку на Ассемблере
14.03.2014 | Категория: Образ мышления: Assembler | Автор: ManHunter
Ранее я выкладывал статью о том, как на Ассемблере перевести строку в вещественное число, теперь настало время произвести обратную операцию, то есть перевести вещественное число в строку. В отличие от целых чисел, где достаточно нескольких строк кода, с преобразованием вещественных чисел пришлось повозиться. В результате появилась следующая функция. За основу взята аналогичная функция из пакета MASM, но со значительными доработками.Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------------------
- ; Функция перевода вещественного числа в строку
- ;------------------------------------------------------------
- ; Портирование с MASM, доработка и оптимизация - ManHunter
- ; Параметры:
- ; lpFloat - указатель на вещественное число TBYTE
- ; lpResult - указатель на строку-приемник результата
- ;------------------------------------------------------------
- proc FloatToString lpFloat:DWORD, lpResult:DWORD
- ; Локальные переменные
- local digits_count:DWORD
- local tmp:DWORD
- local old_cw:WORD
- local new_cw:WORD
- local saved_float:TBYTE
- local tmp1 rb 12h
- local tmp2 rb 12h
- ; Сохранить все регистры
- pusha
- ; Указатель на строку-приемник
- mov edi,[lpResult]
- ; Это ноль?
- mov esi,[lpFloat]
- cmp dword [esi],0
- jne loc_not_zero
- cmp dword [esi+4],0
- jne loc_not_zero
- cmp word [esi+8],0x8000
- je loc_minus_zero
- cmp word [esi+8],0
- jne loc_not_zero
- ; Записать в строку ноль
- mov al,'0'
- stosb
- jmp loc_ret
- loc_minus_zero:
- ; Записать в строку минус ноль
- mov ax,'-0'
- stosw
- jmp loc_ret
- loc_not_zero:
- ; Denormalized?
- mov ax,word [esi+8]
- and ax,7F80h
- or ax,ax
- jnz loc_not_denorm
- cmp dword [esi],0
- jne loc_denorm
- cmp dword [esi+4],0
- je loc_not_denorm
- loc_denorm:
- mov esi,szDen
- movsd
- movsd
- movsd
- jmp loc_ret
- loc_not_denorm:
- ; Infinity или NaN?
- mov ax,word [esi+8]
- and ax,7F80h
- cmp ax,7F80h
- jne loc_not_inf_nan
- ; Это Infinity?
- cmp dword [esi],0
- jne loc_nan
- cmp dword [esi+4],80000000h
- jne loc_nan
- loc_infinity:
- mov esi,szInf
- movsd
- movsb
- loc_plus_minus:
- movsd
- mov esi,[lpFloat]
- test byte [esi+9],80h
- jz loc_ret
- mov esi,[lpResult]
- mov byte[esi],'-'
- jmp loc_ret
- loc_nan:
- mov esi,szNan
- jmp loc_plus_minus
- loc_not_inf_nan:
- ; Скопировать число в локальную переменную
- push edi
- mov esi,[lpFloat]
- lea edi,[saved_float]
- movsd
- movsd
- movsw
- pop edi
- ; Число отрицательное?
- cmp dword [saved_float+6],0
- jge loc_not_signed
- ; Привести число к абсолютному значению
- and byte [saved_float+9],7Fh
- ; Записать в строку минус
- mov al,'-'
- stosb
- loc_not_signed:
- ; Проверить число на наличие дробной части и
- ; подсчитать количество цифр в нем
- fclex
- ; Сохранить управляющее слово
- fstcw [old_cw]
- ; Установить управляющее слово
- mov [new_cw],0000001001111111b
- fldcw [new_cw]
- lea esi,[saved_float]
- fld tbyte [esi]
- fld st
- ; Выделить мантиссу и порядок
- fxtract
- fstp st
- fldlg2
- ; Получить количество цифр в числе
- fmulp st1,st
- fistp [digits_count]
- ; Если цифр больше 16, то число отображается в
- ; нормализованном виде с мантиссой и экспонентой
- cmp [digits_count],10h
- jnb loc_not_integer
- ; У числа есть дробная часть?
- fld st
- frndint
- fcomp st1
- fstsw ax
- test ah,01000000b
- ; Да, отображать число с дробной частью
- jz loc_not_integer
- ; Целое число без дробной части и экспоненты
- lea eax,[tmp1]
- fbstp [eax]
- ; Перевести BCD-число в строку
- push edi
- lea esi,[tmp1+8]
- lea edi,[tmp2]
- mov ecx, 9
- @@:
- std
- xor eax,eax
- lodsb
- cld
- rol ax,12
- rol ah,4
- add ax,'00'
- stosw
- loop @b
- pop edi
- ; Пропустить лидирующий ноль
- mov eax,11h
- mov ecx,[digits_count]
- sub eax,ecx
- inc ecx
- lea esi,[tmp2+eax]
- cmp byte [esi],'0'
- jne @f
- inc esi
- dec ecx
- @@:
- ; Перенести полученное число из временного буфера
- rep movsb
- jmp loc_clear_stack
- loc_not_integer:
- mov eax,10h
- sub eax,[digits_count]
- ; Преобразовать число в целое до 16 разрядов
- mov ecx,eax
- cmp eax,0
- jge @f
- neg eax
- @@:
- ; Для чисел больше 0 корректировка округления в сторону 0
- mov [new_cw],0000101001111111b
- cmp ecx,0
- jge @f
- mov [new_cw],0000011001111111b
- @@:
- ; Установить управляющее слово
- fldcw [new_cw]
- ; Возвести 10 в степень количества цифр
- mov [tmp],eax
- fild [tmp]
- fld [float2]
- fyl2x
- fld1
- fld st1
- fprem
- f2xm1
- faddp
- fscale
- ; Почистить стек
- fxch st1
- fstp st
- ; Если число меньше 0, то умножить, иначе разделить
- cmp ecx,0
- jge @f
- fdivp st1,st
- jmp loc_rounded
- @@:
- fmulp st1,st
- loc_rounded:
- ; Полученное значение меньше 1.0e16 ?
- fcom [float1]
- fstsw ax
- test ah,1
- jz @f
- fmul [float2]
- dec [digits_count]
- @@:
- ; Целое число без дробной части и экспоненты
- lea eax,[tmp1]
- fbstp [eax]
- ; Перевести BCD-число в строку
- push edi
- lea esi,[tmp1+8]
- lea edi,[tmp2]
- mov ecx, 9
- @@:
- std
- xor eax,eax
- lodsb
- cld
- rol ax,12
- rol ah,4
- add ax,'00'
- stosw
- loop @b
- pop edi
- ; Числу требуется мантисса и экспонента?
- lea esi,[tmp2+1]
- mov ecx,[digits_count]
- cmp ecx,-0Fh
- jl loc_mantiss_and_exponent
- cmp ecx,10h
- jg loc_mantiss_and_exponent
- ; Заполнить дробную часть числа
- inc ecx
- cmp ecx,0
- jg @f
- mov ax,'0.'
- stosw
- neg ecx
- mov al,'0'
- rep stosb
- mov ecx,10h
- jmp loc_fraction_filled
- @@:
- rep movsb
- mov al,'.'
- stosb
- mov ecx,10h
- sub ecx,[digits_count]
- loc_fraction_filled:
- rep movsb
- jmp @f
- loc_clear_fraction:
- ; Удалить завершающие нули дробной части
- dec edi
- @@:
- cmp byte [edi-1],'0'
- jz loc_clear_fraction
- cmp byte [edi-1],'.'
- jnz @f
- dec edi
- @@:
- jmp loc_clear_stack
- loc_mantiss_and_exponent:
- ; Дробная часть мантиссы
- movsb
- mov al,'.'
- stosb
- movsd
- movsd
- movsw
- ; Удалить завершающие нули дробной части
- @@:
- cmp byte [edi-1],'0'
- jne @f
- cmp byte [edi-2],'.'
- je @f
- dec edi
- jmp @b
- @@:
- ; Символ и знак экспоненты
- mov al,'e'
- stosb
- mov al,'+'
- mov ebx,[digits_count]
- cmp ebx, 0
- jge @f
- mov al,'-'
- neg ebx
- @@:
- stosb
- ; Значение экспоненты
- mov eax,ebx
- mov ecx,10
- mov ebx,4
- @@:
- dec ebx
- xor edx,edx
- div ecx
- add dl,'0'
- mov [tmp1+ebx],dl
- or ebx,ebx
- jnz @b
- ; Пропустить лидирующие нули экспоненты
- mov ecx,4
- lea esi,[tmp1]
- @@:
- lodsb
- cmp al,'0'
- jne @f
- dec ecx
- jmp @b
- @@:
- dec esi
- rep movsb
- loc_clear_stack:
- ; Восстановить управляющее слово
- fldcw [old_cw]
- loc_ret:
- ; Окончание строки
- mov al,0
- stosb
- ; Восстановить все регистры
- popa
- ret
- float1 dq 1.0e16
- float2 dq 10.0
- szInf db '+Infinity'
- szNan db '+NaN'
- szDen db 'Denormalized'
- endp
Читать статью целиком »
Просмотров: 11156 | Комментариев: 27
Оптимизация умножения на константу на Ассемблере
05.08.2013 | Категория: Образ мышления: Assembler | Автор: ManHunter
В предыдущей статье по оптимизации мы рассматривали замену команд деления, как это описано в "AMD Athlon Processor x86 Code Optimization Guide". Но в этом же мануале описана оптимизация умножения на константу. Тут нет универсальных алгоритмов, по которым можно было бы однозначно определить нужную последовательность команд замены, как в случае с делением. Для каждой константы набор команд определяется на основании их "весовых коэффициентов" и количества тактов процессора, необходимых для их выполнения. В качестве примера приведена вот такая табличка оптимизации умножения с 2 до 32. Ее всегда можно посмотреть и в самом мануале, но лучше пусть будет под рукой.Code (Assembler) : Убрать нумерацию
- ; Умножение на 2
- add reg1, reg1 ; 1 такт процессора
- ; Умножение на 3
- lea reg1, [reg1+reg1*2] ; 2 такта процессора
- ; Умножение на 4
- shl reg1, 2 ; 1 такт процессора
- ; Умножение на 5
- lea reg1, [reg1+reg1*4] ; 2 такта процессора
- ; Умножение на 6
- lea reg1, [reg1+reg1*2] ; 3 такта процессора
- add reg1, reg1
- ; Умножение на 7:
- mov reg2, reg1 ; 2 такта процессора
- shl reg1, 3
- sub reg1, reg2
- ; Умножение на 8:
- shl reg1, 3 ; 1 такт процессора
- ; Умножение на 9:
- lea reg1, [reg1+reg1*8] ; 2 такта процессора
- ; Умножение на 10:
- lea reg1, [reg1+reg1*4] ; 3 такта процессора
- add reg1, reg1
- ; Умножение на 11:
- lea reg2, [reg1+reg1*8] ; 3 такта процессора
- add reg1, reg1
- add reg1, reg2
- ; Умножение на 12:
- lea reg1, [reg1+reg1*2] ; 3 такта процессора
- shl reg1, 2
- ; Умножение на 13:
- lea reg2, [reg1+reg1*2] ; 3 такта процессора
- shl reg1, 4
- sub reg1, reg2
- ; Умножение на 14:
- lea reg2, [reg1+reg1] ; 3 такта процессора
- shl reg1, 4
- sub reg1, reg2
- ; Умножение на 15:
- lea reg1, [reg1+reg1*2] ; 4 такта процессора
- lea reg1, [reg1+reg1*4]
- ; Умножение на 16:
- shl reg1, 4 ; 1 такт процессора
- ; Умножение на 17:
- mov reg2, reg1 ; 2 такта процессора
- shl reg1, 4
- add reg1, reg2
- ; Умножение на 18:
- lea reg1, [reg1+reg1*8] ; 3 такта процессора
- add reg1, reg1
- ; Умножение на 19:
- lea reg2, [reg1+reg1*2] ; 3 такта процессора
- shl reg1, 4
- add reg1, reg2
- ; Умножение на 20:
- lea reg1, [reg1+reg1*4] ; 3 такта процессора
- shl reg1, 2
- ; Умножение на 21:
- lea reg2, [reg1+reg1*4] ; 3 такта процессора
- shl reg1, 4
- add reg1, reg2
- ; Умножение на 22:
- lea reg2, [reg1+reg1*4] ; 4 такта процессора
- add reg1, reg1
- lea reg1, [reg1+reg2*4]
- ; Умножение на 23:
- lea reg2, [reg1+reg1*8] ; 3 такта процессора
- shl reg1, 5
- sub reg1, reg2
- ; Умножение на 24:
- lea reg1, [reg1+reg1*2] ; 3 такта процессора
- shl reg1, 3
- ; Умножение на 25:
- lea reg1, [reg1+reg1*4] ; 4 такта процессора
- lea reg1, [reg1+reg1*4]
- ; Умножение на 26:
- lea reg2, [reg1+reg1*2] ; 4 такта процессора
- add reg1, reg1
- lea reg1, [reg1+reg2*8]
- ; Умножение на 27:
- lea reg1, [reg1+reg1*2] ; 4 такта процессора
- lea reg1, [reg1+reg1*8]
- ; Умножение на 28:
- lea reg2, [reg1*4] ; 3 такта процессора
- shl reg1, 5
- sub reg1, reg2
- ; Умножение на 29:
- lea reg2, [reg1+reg1*2] ; 3 такта процессора
- shl reg1, 5
- sub reg1, reg2
- ; Умножение на 30:
- lea reg2, [reg1+reg1] ; 3 такта процессора
- shl reg1, 5
- sub reg1, reg2
- ; Умножение на 31:
- mov reg2, reg1 ; 2 такта процессора
- shl reg1, 5
- sub reg1, reg2
- ; Умножение на 32:
- shl reg1, 5 ; 1 такт процессора
Читать статью целиком »
Просмотров: 8182 | Комментариев: 7
Замена деления умножением на Ассемблере
07.07.2013 | Категория: Образ мышления: Assembler | Автор: ManHunter
Замена деления умножением на Ассемблере
При написании на Ассемблере алгоритмов, использующих деление на константу, операции деления можно заменять на операции умножения. Зачем это надо? Дело в том, что процессор выполняет операцию умножения в несколько раз быстрее, чем операцию деления. К примеру, на умножение тратится 5-9 тактов процессора (знаковое умножение) или 4-8 (беззнаковое умножение), тогда как для деления необходимо 22-47 тактов (знаковое деление) или 17-41 тактов (беззнаковое деление). В высокооптимизированных алгоритмах, таких как шифрование, математические расчеты, архивация больших объемов данных, подсчет контрольных сумм и других подобных задачах, экономия каждого такта процессора может дать значительный прирост общей скорости работы программы.
В руководстве по оптимизации "AMD Athlon Processor x86 Code Optimization Guide" вопрос замены деления умножением расписан очень подробно. Рассмотрены частные случаи деления, такие как деление на степень двойки, описан выбор алгоритма для знакового и беззнакового деления и приведен код для вычисления вспомогательных корректирующих значений. Кроме этого, в руководстве описаны методы оптимизации и других математических операций. Даже если вы никогда не будете использовать на практике замену деления умножением, почитать о других способах оптимизации будет очень полезно.
Читать статью целиком »
Просмотров: 14413 | Комментариев: 4
Расчет энтропии на Ассемблере
29.06.2012 | Категория: Образ мышления: Assembler | Автор: ManHunter
Энтропия - это количество информации, приходящейся на одно элементарное сообщение источника, вырабатывающего статистически независимые сообщения. Говоря проще, это условный коэффициент, показывающий распределение уникальных элементов в массиве данных. На практике, к примеру, анализаторы исполняемых файлов используют подсчет энтропии секции кода как часть эвристики, для определения насколько упакованы или зашифрованы файлы. Чем выше показатель энтропии - тем выше вероятность, что данные уже упакованы или зашифрованы, и тем меньше они могут быть подвергнуты повторной компрессии. Математическая формула расчета энтропии следующая:Формула расчета энтропии
Где p(i) - количество каждого уникального символа в строке, разделенное на общую длину строки. Программно это легко реализуется. Так, строка '012345' имеет показатель энтропии 2.58, строка '001122', так же как и '222200001111' - 1.58, а строка любой длины, состоящая из одинаковых символов, имеет нулевую энтропию. Я написал такую функцию на Ассемблере для расчета энтропии произвольного блока памяти:
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------------------------
- ; Функция расчета энтропии блока памяти
- ; by ManHunter / PCL
- ; http://www.manhunter.ru
- ;
- ; Параметры:
- ; szStr - указатель на блок памяти для расчета
- ; dLen - размер блока в байтах
- ; lpRes - указатель на приемник результата (DWORD)
- ;-----------------------------------------------------------------------
- proc CalcEntropy szStr:DWORD, dLen:DWORD, lpRes:DWORD
- locals
- count dd ? ; Количество символов
- cnt rd 256 ; Счетчики символов
- endl
- pusha
- ; Инициализация сопроцессора
- finit
- ; Обнулить счетчики символов
- lea edi,[cnt]
- mov ecx,256
- xor eax,eax
- rep stosd
- ; Подсчет количества символов
- mov esi,[szStr]
- mov ecx,[dLen]
- .loc_count_chars:
- xor eax,eax
- lodsb
- shl eax,2
- inc dword [cnt+eax]
- loop .loc_count_chars
- ; Начальное значение энтропии
- fldz
- ; Расчет энтропии для каждого символа
- mov ecx,256
- .loc_calc_entr:
- dec ecx
- ; Получить количества символов
- mov eax,ecx
- shl eax,2
- mov eax,[cnt+eax]
- ; Нулевые количества пропускаем
- or eax,eax
- jz @f
- mov [count],eax
- fild [dLen] ; Длина строки
- fild [count] ; Количество символов
- fdiv st0,st1 ; P(i) = SUM(i)/total
- fst st1 ; Скопировать st0 в st1
- fchs ; Изменить знак
- fxch st1 ; Поменять местами регистры
- fyl2x ; H(i) = -P(i)*log2(P(i))
- fadd st1,st0 ; H = H+H(i)
- ffree st0
- fincstp ; Почистить стек
- @@:
- ; Все символы обработали?
- or ecx,ecx
- jnz .loc_calc_entr
- ; Записать значение в ячейку памяти
- mov eax,[lpRes]
- fstp dword [eax]
- ffree st0
- fincstp ; Почистить стек
- popa
- ret
- endp
Читать статью целиком »
Просмотров: 6090 | Комментариев: 1