
Несколько полезных функций на Ассемблере

Несколько полезных функций на Ассемблере
За время программирования на Ассемблере у меня накопилось несколько полезных решений. Выделять под каждое из них отдельную статью не хочется, а держать под рукой пригодится. Поэтому все сложу сюда, по мере надобности буду пополнять.
Начну с функции очень быстрого копирования одного участка памяти в другой. Фишка в том, что основная часть строки копируется по 4 байта DWORD'ами, а остаток дописывается побайтно. Это дает нехилый выигрыш в скорости.
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого копирования участка памяти
- ;-----------------------------------------------------
- ; lpDst - указатель на приемник
- ; lpSrc - указатель на источник
- ; dSize - размер копируемого блока
- ;-----------------------------------------------------
- proc _memcopy lpDst:DWORD, lpSrc:DWORD, dSize:DWORD
- pusha
- ; Установить указатели на источник и приемник
- cld
- mov edi,[lpDst]
- mov esi,[lpSrc]
- mov ecx,[dSize]
- push ecx
- ; Разделить на 4 и получить длину в DWORD
- shr ecx,2
- ; Скопировать основную часть строки DWORD'ами
- rep movsd
- pop ecx
- ; Получить остаток от деления на 4
- and ecx,3
- ; Скопировать остаток строки байтами
- rep movsb
- popa
- ret
- endp
Еще один вариант копирования. Он более красивый по реализации, но менее эффективный по производительности за счет использования переходов и, соответственно, невозможности использования конвейера команд процессора.
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого копирования участка памяти
- ;-----------------------------------------------------
- ; lpDst - указатель на приемник
- ; lpSrc - указатель на источник
- ; dSize - размер копируемого блока
- ;-----------------------------------------------------
- proc _memcopy lpDst:DWORD, lpSrc:DWORD, dSize:DWORD
- pusha
- ; Установить указатели на источник и приемник
- cld
- mov edi,[lpDst]
- mov esi,[lpSrc]
- mov ecx,[dSize]
- ; Если есть остаток от деления на 2
- shr ecx,1
- jnc @f
- ; Скопировать один байт
- movsb
- @@:
- ; Если есть остаток от деления на 4
- shr ecx,1
- jnc @f
- ; Скопировать слово
- movsw
- @@:
- ; Остаток строки скопировать двойными словами
- rep movsd
- popa
- ret
- endp
Аналог функции lstrlen - получение длины строки. На входе адрес строки в формате ASCIIZ, на выходе EAX - длина строки.
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция получения длины строки
- ;-----------------------------------------------------
- ; lpStr - указатель на строку ASCIIZ
- ; На выходе: EAX - длина строки без учета завершающего
- ; нулевого байта
- ;-----------------------------------------------------
- proc _lstrlen lpStr:DWORD
- push edi ecx
- cld
- mov edi,[lpStr]
- xor ecx,ecx
- dec ecx
- xor eax,eax
- repne scasb
- not ecx
- dec ecx
- mov eax,ecx
- pop ecx edi
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция получения длины строки (Fast)
- ;-----------------------------------------------------
- ; lpStr - указатель на строку ASCIIZ
- ; На выходе: EAX - длина строки без учета завершающего
- ; нулевого байта
- ;-----------------------------------------------------
- proc _lstrlen lpStr:DWORD
- mov eax, [lpStr]
- sub eax, 4
- @@:
- add eax, 4
- cmp byte [eax], 0
- je .szlen_lb1
- cmp byte [eax+1], 0
- je .szlen_lb2
- cmp byte [eax+2], 0
- je .szlen_lb3
- cmp byte [eax+3], 0
- jne @b
- sub eax, [lpStr]
- add eax, 3
- ret
- .szlen_lb3:
- sub eax, [lpStr]
- add eax, 2
- ret
- .szlen_lb2:
- sub eax, [lpStr]
- add eax, 1
- ret
- .szlen_lb1:
- sub eax, [lpStr]
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция получения длины строки
- ;-----------------------------------------------------
- ; lpStr - указатель на строку ASCIIZ
- ; На выходе: EAX - длина строки без учета завершающего
- ; нулевого байта
- ;-----------------------------------------------------
- proc _lstrlen lpStr:DWORD
- push ebx
- mov ebx,[lpStr]
- xor eax,eax
- @@:
- cmp byte[ebx+eax],0
- je @f
- inc eax
- jmp @b
- @@:
- pop ebx
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; lpStr - указатель на строку ASCIIZ
- ; На выходе: EAX - длина строки без учета завершающего
- ; нулевого байта
- ;-----------------------------------------------------
- proc _lstrlen lpStr:DWORD
- mov eax, [lpStr]
- dec eax
- @@:
- inc eax
- cmp byte [eax],0
- jne @b
- sub eax, [lpStr]
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; lpStr - указатель на строку ASCIIZ
- ; На выходе: EAX - длина строки без учета завершающего
- ; нулевого байта
- ;-----------------------------------------------------
- proc _lstrlen lpStr:DWORD
- mov eax, [lpStr]
- @@:
- cmp byte [eax],1
- inc eax
- jnc @b
- sbb eax, [lpStr]
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого копирования строки
- ; используются функции _lstrlen, _memcopy
- ;-----------------------------------------------------
- ; lpDst - указатель на приемник
- ; lpSrc - указатель на строку ASCIIZ
- ;-----------------------------------------------------
- proc _lstrcpy lpDst:DWORD, lpSrc:DWORD
- pusha
- stdcall _lstrlen,[lpSrc]
- inc eax
- stdcall _memcopy,[lpDst],[lpSrc],eax
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого слияния двух строк
- ; используются функции _lstrlen, _lstrcpy
- ;-----------------------------------------------------
- ; lpDst - указатель на исходную строку ASCIIZ
- ; lpSrc - указатель на добавляемую строку ASCIIZ
- ;-----------------------------------------------------
- proc _lstrcat lpDst:DWORD, lpSrc:DWORD
- pusha
- stdcall _lstrlen,[lpDst]
- add eax,[lpDst]
- stdcall _lstrcpy,eax,[lpSrc]
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого сравнения двух строк
- ; используется функция _lstrlen
- ;-----------------------------------------------------
- ; lpStr1 - указатель на первую строку ASCIIZ
- ; lpStr2 - указатель на вторую строку ASCIIZ
- ; На выходе: EAX=0 - строки совпадают
- ; EAX=1 - строки различаются
- ;-----------------------------------------------------
- proc _lstrcmp lpStr1:DWORD, lpStr2:DWORD
- push ecx esi edi
- mov esi,[lpStr1]
- mov edi,[lpStr2]
- stdcall _lstrlen,esi
- mov ecx,eax
- stdcall _lstrlen,edi
- cmp ecx,eax
- ; Длина строк не совпадает
- jnz @f
- cld
- repe cmpsb
- @@:
- setnz al
- movsx eax,al
- pop edi esi ecx
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого сравнения двух строк
- ;-----------------------------------------------------
- ; lpStr1 - указатель на первую строку ASCIIZ
- ; lpStr2 - указатель на вторую строку ASCIIZ
- ; На выходе: EAX=0 - строки совпадают
- ; EAX=1 - строки различаются
- ;-----------------------------------------------------
- proc _lstrcmp lpStr1:DWORD,lpStr2:DWORD
- push esi edi
- mov esi,[lpStr1] ; Указатели на строки
- mov edi,[lpStr2]
- xor eax,eax ; Предположим, что строки равны
- @@:
- lodsb ; Сравнить следующие символы
- mov ah,[edi]
- inc edi
- or al,al ; Первая строка закончилась?
- jz @f ; Да
- cmp al,ah ; Символы совпадают?
- je @b ; Да, проверить следующий символ
- @@:
- or ah,ah ; Вторая строка закончилась?
- je @f ; Да, строки равны
- xor eax,eax ; Строки не совпадают
- inc eax
- @@:
- pop edi esi
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого регистронезависимого сравнения
- ; двух строк
- ;-----------------------------------------------------
- ; lpStr1 - указатель на первую строку ASCIIZ
- ; lpStr2 - указатель на вторую строку ASCIIZ
- ; На выходе: EAX=0 - строки совпадают
- ; EAX=1 - строки различаются
- ;-----------------------------------------------------
- proc _lstrcmpi lpStr1:DWORD,lpStr2:DWORD
- push esi edi
- mov esi,[lpStr1] ; Указатели на строки
- mov edi,[lpStr2]
- xor eax,eax ; Предположим, что строки равны
- .loc_compare:
- lodsb ; Сравнить следующие символы
- mov ah,[edi]
- inc edi
- cmp al,ah ; Символы совпадают?
- jne @f ; Нет
- or al,al ; Строки закончились?
- jz .loc_ret ; Да, строки совпадают
- jmp .loc_compare ; Проверить следующий символ
- @@:
- and eax,0DFDFh ; Оба символа в верхний регистр
- cmp al,'A'
- jb .loc_not_equal
- cmp al,'Z'
- ja .loc_not_equal
- cmp al,ah ; Разница была только в регистре?
- je .loc_compare ; Да, следующий символ
- .loc_not_equal:
- xor eax,eax ; Строки не совпадают
- inc eax
- .loc_ret:
- pop edi esi
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------
- ; Функция быстрого заполнения блока памяти значениями
- ;-----------------------------------------------------
- ; lpDst - указатель на приемник
- ; dVal - заполнитель (берется младший байт)
- ; dSize - размер заполняемого блока
- ;-----------------------------------------------------
- proc _fillmem lpDst:DWORD, dVal:DWORD, dSize:DWORD
- pusha
- cld
- mov edi,[lpDst]
- mov eax,[dVal]
- ; Оставить только младший байт
- movzx eax,al
- mov edx,01010101h
- ; Теперь в EAX будет DWORD-заполнитель
- mul edx
- mov ecx,[dSize]
- push ecx
- ; Разделить на 4 и получить длину в DWORD
- shr ecx,2
- ; Заполнить основную часть строки DWORD'ами
- rep stosd
- pop ecx
- ; Получить остаток от деления на 4
- and ecx,3
- ; Заполнить остаток строки байтами
- rep stosb
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------
- ; Перевести строку ASCIIZ в нижний регистр
- ;----------------------------------------------------
- ; szStr - указатель на строку
- ;----------------------------------------------------
- proc lower_case szStr:DWORD
- pusha
- mov esi,[szStr]
- mov edi,esi
- cld
- .loc_loop:
- lodsb
- cmp al,'A'
- jb @f
- cmp al,'Z'
- ja @f
- or al,060h
- @@:
- stosb
- or al,al
- jnz .loc_loop
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------
- ; Перевести строку ASCIIZ в верхний регистр
- ;----------------------------------------------------
- ; szStr - указатель на строку
- ;----------------------------------------------------
- proc upper_case szStr:DWORD
- pusha
- mov esi,[szStr]
- mov edi,esi
- cld
- .loc_loop:
- lodsb
- cmp al,'a'
- jb @f
- cmp al,'z'
- ja @f
- and al,0DFh
- @@:
- stosb
- or al,al
- jnz .loc_loop
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ; Символ из AL в заглавную букву
- mov dl,al
- sub dl,'a'
- cmp dl,26
- sbb dh,dh
- and dh,20h
- sub al,dh
- ; Символ из AL в строчную букву
- mov dl,al
- sub dl,'A'
- cmp dl,26
- sbb dh,dh
- and dh,20h
- add al,dh
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------
- ; Очистить строку ASCIIZ от всех символов кроме цифр
- ;----------------------------------------------------
- ; szString - указатель на исходную строку
- ; szFiltered - указатель на отфильтрованную строку
- ;----------------------------------------------------
- proc filter_digits szString:DWORD, szFiltered:DWORD
- pusha
- mov esi,[szString] ; Исходная строка
- mov edi,[szFiltered] ; Отфильтрованная строка
- @@:
- lodsb
- or al,al
- jz @f
- mov bl,al
- add bl,(256-'0') ; Начальный символ интервала
- sub bl,10 ; Длина интервала
- jnb @b
- stosb
- jmp @b
- @@:
- stosb
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ; my_path описан в данных как буфер размером MAX_PATH+1
- mov edi,my_path
- invoke GetModuleFileName,NULL,edi,MAX_PATH
- add edi,eax
- std
- mov ecx,eax
- mov al,'\'
- repne scasb
- mov byte [edi+2],0
- cld
- ; Теперь в my_path содержится каталог запуска с завершающим '\'
Code (Assembler) : Убрать нумерацию
- ; Вариант №1
- @@: neg eax
- js @b
- ; EAX = |EAX|
- ;------------------------------------
- ; Вариант №2
- mov edx, eax
- sar edx, 31
- xor eax, edx
- sub eax, edx
- ; EAX = |EAX|
Code (Assembler) : Убрать нумерацию
- ; EAX = min(EAX,EBX)
- sub ebx, eax
- sbb ecx, ecx
- and ecx, ebx
- add eax, ecx
Code (Assembler) : Убрать нумерацию
- ; Если EAX!=0, то EAX=EBX, иначе EAX=ECX
- cmp eax, 1
- sbb eax, eax
- and ecx, eax
- xor eax, -1
- and eax, ebx
- or eax, ecx
Code (Assembler) : Убрать нумерацию
- ; Идеальный вариант с использованием штатной команды XCHG
- xchg eax,ebx
- ; Классический вариант с использованием стека
- push eax
- push ebx
- pop eax
- pop ebx
- ; Хитрый вариант, иногда встречается на олимпиадах по программированию
- xor eax,ebx
- xor ebx,eax
- xor eax,ebx
- ; Еще один хитрый вариант обмена с вычитанием и сложением
- sub eax,ebx
- add ebx,eax
- neg eax
- add eax,ebx
Code (Assembler) : Убрать нумерацию
- ; Первый вариант
- cmp ebx,ecx
- sbb eax,eax ; ebx<ecx ? -1 : 0
- xor ebx,ecx
- and eax,ebx ; ebx<ecx ? ebx^ecx : 0
- xor ecx,eax ; ebx<ecx ? ebx : ecx
- xor ebx,ecx ; ebx<ecx ? ecx : ebx
- ; Второй вариант
- mov edx,[y]
- sub edx,[x]
- sbb ecx,ecx
- and ecx,edx
- add [x],ecx ; x=min(x,y)
- sub [y],ecx ; y=max(x,y)
Code (Assembler) : Убрать нумерацию
- ; EAX = первое число
- ; EDX = второе число
- neg eax
- jz loc_3
- loc_1:
- neg eax
- xchg edx,eax
- loc_2:
- sub eax,edx
- jg loc_2
- jnz loc_1
- loc_3:
- add eax,edx
- jnz loc_4
- inc eax
- loc_4:
- ; EAX = найденное значение НОД
Code (Assembler) : Убрать нумерацию
- ; EAX = первое число
- ; EBX = второе число
- cmp eax,ebx
- je loc_3
- jb loc_1
- xchg eax,ebx
- loc_1:
- mov ecx,eax
- loc_2:
- add eax,ecx
- push eax
- xor edx,edx
- div ebx
- pop eax
- or edx,edx
- jnz loc_2
- loc_3:
- ; EAX = найденное значение НОК
Code (Assembler) : Убрать нумерацию
- ; value = байт для преобразования
- ; result = буфер для получения результата
- proc byte2hex value:DWORD, result:DWORD
- pusha
- mov eax,[value]
- mov ecx,eax
- shr eax,4
- and ecx,15
- mov al,[.table+eax]
- mov ah,[.table+ecx]
- mov edx,[result]
- mov word [edx],ax
- popa
- ret
- .table db '0123456789ABCDEF'
- endp
Code (Assembler) : Убрать нумерацию
- ; value = байт для преобразования
- ; result = буфер для получения результата
- proc byte2hex value:DWORD, result:DWORD
- pusha
- mov eax,[value]
- mov ebx,.table
- mov ah,al
- and al,00001111b
- xlat byte [ebx]
- xchg al,ah
- shr al,4
- xlat byte [ebx]
- mov edi,[result]
- stosw
- popa
- ret
- .table db '0123456789ABCDEF'
- endp
Code (Assembler) : Убрать нумерацию
- ; value = байт для преобразования
- ; result = буфер для получения результата
- proc byte2hex value:DWORD, result:DWORD
- pusha
- mov eax,[value]
- mov ah,al
- and al,15
- cmp al,10
- sbb al,69h
- das
- xchg al,ah
- shr al,4
- cmp al,10
- sbb al,69h
- das
- mov edi,[result]
- stosw
- popa
- ret
- endp
Code (Assembler) : Убрать нумерацию
- ; EAX = конвертируемое значение
- ; EDI = указатель на строку-результат
- ; Флаг направления сброшен (CLD)
- mov ecx,8
- @@:
- rol eax,4
- push eax
- and al,0Fh
- daa
- add al,0F0h
- adc al,40h
- stosb
- pop eax
- loop @b
- mov al,0
- stosb
Code (Assembler) : Убрать нумерацию
- ; EAX = конвертируемое значение
- ; EDI = указатель на строку-результат
- ; Флаг направления сброшен (CLD)
- proc num_to_str
- call @f
- mov al,0
- stosb
- ret
- @@:
- xor edx,edx
- ; Основание системы счисления
- mov ebx,10
- div ebx
- push edx
- or eax,eax
- jz @f
- call @b
- @@:
- pop eax
- add al,'0'
- stosb
- retn
- endp
Code (Assembler) : Убрать нумерацию
- ; В сегменте данных
- power dd 9
- x dd 3
- result dd ?
- ; В коде (для примера считаем 3^9)
- finit
- fild [power]
- fild [x]
- fyl2x
- fld1
- fld st1
- fprem
- f2xm1
- faddp
- fscale
- fxch st1
- fstp st0
- fistp [result]
- ; result = 3^9
Code (Assembler) : Убрать нумерацию
- ; Делимое A
- mov eax,8
- ; Делитель B
- mov ecx,9
- ; (A+A+B)/(B+B)
- add eax,eax
- add eax,ecx
- add ecx,ecx
- xor edx,edx
- div ecx
- ; EAX - округленное частное
Code (Assembler) : Убрать нумерацию
- ; ECX = X, должно быть в диапазоне [X_MIN..X_MAX]
- ; EDX = Y, должно быть в диапазоне [Y_MIN..Y_MAX]
- sub ecx,X_MIN
- cmp ecx,X_MAX-X_MIN
- sbb al,al
- sub edx,Y_MIN
- cmp edx,Y_MAX-Y_MIN
- adc al,0
- ; Как минимум одно значение не входит в диапазон
- jae not_in_ranges
Code (Assembler) : Убрать нумерацию
- ; Реверс битов (8 битов)
- mov eax,12h
- mov ah,al
- shr al,1
- and al,0x55
- shl ah,1
- and ah,0xAA
- or al,ah
- mov ah,al
- shr al,2
- and al,0x33
- shl ah,2
- and ah,0xCC
- or al,ah
- ; AL = 84h
- ; Реверс битов (16 битов)
- mov eax,1234h
- mov bx,ax
- shr ax,1
- and ax,0x5555
- shl bx,1
- and bx,0xAAAA
- or ax,bx
- mov bx,ax
- shr ax,2
- and ax,0x3333
- shl bx,2
- and bx,0xCCCC
- or ax,bx
- ; AX = 84C2h
- ; Реверс битов (32 бита)
- mov eax,12345678h
- mov ebx,eax
- shr eax,1
- and eax,0x55555555
- shl ebx,1
- and ebx,0xAAAAAAAA
- or eax,ebx
- mov ebx,eax
- shr eax,2
- and eax,0x33333333
- shl ebx,2
- and ebx,0xCCCCCCCC
- or eax,ebx
- ; EAX = 84C2A6E1h
- ; Реверс байтов (16 битов)
- mov eax,1234h
- mov bx,ax
- shr ax,8
- and ax,0x00FF
- shl bx,8
- and bx,0xFF00
- or ax,bx
- ; EAX = 3412h
- ; Реверс байтов (32 бита)
- mov eax,12345678h
- mov ebx,eax
- shr eax,8
- and eax,0x00FF00FF
- shl ebx,8
- and ebx,0xFF00FF00
- or eax,ebx
- mov ebx,eax
- shr eax,16
- and eax,0x0000FFFF
- shl ebx,16
- and ebx,0xFFFF0000
- or eax,ebx
- ; EAX = 78563412h
Просмотров: 28919 | Комментариев: 34

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Loloshka
(28.05.2021 в 17:58):
Спасибо!

