Blog. Just Blog

Быстрый поиск

Введите фрагмент названия статьи для поиска

Преобразование строки в вещественное число на Ассемблере

31.05.2012 | Категория: Образ мышления: Assembler | Автор: ManHunter
Про преобразование строки в обычное число я уже писал, теперь задача посложнее - надо преобразовать строку в вещественное число с плавающей запятой (float). Для этого я написал вот такую функцию преобразования:
  1. ;------------------------------------------------------------
  2. ; Функция преобразования строки в вещественное число
  3. ; by ManHunter / PCL
  4. ; http://www.manhunter.ru
  5. ;
  6. ; Параметры:
  7. ;   lpStr - указатель на исходную строку в формате ASCIIZ
  8. ;   lpResult - указатель на переменную-приемник значения
  9. ; На выходе:
  10. ;   EAX = 1 - строка успешно преобразована
  11. ;   EAX = 0 - строка не может быть преобразована в число
  12. ;
  13. ; Примечание: переменная-приемник может иметь размер DWORD
  14. ; или QWORD, в зависимости от этого должна изменяться и
  15. ; функция (см. комментарии в конце кода). По умолчанию
  16. ; считается, что переменная имеет размер DWORD
  17. ;------------------------------------------------------------
  18. proc    string2float lpStr:DWORD, lpResult:DWORD
  19.         ; Локальные переменные
  20.         locals
  21.           dot    dd ?   ; Указатель на дробную часть
  22.           exp    dd ?   ; Указатель на экспоненту
  23.  
  24.           digit  dd ?   ; Цифра
  25.         endl
  26.  
  27.         pusha
  28.  
  29.         ; Проверка строки на валидность
  30.         mov     [digit],1
  31.  
  32.         mov     [exp],0
  33.         mov     [dot],0
  34.         mov     esi,[lpStr]
  35.         ; Минус или плюс может быть только в начале
  36.         cmp     byte [esi],'-'
  37.         je      @f
  38.         cmp     byte [esi],'+'
  39.         jne     .loc_chk_loop
  40. @@:
  41.         inc     esi
  42.  
  43.         ; После знака не может быть нуля
  44.         cmp     byte [esi],0
  45.         je      .loc_chk_error
  46. .loc_chk_loop:
  47.         ; В строке должны быть цифр, экспонента и не более одной точки
  48.         lodsb
  49.         or      al,al
  50.         jz      .loc_chk_complete
  51.         cmp     al,'e'
  52.         je      .loc_chk_exp
  53.         cmp     al,'E'
  54.         je      .loc_chk_exp
  55.         cmp     al,'.'
  56.         je      .loc_chk_dot
  57.         cmp     al,'0'
  58.         jb      .loc_chk_error
  59.         cmp     al,'9'
  60.         ja      .loc_chk_error
  61.         jmp     .loc_chk_loop
  62.  
  63. .loc_chk_dot:
  64.         ; Точка в строке уже есть?
  65.         cmp     [dot],0
  66.         ; Строка имеет некорректный формат
  67.         jne     .loc_chk_error
  68.  
  69.         ; Экспонента уже есть?
  70.         cmp     [exp],0
  71.         ; Строка имеет некорректный формат
  72.         jne     .loc_chk_error
  73.  
  74.         ; Указатель на дробную часть
  75.         mov     [dot],esi
  76.  
  77.         jmp     .loc_chk_loop
  78.  
  79. .loc_chk_exp:
  80.         ; Экспонента уже есть?
  81.         cmp     [exp],0
  82.         ; Строка имеет некорректный формат
  83.         jne     .loc_chk_error
  84.  
  85.         ; Указатель на начало экспоненты
  86.         mov     [exp],esi
  87.  
  88.         ; Сразу после экспоненты не может быть нуля
  89.         cmp     byte [esi],0
  90.         je      .loc_chk_error
  91.  
  92.         ; После экспоненты может быть знак
  93.         cmp     byte [esi],'-'
  94.         je      @f
  95.         cmp     byte [esi],'+'
  96.         jne     .loc_chk_loop
  97. @@:
  98.         inc     esi
  99.  
  100.         ; Сразу после минуса не может быть нуля
  101.         cmp     byte [esi],0
  102.         je      .loc_chk_error
  103.  
  104.         ; Проверить следующий символ
  105.         jmp     .loc_chk_loop
  106.  
  107. .loc_chk_error:
  108.         ; Строка не является числом
  109.         mov     [digit],0
  110.         jmp     .loc_ret
  111.  
  112. .loc_chk_complete:
  113.         ; Инициализация сопроцессора
  114.         finit
  115.  
  116.         ; Начальное значение числа
  117.         fldz
  118.  
  119.         ; Множитель и делитель
  120.         mov     [digit],10
  121.         fild    dword [digit]
  122.  
  123.         ; Запись значений до запятой
  124.         mov     esi,[lpStr]
  125.  
  126.         ; В начале строки минус?
  127.         cmp     byte [esi],'-'
  128.         je      @f
  129.         cmp     byte [esi],'+'
  130.         jne     .loc_before_dot
  131. @@:
  132.         inc     esi
  133.         ; Преобразование числа до запятой
  134. .loc_before_dot:
  135.         lodsb
  136.         ; Конец строки?
  137.         or      al,al
  138.         jz      .loc_complete
  139.  
  140.         cmp     al,'.'
  141.         je      .loc_complete_before_dot
  142.         cmp     al,'e'
  143.         je      .loc_exp
  144.         cmp     al,'E'
  145.         je      .loc_exp
  146.  
  147.         ; Очередная цифра
  148.         sub     al,'0'
  149.         movzx   eax,al
  150.         mov     [digit],eax
  151.  
  152.         ; Записать
  153.         fild    dword [digit]
  154.         fxch    st2
  155.         fmul    st0,st1
  156.         fxch    st2
  157.         fadd    st2,st0
  158.  
  159.         ffree   st0     ; Почистить стек
  160.         fincstp
  161.  
  162.         jmp     .loc_before_dot
  163.  
  164.         ; Преобразование дробной части числа
  165. .loc_complete_before_dot:
  166.         ; Дробная часть есть?
  167.         cmp     [dot],0
  168.         je      .loc_complete_after_dot
  169.  
  170.         ; Экспонента есть?
  171.         cmp     [exp],0
  172.         je      @f
  173.  
  174.         ; Указатель на начало экспоненты
  175.         mov     esi,[exp]
  176.         jmp     .loc_start_after_dot
  177. @@:
  178.         ; Иначе перенести указатель на конец строки
  179.         xor     ecx,ecx
  180.         dec     ecx
  181.         xor     eax,eax
  182.         mov     edi,esi
  183.         repne   scasb
  184.  
  185.         mov     esi,edi
  186.  
  187. .loc_start_after_dot:
  188.         std
  189.         dec     esi
  190.         dec     esi
  191.  
  192.         ; Дробная часть
  193.         fldz
  194.         fxch    st1
  195. .loc_after_dot:
  196.         lodsb
  197.         ; Конец дробной части?
  198.         cmp     al,'.'
  199.         je      .loc_complete_after_dot
  200.  
  201.         ; Очередная цифра
  202.         sub     al,'0'
  203.         movzx   eax,al
  204.         mov     [digit],eax
  205.  
  206.         ; Записать
  207.         fild    dword [digit]
  208.         fadd    st2,st0
  209.         fxch    st2
  210.         fdiv    st0,st1
  211.         fxch    st2
  212.  
  213.         ffree   st0     ; Почистить стек
  214.         fincstp
  215.  
  216.         jmp     .loc_after_dot
  217.  
  218. .loc_complete_after_dot:
  219.         ; Сбросить флаг направления
  220.         cld
  221.  
  222.         ffree   st0     ; Почистить стек
  223.         fincstp
  224.  
  225.         ; Сложить дробную и целую часть
  226.         fadd    st1,st0
  227.  
  228. .loc_exp:
  229.         ; Экспонента есть?
  230.         cmp     [exp],0
  231.         je      .loc_complete
  232.  
  233.         ; Получить значение экспоненты
  234.         xor     ecx,ecx
  235.  
  236.         mov     esi,[exp]
  237.         ; В начале строки минус?
  238.         cmp     byte [esi],'-'
  239.         je      @f
  240.         cmp     byte [esi],'+'
  241.         jne     .loc_start_exp
  242. @@:
  243.         inc     esi
  244. .loc_start_exp:
  245.         lodsb
  246.         or      al,al
  247.         jz      .loc_end_exp
  248.  
  249.         sub     al,'0'
  250.         movzx   eax,al
  251.         imul    ecx,10
  252.         add     ecx,eax
  253.  
  254.         jmp     .loc_start_exp
  255. .loc_end_exp:
  256.  
  257.         or      ecx,ecx
  258.         jz      .loc_complete
  259.  
  260.         ffree   st0     ; Почистить стек
  261.         fincstp
  262.  
  263.         mov     [digit],10
  264.         fild    dword [digit]
  265.  
  266.         ; Делить или умножать?
  267.         mov     esi,[exp]
  268.         cmp     byte [esi],'-'
  269.         je      .loc_exp_divide
  270.  
  271. .loc_exp_multiple:
  272.         fmul    st1,st0
  273.         loop    .loc_exp_multiple
  274.         jmp     .loc_complete
  275.  
  276. .loc_exp_divide:
  277.         fdiv    st1,st0
  278.         loop    .loc_exp_divide
  279.  
  280. .loc_complete:
  281.         ffree   st0     ; Почистить стек
  282.         fincstp
  283.  
  284.         ; В начале строки минус?
  285.         mov     esi,[lpStr]
  286.         cmp     byte [esi],'-'
  287.         jne     @f
  288.  
  289.         ; Изменить знак числа
  290.         fchs
  291. @@:
  292.         ; Записать значение в ячейку памяти
  293.         mov     eax,[lpResult]
  294.         ; Если требуется повышенная точность, то приемник
  295.         ; должен иметь размер QWORD, а следующую команду
  296.         ; надо заменить на fstp qword [eax]
  297.         fstp    dword [eax]
  298.  
  299.         ; Успешное преобразование
  300.         mov     [digit],1
  301. .loc_ret:
  302.         popa
  303.  
  304.         ; Результат преобразования
  305.         mov     eax,[digit]
  306.  
  307.         ret
  308. endp