ManHunter
(28.05.2021 в 07:47):
Да практически все то же самое, только вместо байтовых операций будут операции с WORD'ами.

Loloshka
(28.05.2021 в 01:45):
А как лучше будет реализовать для юникодных строк подсчет количества символов?

ManHunter
(10.11.2020 в 16:01):
Два последних.

Petya
(10.11.2020 в 15:43):
А какой из _lstrlen самый быстрый? 2й?

ManHunter
(10.07.2018 в 12:47):
Добавлены функции преобразования байта в hex-строку.

ManHunter
(12.06.2018 в 12:44):
IOAN, садись, двойка. Избыточный код.

IOAN
(10.06.2018 в 10:07):
proc _lstrlen lpStr:DWORD
mov edx, [lpStr]
xor ecx,ecx
xor eax,eax
dec eax
@@:
inc eax
cmp [edx+eax],cl
jne @b
ret
endp
mov edx, [lpStr]
xor ecx,ecx
xor eax,eax
dec eax
@@:
inc eax
cmp [edx+eax],cl
jne @b
ret
endp

ManHunter
(23.03.2018 в 11:03):
Ну и?

Константин
(23.03.2018 в 10:56):
Привет. Сразу к делу. Есть калькулятор на vb2008. Умножает до 32000000 знаков, после запятой до 10000 знаков. На умножение 1000000 на 1000000 знаков уходит 28 секунд. Проблем в том, что массивы размерностью >22000000 не проходят. Умножение разбито на потоки. Стоит ещё вопрос алгоритма деления
длинных чисел на длинные. Алгоритм деления на числа до 18 знаков работает быстро, а выше есть задумки , на писать на ассемблере.
длинных чисел на длинные. Алгоритм деления на числа до 18 знаков работает быстро, а выше есть задумки , на писать на ассемблере.

ManHunter
(30.06.2016 в 18:28):
Добавил функции перевода строки в верхний и нижний регистр.

ManHunter
(03.12.2013 в 23:03):
Главное, чтобы не в shareware. А в остальном можно как угодно.

Heavyiron
(03.12.2013 в 22:56):
Благодарю за добавление в статью, только тег [code] потерялся. Кстати, забыл уточнить про лицензию(в глаза по крайней мере нигде не бросилось): можно ли использовать наработки из этого раздела в GPL-ном проекте?

Heavyiron
(01.12.2013 в 19:12):
Коллега по проекту 0CodErr выдал код еще на 3 байта короче и чуть быстрее (из за отсутствия необходимости засовывать регистры в стек):
proc _lstrlen lpStr:DWORD
mov eax, [lpStr]
dec eax
@@:
inc eax
cmp [eax], byte 0
jne @b
sub eax, [lpStr]
ret
endp
_http://board.kolibrios.org/viewtopic.php?p=54336#p54336
proc _lstrlen lpStr:DWORD
mov eax, [lpStr]
dec eax
@@:
inc eax
cmp [eax], byte 0
jne @b
sub eax, [lpStr]
ret
endp
_http://board.kolibrios.org/viewtopic.php?p=54336#p54336

ManHunter
(24.11.2013 в 11:44):
Ну вот, блин, в погоне за наворотами забыл самый простой вариант :)
Добавил, спасибо!
Добавил, спасибо!