Функция универсальная, понимает положительные и отрицательные, нормализованные и денормализованные числа, с любой мантиссой и экспонентой. Например, "123.45", "-1.67e+4", "99.999e-99", "45e004" и т.п. Также выполняется проверка на корректность исходной строки. Заведения дополнительных переменных в сегменте данных не требуется. Параметры вызова: lpStr - указатель на строку для преобразования, lpResult - указатель на переменную-приемник для записи результата, ее размер может быть DWORD или QWORD, в зависимости от желаемой точности результата. Соответственно, вы должны изменить команду (строка 297 в листинге) на fstp dword [eax] или fstp qword [eax].

Читать статью целиком »
Просмотров: 8961 | Комментариев: 13

Замена подстроки в строке на Ассемблере

28.03.2012 | Категория: Образ мышления: Assembler | Автор: ManHunter
Во всех языках высокого уровня среди функций работы со строками присутствуют функции замены заданной подстроки в строке. В Ассемблере такой функции нет, как нет ее и среди функций стандартных библиотек. Замена подстроки на строку такой же длины обычно сложностей не составляет, так как ее можно выполнить прямо в исходной строке без выделения дополнительной памяти. Замена на строку произвольной длины, в том числе и пустую, будет посложнее. Для этого я написал следующую функцию.
  1. ;-----------------------------------------------------
  2. ; Функция замены подстроки в строке
  3. ;-----------------------------------------------------
  4. ; lpSrc - указатель на исходную строку
  5. ; lpDst - указатель на буфер для полученной строки
  6. ; lpPattern - указатель на заменяемую подстроку
  7. ; lpReplace - указатель на строку для замены
  8. ; dNum - количество замен (0 - заменить все)
  9. ;-----------------------------------------------------
  10. proc    _replace lpSrc:DWORD, lpPattern:DWORD, lpReplace:DWORD,\
  11.                  lpDst:DWORD, dNum:DWORD
  12.  
  13.         pusha
  14.  
  15.         ; Указатель на буфер-приемник
  16.         mov     edx,[lpDst]
  17.  
  18.         ; Счетчик замен
  19.         xor     ebx,ebx
  20.  
  21.         ; Исходная строка не пустая?
  22.         mov     ecx,[lpSrc]
  23.         cmp     byte [ecx],0
  24.         jz      .loc_ret
  25.  
  26.         ; Заменяемая строка не пустая?
  27.         mov     eax,[lpPattern]
  28.         cmp     byte [eax],0
  29.         jz      .loc_copy_all
  30.  
  31. .loc_scan:
  32.         mov     esi,ecx
  33.         mov     edi,[lpPattern]
  34.  
  35.         ; Исходная строка закончилась?
  36.         cmp     byte [esi],0
  37.         je      .loc_end_replace
  38. @@:
  39.         ; Строки совпали с паттерном?
  40.         cmp     byte [edi],0
  41.         je      .loc_move_replace
  42.  
  43.         ; Символ совпадает с
  44.         lodsb
  45.  
  46.         ; Заменять все вхождения?
  47.         cmp     [dNum],0
  48.         je      .loc_skip_counter
  49.  
  50.         ; Уже заменили нужное количество?
  51.         cmp     ebx,[dNum]
  52.         je      .loc_move_one_char
  53. .loc_skip_counter:
  54.         cmp     al,byte [edi]
  55.         jne     .loc_move_one_char
  56.  
  57.         inc     edi
  58.         jmp     @b
  59.  
  60. .loc_move_replace:
  61.         ; Увеличить счетчик замен
  62.         inc     ebx
  63.  
  64.         mov     ecx,esi
  65.  
  66.         ; Записать заменяющую строку
  67.         mov     esi,[lpReplace]
  68.         mov     edi,edx
  69. @@:
  70.         lodsb
  71.         or      al,al
  72.         jz      .loc_scan
  73.         stosb
  74.         inc     edx
  75.         jmp     @b
  76.  
  77. .loc_move_one_char:
  78.         ; Скопировать один символ
  79.         mov     al,byte [ecx]
  80.         mov     byte [edx],al
  81.         inc     edx
  82.         inc     ecx
  83.         jmp     .loc_scan
  84.  
  85. .loc_end_replace:
  86.         ; Записать финальный 0 в строку
  87.         mov     byte [edx],0
  88.  
  89.         jmp     .loc_ret
  90. .loc_copy_all:
  91.         ; Просто скопировать исходную строку
  92.         mov     esi,[lpSrc]
  93.         mov     edi,[lpDst]
  94. @@:
  95.         lodsb
  96.         stosb
  97.         or      al,al
  98.         jnz     @b
  99. .loc_ret:
  100.         popa
  101.         ret
  102. endp
Функция самодостаточная, не использует никаких внешних функций и не требует для своей работы дополнительных переменных в памяти. Параметры: lpSrc - указатель на исходную строку в формате ASCIIZ, lpPattern - указатель на искомую подстроку в формате ASCIIZ, lpReplace - указатель на строку для замены в формате ASCIIZ, может быть пустая строка, lpDst - указатель на буфер-приемник полученной после замены строки, его размер должен быть зарезервирован с учетом замененных строк, dNum - количество замен, которое надо выполнить (0 - заменять все вхождения). Я постарался оптимизировать функцию замены по скорости, но, наверное, можно ее ускорить как-нибудь еще.

Читать статью целиком »
Просмотров: 11460 | Комментариев: 8

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

21.05.2011 | Категория: Образ мышления: Assembler | Автор: ManHunter

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

За время программирования на Ассемблере у меня накопилось несколько полезных решений. Выделять под каждое из них отдельную статью не хочется, а держать под рукой пригодится. Поэтому все сложу сюда, по мере надобности буду пополнять.

Читать статью целиком »
Просмотров: 28372 | Комментариев: 34

Сортировка массива строк на Ассемблере

29.01.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Долго откладывал написание этой функции, но теперь вот прижало. Получилась функция сортировки массива произвольных текстовых строк в формате ASCIIZ усовершенствованным методом "пузырька". Усовершенствование заключается в том, что если при очередном проходе ни одной сортировки не было выполнено, то дальнейшая обработка массива прекращается. В некоторых случаях это дает значительный выигрыш в скорости работы. Однако, алгоритм сортировки "пузырьком" в любом случае является самым медленным, поэтому для очень больших массивов эта функция не подойдет. Но мне для больших объемов ее и не надо, на массиве из нескольких сотен или даже тысяч строк скорость работы функции меня вполне устраивает.
  1. ;------------------------------------------------------------------
  2. ; Функция сортировки массива строк
  3. ; by ManHunter / PCL
  4. ; http://www.manhunter.ru
  5. ;
  6. ; Сортировка выполняется усовершенствованным методом "пузырька"
  7. ; Параметры:
  8. ; lpArray - указатель на массив адресов строк
  9. ; dFlag   - метод сортировки: TRUE - по возрастанию,
  10. ;           FALSE - по убыванию
  11. ; На выходе:
  12. ; отсортированный согласно правилу массив адресов строк
  13. ;------------------------------------------------------------------
  14. proc    SortArray lpArray:dword, dFlag:dword
  15.         pusha
  16.  
  17.         ; Указатель на массив адресов строк
  18.         mov     esi,[lpArray]
  19.  
  20.         mov     ebx,[dFlag]
  21. sa_sort_1:
  22.         ; Проверка на 0 - признак окончания массива
  23.         mov     eax,[esi]
  24.         or      eax,eax
  25.         jz      sa_stop_sort
  26.  
  27.         or      bh,bh
  28.         jnz     sa_stop_sort
  29.  
  30.         ; Сравниваем, начиная со следующего элемента
  31.         lea     edi,[esi+4]
  32.  
  33.         ; Установить флаг, что сортировка не требуется,
  34.         ; если дальнейший остаток массива уже отсортирован
  35.         mov     bh,1
  36. sa_sort_2:
  37.         ; Следующий элемент 0 - массив закончился
  38.         mov     edx,[edi]
  39.         or      edx,edx
  40.         jz      sa_next_sort
  41.  
  42.         ; Сохранить текущие значения указателей
  43.         push    esi edi
  44.  
  45.         ; Указатели на строки
  46.         mov     esi,eax
  47.         mov     edi,edx
  48. sa_compare_string:
  49.         ; Сравнить символы в строках
  50.         mov     cl,byte [edi]
  51.         mov     ch,byte [esi]
  52.         ; Если символы равны, то сравнить следующие
  53.         cmp     cl,ch
  54.         je      sa_equal
  55.  
  56.         ; Проверка больше-меньше в зависимости от флага
  57.         cmp     bl,0
  58.         jz      @f
  59.  
  60.         cmp     cl,ch
  61.         ja      ss_next_string
  62.         jmp     sa_change_offs
  63. @@:
  64.         cmp     cl,ch
  65.         jb      ss_next_string
  66.  
  67. sa_change_offs:
  68.         ; Поменять местами адреса строк
  69.         xchg    eax,edx
  70.         ; Сбросить флаг, что сортировка не требуется
  71.         xor     bh,bh
  72.         jmp     ss_next_string
  73.  
  74. sa_equal:
  75.         ; Если закончилась строка, то перейти к следующей паре
  76.         or      cl,cl
  77.         jz      ss_next_string
  78.  
  79.         ; Перейти к следующей паре символов
  80.         inc     esi
  81.         inc     edi
  82.         jmp     sa_compare_string
  83.  
  84. ss_next_string:
  85.         ; Восстановить значения указателей и записать в них
  86.         ; значения адресов строк, без разницы изменившихся или нет
  87.         pop     edi esi
  88.         mov     [esi],eax
  89.         mov     [edi],edx
  90.  
  91.         ; Перейти к следующему элементу массива
  92.         add     edi,4
  93.         jmp     sa_sort_2
  94.  
  95. sa_next_sort:
  96.         ; Перейти к следующему элементу массива
  97.         add     esi,4
  98.         jmp     sa_sort_1
  99.  
  100. sa_stop_sort:
  101.         popa
  102.         ret
  103. endp