Heavyiron
(24.11.2013 в 05:04):
Не мое. По размеру код чуть меньше (4 байта), и чуть быстрее (~6%) чем приведенный здесь вариант №1:
;-----------------------------------------------------
; Функция получения длины строки
;-----------------------------------------------------
; lpStr - указатель на строку ASCIIZ
; На выходе: EAX - длина строки без учета завершающего
; нулевого байта
;-----------------------------------------------------
proc _lstrlen lpStr:DWORD
push ebx
mov ebx,[lpStr]
xor eax,eax
@@: cmp byte[ebx+eax],0
je @f
inc eax
jmp @b
@@: pop ebx
ret
endp
;-----------------------------------------------------
; Функция получения длины строки
;-----------------------------------------------------
; lpStr - указатель на строку ASCIIZ
; На выходе: EAX - длина строки без учета завершающего
; нулевого байта
;-----------------------------------------------------
proc _lstrlen lpStr:DWORD
push ebx
mov ebx,[lpStr]
xor eax,eax
@@: cmp byte[ebx+eax],0
je @f
inc eax
jmp @b
@@: pop ebx
ret
endp

ManHunter
(26.03.2012 в 20:32):
Красивее - да, быстрее - сомневаюсь. Хотя для небольших проектов очень даже ничего. Добавил в статью, спасибо!