Сортировать сами строки в памяти слишком нерационально, поэтому для сортировки нам понадобится массив DWORD'ов с указателями на строки. Параметр lpArray - указатель на такой массив. Признак окончания массива - DWORD с нулевым значением. Параметр dFlag определяет в каком порядке будет отсортирован массив: по возрастанию (значение TRUE) или по убыванию (значение FALSE). На выходе получаем отсортированный массив указателей.

Читать статью целиком »
Просмотров: 18286 | Комментариев: 7

Функции base64 на Ассемблере

09.01.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Алгоритм Base64 может использоваться в пользовательских почтовых приложениях, в качестве одного из уровней защиты шифрованием, для хранения двоичных данных и для решения многих других задачах. В большинстве языков высокого уровня используются штатные функции, в Ассемблере приходится все реализовывать самостоятельно.

Алгоритм Base64 обратимый, то есть из закодированного текста можно в точности получить исходные данные. Начнем с функции кодирования.
  1. ;---------------------------------------------------------------
  2. ; Функция кодирования Base64
  3. ;---------------------------------------------------------------
  4. ; Параметры:
  5. ; lpFrom - указатель на исходные данные
  6. ; lpTo   - указатель на буфер для приема кодированных данных
  7. ; dSize  - размер исходных данных
  8. ; Функция ничего не возвращает
  9. ;---------------------------------------------------------------
  10. proc    base64_encode lpFrom:dword, lpTo:dword, dSize:dword
  11.         pusha
  12.  
  13.         mov     ebx,.base64
  14.         mov     esi,[lpFrom]
  15.         mov     edi,[lpTo]
  16.         mov     ecx,[dSize]
  17.  
  18.         or      ecx,ecx
  19.         jz      .r3
  20. .encode_loop:
  21.         lodsd
  22.         mov     edx,eax
  23.         bswap   edx
  24.         xor     eax,eax
  25.  
  26.         shld    eax,edx,6
  27.         shl     edx,6
  28.         xlatb
  29.         stosb
  30.  
  31.         xor     eax,eax
  32.         shld    eax,edx,6
  33.         shl     edx,6
  34.         xlatb
  35.         stosb
  36.         dec     ecx
  37.         jz      .r2
  38.  
  39.         xor     eax,eax
  40.         shld    eax,edx,6
  41.         shl     edx,6
  42.         xlatb
  43.         stosb
  44.         dec     ecx
  45.         jz      .r1
  46.  
  47.         xor     eax,eax
  48.         shld    eax,edx,6
  49.         shl     edx,6
  50.         xlatb
  51.         stosb
  52.  
  53.         dec     esi
  54.         dec     ecx
  55.         jnz     .encode_loop
  56.  
  57.         jmp     .r3
  58. .r2:
  59.         mov     al,'='
  60.         stosb
  61. .r1:
  62.         mov     al,'='
  63.         stosb
  64. .r3:
  65.         xor     eax,eax
  66.         stosb
  67.         popa
  68.  
  69.         ret
  70.  
  71. .base64 db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  72.         db 'abcdefghijklmnopqrstuvwxyz'
  73.         db '0123456789+/'
  74. endp
Параметры вызова: lpFrom - указатель на кодируемые данные, lpTo - указатель на буфер для приема кодированных данных и dSize - размер кодируемых данных. Все параметры обязательные. Размер буфера-приемника должен быть примерно в 1,3 раза больше исходных данных, это обусловлено особенностями алгоритма кодирования.

Читать статью целиком »
Просмотров: 5738 | Комментариев: 9

Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 3 (0.0034 сек.) / Память: 4.5 Mb
Наверх