Alexey32
(26.03.2012 в 19:50):
По-моему, так лучше:
proc _memcopy lpDst:DWORD, lpSrc:DWORD, dSize:DWORD
pusha
; Установить указатели на источник и приемник
cld
mov edi,[lpDst]
mov esi,[lpSrc]
mov ecx,[dSize]
shr ecx,1 ;проверка на чётность и деление на 2
jnc @f
movsb ;по необходимости копируем байт
@@:
shr ecx,1 ;проверка на делимость на 4 и деление ещё на 2
jnc @f
movsw ;по необходимости копируем слово
@@:
rep movsd ;копируем оставшиеся двойные слова
popa
ret
endp
proc _memcopy lpDst:DWORD, lpSrc:DWORD, dSize:DWORD
pusha
; Установить указатели на источник и приемник
cld
mov edi,[lpDst]
mov esi,[lpSrc]
mov ecx,[dSize]
shr ecx,1 ;проверка на чётность и деление на 2
jnc @f
movsb ;по необходимости копируем байт
@@:
shr ecx,1 ;проверка на делимость на 4 и деление ещё на 2
jnc @f
movsw ;по необходимости копируем слово
@@:
rep movsd ;копируем оставшиеся двойные слова
popa
ret
endp

ManHunter
(22.08.2011 в 16:03):
Зачем городить все в одну кучу? Кому надо - добавят обработку исключений.

DJK
(22.08.2011 в 16:01):
ваши идеи хорошы, но при работе с буферами памяти, размер которых не удается достоверно определить в функции, следует использовать SEH иначе могут функции повести себя совсем не так как хотелось бы.

ManHunter
(10.07.2011 в 14:35):
Добавил еще один шустрый вариант сравнения строк _lstrcmp и регистронезависимое сравнение строк _lstrcmpi

ManHunter
(02.06.2011 в 00:42):
Надо будет позаимствовать оттуда счетчики времени. А так - отличная работа!

disciple27
(01.06.2011 в 00:04):
ManHunter, ещё раз здравствуйте!
Дело было вечером, делать было нечего... http://ifolder.ru/23887012
Дело было вечером, делать было нечего... http://ifolder.ru/23887012

disciple27
(30.05.2011 в 23:56):
ManHunter, всегда пожалуйста - правда это не моё решение, а всё из того же масма (а точнее masmlib которое, пардон за плагиат), которое я нагло оттуда позаимствовал, обожаю всё на свете портировать под FASM :)

ManHunter
(30.05.2011 в 16:28):
disciple27, добавил альтернативную функцию _lstrlen из твоего примера. Спасибо!

disciple27
(29.05.2011 в 23:58):
ManHunter огромное тебе спасибо за функции, особенно понравилась 'получение каталога' оригинально :)
В долгу не останусь, так как еще понравились MASM'овые счётчики по ссылкам, я их тоже немного позаимствовал ;) http://ifolder.ru/23841188
В долгу не останусь, так как еще понравились MASM'овые счётчики по ссылкам, я их тоже немного позаимствовал ;) http://ifolder.ru/23841188

ManHunter
(20.05.2011 в 20:14):
Фигасе там народ отжигает :) А я думал что это я извращенец :)

Voffka
(20.05.2011 в 19:42):
И еще тесты разных алгоритмов.
memcopy
http://www.masm32.com/board/in...topic=6445.0
http://www.masm32.com/board/in...topic=2471.0
strcat
http://www.masm32.com/board/in...topic=2555.0
strcmp
http://www.masm32.com/board/in...topic=2508.0
memcopy
http://www.masm32.com/board/in...topic=6445.0
http://www.masm32.com/board/in...topic=2471.0
strcat
http://www.masm32.com/board/in...topic=2555.0
strcmp
http://www.masm32.com/board/in...topic=2508.0

Voffka
(20.05.2011 в 19:22):
Тесты разных strLen
http://www.masm32.com/board/in...topic=1807.0
http://www.masm32.com/board/in...topic=1807.0

ManHunter
(20.05.2011 в 15:58):
Эх, не писал ты вирусов под MS-DOS :))))

zummenix
(20.05.2011 в 15:58):
Да, конечно esi. А в оптимизации я нуб :)

ManHunter
(20.05.2011 в 15:42):
А разве не mov ESI,[lpStr] ? И зачем xor eax,eax, если можно сравнивать с нулем al? Флаг направления тоже желательно устанавливать. Тогда уж надо что-то типа такого:
xor ecx,ecx
mov esi,[lpStr]
cld
@@:
inc ecx
lodsb
or al,al
jnz @b
dec ecx
Плюс команда перехода подавляет конвейер команд процессора, теряется производительность :)
xor ecx,ecx
mov esi,[lpStr]
cld
@@:
inc ecx
lodsb
or al,al
jnz @b
dec ecx
Плюс команда перехода подавляет конвейер команд процессора, теряется производительность :)

zummenix
(20.05.2011 в 15:41):
Для получения длины строки мне нравится такой вот способ :)
xor eax,eax
xor ecx,ecx
mov edi,[lpStr]
@@:
inc ecx
lodsb
test eax,eax
jne @R
dec ecx
xor eax,eax
xor ecx,ecx
mov edi,[lpStr]
@@:
inc ecx
lodsb
test eax,eax
jne @R
dec ecx

Всеволод
(20.05.2011 в 12:14):
Ассемблер — прикольная штука. Все хочу сесть, поучить :)

Добавить комментарий
Заполните форму для добавления комментария
