Требуется оптимизировать по скорости.

Тема в разделе "WASM.ASSEMBLER", создана пользователем Asterix, 11 авг 2004.

  1. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Требуется оптимизировать по скорости перевод ASCII строки вида

    sign1 = 5678ff45::::::0011,0, sign 2= 45454500::ff,0,0 (строка оканчивается на два нуля!)

    в которой могут присутствовать пробелы и табуляция

    в строку

    'sign1',0,5678FF450000000011 , где sign1 осталось в ASCII, всё остальное переведено в HEX

    причем получаемая строка должна всё время писаться сначала буфера buff

    Т.е. символы :::: должны заменяться на 0000, в идеале нужно чтоб любые не HEX

    символы в ASCII представлении заменялись бы 0 нулём.



    Я тут набросал первоначальный вариант, но что-то у меня уже крышу сносит,

    кажется я не все учёл, а уж что не оптимально так это точно.
    Код (Text):
    1.   mov esi, src
    2. @loop:
    3.   mov edi, buff
    4.   mov al, BYTE [esi]
    5.   cmp al, 20h  ; пробел
    6.   je @skip
    7.   cmp al, 09h  ; табуляция
    8.   je @skip
    9. @parse:
    10.   test al, al
    11.   jz @test
    12.   cmp al, '='
    13.   je @found
    14.   mov BYTE [edi], al
    15.   inc esi
    16.   inc edi
    17.   mov al, BYTE [esi]
    18.   jmp @parse
    19. @found:
    20.   mov BYTE [edi], 0
    21.   inc edi
    22.   inc esi
    23. @loop3:
    24.   mov ecx, 2
    25. ;  xor bl, bl
    26. @loop2:
    27.   lodsb
    28.   test al, al
    29.   jz @test2
    30.   cmp al, 20h  ; пробел
    31.   je @loop2
    32.   cmp al, 09h  ; табуляция
    33.   je @loop2
    34.      shl ebx, 4
    35.      cmp al, 3Fh+1
    36.      sbb edx, edx
    37.      cmp al, 3Ah
    38.      adc edx, 0
    39.      cmp edx, -1
    40.      sbb edx, edx
    41.      and eax, edx
    42.      jz @F
    43.      cmp al, 'f'+1
    44.      sbb edx, edx
    45.      cmp al, 'a'
    46.      adc edx, 0
    47.      and edx, 'A'-'a'
    48.      add al, dl
    49.      cmp al, 'F'+1
    50.      sbb edx, edx
    51.      cmp al, 'A'
    52.      adc edx, 0
    53.      and edx, -07h
    54.      add al, dl
    55.      xor al, 030h
    56. @@:
    57.      or ebx, eax
    58.      loop @loop2
    59.   mov BYTE [edi], bl
    60.   inc edi
    61.   jmp @loop3
    62. ;--------------------------------------------------------
    63. @skip:
    64.   inc esi
    65.   jmp @loop
    66. @test:
    67.   mov al, BYTE [esi+1]
    68. @test2:
    69.   test al, al
    70.   jnz @loop
     
  2. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Asterix

    перевод ASCII строки вида ... в строку ...

    Мне не совсем понятна твоя запись.

    Можно увидеть исходную строку и результирующую в шестнадцатеричном виде, байты отделены пробелами? И если можно, то пример содержащий пробелы и табуляции и как с ними надо поступисть.
     
  3. EvilsInterrupt

    EvilsInterrupt Постигающий азы дзена

    Публикаций:
    0
    Регистрация:
    28 окт 2003
    Сообщения:
    2.428
    Адрес:
    Russia
    А пример можно?
     
  4. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Исходная строка, оканчивающаяся двумя 0 нулями.

    Каждая подстрока в исходной строке в свою очередь оканчивается 0 нулём.

    Вывод нужно делать в один и тот же буфер, с его начала, для каждой подстроки.
    Код (Text):
    1. 00550000  73 69 67 6E 31 3D 39 41  sign1=9A
    2. 00550008  20 46 46 20 46 46 20 30   FF FF 0
    3. 00550010  30 20 30 30 20 39 41 20  0 00 9A
    4. 00550018  46 46 46 46 20 30 30 30  FFFF 000
    5. 00550020  30 20 35 35 38 39 20 45  0 5589 E
    6. 00550028  35 33 31 20 3A 3A 3A 3A  531 ::::
    7. 00550030  46 46 30 30 30 30 00 73  FF0000.s
    8. 00550038  69 67 6E 20 32 3D 41 31  ign 2=A1
    9. 00550040  3A 3A 3A 3A 3A 3A 3A 3A  ::::::::
    10. 00550048  43 31 3A 3A 3A 3A 41 33  C1::::A3
    11. 00550050  3A 3A 3A 3A 3A 3A 3A 3A  ::::::::
    12. 00550058  38 33 3A 3A 3A 3A 3A 3A  83::::::
    13. 00550060  3A 3A 37 35 3A 3A 35 37  ::75::57
    14. 00550068  35 31 33 33 43 30 42 46  5133C0BF
    15. 00550070  00 73 69 67 6E 33 3D 41  .sign3=A
    16. 00550078  31 3A 3A 3A 3A 3A 3A 3A  1:::::::
    17. 00550080  3A 43 31 3A 3A 3A 3A 41  :C1::::A
    18. 00550088  33 3A 3A 3A 3A 3A 3A 3A  3:::::::
    19. 00550090  3A 35 37 35 31 33 33 43  :575133C
    20. 00550098  30 42 46 3A 3A 3A 3A 3A  0BF:::::
    21. 005500A0  3A 3A 3A 42 39 3A 3A 3A  :::B9:::
    22. 005500A8  3A 3A 3A 3A 3A 33 42 43  :::::3BC
    23. 005500B0  46 37 36 00 00 00 00 00  F76.....




    Это результирующая строка, которая должна выводится

    для каждой подстроки в строке:
    Код (Text):
    1. 00401008              73 69 67 6E      sign
    2. 00401010  31 00 9A FF FF 00 00 9A  1.љяя..љ
    3. 00401018  FF FF 00 00 55 89 E5 31  яя..U‰е1
    4. 00401020  00 00 FF 00 00           ..я..




    > И если можно, то пример содержащий пробелы и табуляции и как с ними надо поступисть



    Пробелы до начала строки должны проskip'ываться, пробелы в названии sign 1 должны оставляться.
    Код (Text):
    1.  sign 1 = 9A FF FF 00 00 9A FFFF 0000 5589 E531 ::::FF0000
    2. |    |   |_этот не нужен   |____|____|эти пробелы не нужны
    3. |    |
    4. |    |_этот нужен
    5. |
    6. |
    7. |
    8. |_этот пробел не нужен
    9.  
    10. Хотя практически получается что строка возле = не содержит пробелов
    11. на это нельзя рассчитывать.
     
  5. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Asterix

    Если внутри сигнатуры могут содержаться нули, как ты определишь где начинается следующая подстрока?



    Или мы записываем в буфер первую подстроку, обрабатываем, а затем записываем следующую?



    И еще вопрос: как обрабатывать последний символ сигнатуры если их количество нечетное?
     
  6. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Black_mirror

    Внутри сигнатуры нулей 00h нет, есть только '0'=30h

    те нули что там встречаются это концы подстрок



    В исходном буфере все подстроки идут подряд:

    подстрока1,0,подстрока2,0,подстрока3,0,0 <-это конец т.к. два нуля.



    Условимся что четное, т.е. сигнатура, после = будет состоять из четного числа байт(не считая пробелы и табуляцию, с ними может быть и не четное), иначе я вобще не понимаю как это можно правильно перевести из ASCII в HEX.
     
  7. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Код (Text):
    1. src db <font color="#B00000]'sign1 = 9A FF FF 00 00 9A FFFF 0000 5589 E531 ::::FF0000'</font><!--color-->,0
    2.     db <font color="#B00000]'sign 2=A1::::::::C1::::A3::::::::83::::::::75::575133C0BF'</font><!--color-->,0
    3.     db <font color="#B00000]'sign3 =A1::::::::C1::::A3::::::::575133C0BF::::::::B9::::::::3BCF76'</font><!--color-->,0,0
     
  8. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Asterix

    Я не правильно задал вопрос, если после преобразования подстроки в сигнатуру, внутри сигнатуры окажутся нули, то как ты определишь где начинается следующая сигнатура?



    И еше напиши пожалуйста какие символы в подстроке вообще игнорируются и из каких может состоять имя.



    PS: Если бы в части подстроки, которая представляет сигнатуру не было бы символов которые нужно игнорировать, то можно было бы преобразовывать сразу по 4 или по 8 символов.
     
  9. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Black_mirror

    > Я не правильно задал вопрос, если после преобразования подстроки в сигнатуру, внутри сигнатуры окажутся нули, то как ты определишь где начинается следующая сигнатура?



    Вобще-то я планировал подсчитывать размер сигнатуры в момент преобразования, но здесь пока не реализовал.



    > то как ты определишь где начинается следующая сигнатура?



    Следующая сигнатура будет вписываться в этот же буфер с самого начала, перекрывая предыдущую, потому что после получения сигнатуры и ее длины эти параметры будут передаваться в процедуру и по результату работы процедуры будет решаться парсить ли src дальше.



    > И еше напиши пожалуйста какие символы в подстроке вообще игнорируются и из каких может состоять имя.



    В имени могут быть любые символы кроме = , т.к. равно определяет конец имени сигнатуры и начало

    собственно ее самой, даже пробельные, в сигнатуре любые не HEX символы, кроме пробельных, должны заменяться на нули, в данном случае это :: дают 00 т.е. нулевой байт, пробельные пропускаться и не входить в итоговую сигнатуру в hex представлении.



    В результате преобразования мне нужно получить:

    <ul type=disc>поинтер на имя сигнатуры(это есть т.к. совпадает с OFFSET buff)

    поинтер на первый байт сигнатуры

    длину сигнатуры</ul>
     
  10. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Asterix

    Вот как можно по 4 символа сразу обрабатывать:



    Четыре символа находящиеся в регистре eax рассматриваются как 16-ричные цифры(биты 7:0 - первая цифра, 31:24 - последная цифра, все что не является цифрой заменяется на 0) и переводятся в два байта(al байт полученный из бит 7:0(старшая цифра) и 15:8(младшая цифра), ah - байт полученный из 23:16 и 31:24). Под bit7 имеетются ввиду старшие биты каждого байта регистра.
    Код (Text):
    1. hextonum:;(eax - four char):ax - num
    2. ;A..F  -> a..f
    3.     mov ecx,40404040h ;перевод букв в верхний регист
    4.     and ecx,eax       ;также могут буть заменены и некоторые другие символы
    5.     shr ecx,1         ;но на правильность работы функции это никак не влияет
    6.     not ecx
    7.     and eax,ecx
    8. ;char -> BCD
    9.     lea edx,[eax-'0000']   
    10.     or edx,80808080h ;для избежания распространения переноса в соседние байты
    11.     lea ebx,[edx-'AAAA'+'0000'] ;принадлежит ли байт диапазону A..F  
    12.     lea ecx,[edx-'GGGG'+'0000']
    13.     xor ebx,ecx ;bit7=1 if A..F
    14.     lea ecx,[edx-0A0A0A0Ah] ;принадлежит ли байт диапазону 0..9  
    15.     xor ecx,edx ;bit7=1 if 0..9
    16.     not eax ;bit7=1 if not digit
    17.     xor ecx,ebx ;буква или цифра
    18.     and eax,ecx ;bit7=1 if digit
    19. ;if A..F then sub 7
    20.     and ebx,80808080h ; сдвигаем интервал A..F к интервалу 0..9
    21.     shr ebx,4
    22.     sub edx,ebx
    23.     shr ebx,3
    24.     add edx,ebx
    25. ;create mask
    26.     and eax,80808080h ;обнуляем все символы не цифры
    27.     mov ecx,eax
    28.     shr ecx,7
    29.     sub eax,ecx
    30.     and eax,edx ;not digit -> 0
    31. ;BCD -> num
    32.     mov edx,eax ;в каждом байте теперь по одной 16-ричной цифре
    33.     shl edx,12  
    34.     add eax,edx
    35.     mov al,ah
    36.     rol eax,8
    37.  
    38.     xchg al,ah
    39.     ret


    Нужно только эффективный метод выкидывания пробелов придумать.



    PS: Кстати без всяких if'ов и переходов!
     
  11. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Black_mirror

    > Нужно только эффективный метод выкидывания пробелов придумать.



    Невыполнимо наверно :-(



    А что до твоего кода то я практически ничего не понял, думаю тут нужно на бумажке себе всё расписать что на каком шаге происходит.



    Давай посмотрим по кускам, вот здесь
    Код (Text):
    1. cmp al, 20h  ; пробел
    2.   je @skip
    3.   cmp al, 09h  ; табуляция
    4.   je @skip


    и
    Код (Text):
    1.   test al, al
    2.   jz @test2
    3.   cmp al, 20h  ; пробел
    4.   je @loop2
    5.   cmp al, 09h  ; табуляция
    6.   je @loop2


    Может можно как-то оптимизировать чтоб остался только один переход?
     
  12. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Asterix

    Выкинуть не сложно, только эти переходы срабатывают не часто, так что наверно лучше с ними.


    Код (Text):
    1.   mov ah,al
    2.   xor eax,2009h
    3.   lea edx,[eax-101h]
    4.   xor edx,eax
    5.   and edx,eax
    6.   xor al,9
    7.   and ebx,8080h
    8.   jnz .skip


    или в лоб:
    Код (Text):
    1.   cmp al,21h
    2.   sbb ebx,ebx
    3.   cmp al,20h
    4.   adc ebx,0
    5.   cmp al,10
    6.   sbb ebx,0
    7.   cmp al,9
    8.   adc ebx,0
    9.   jnz .skip




    А для моей функции требуется собрать в eax четыре непробельных символа и она их преобразует в 2 байта сигнатуры. Я еще там малость коментариев дописал.



    Для второго участка кода одним переходом не обойтись, там метки 2 разные метки.
     
  13. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Black_mirror

    > Для второго участка кода одним переходом не обойтись, там метки 2 разные метки



    Точно, это не доглядел когда постил.



    > А для моей функции требуется собрать в eax четыре непробельных символа и она их преобразует в 2 байта сигнатуры. Я еще там малость коментариев дописал.



    Спасибо, с комментариями немного стало понятней.

    Ладно, а как функция сработает если 4-е байта не найдется в конце сигнатуры ?



    А как проскипать пробелы я кажется понял типа:
    Код (Text):
    1.  mov ecx, 4
    2. @@:
    3.  lodsb
    4.  test al, al
    5.  jz
    6.  cmp al, 20h
    7.  je @B
    8.  cmp al, 09h
    9. je @B
    10. shl eax, 8
    11. loop @B




    Для быстроты конечно нужно будет lodsb и loop заменить.
     
  14. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Asterix



    Все зависит от того, что ты ей вместо недостающих байт подсунешь.
     
  15. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Да, ещё, как при обработке по 4-е байта посчитать заодно размер сигнатуры?

    Хотя сейчас кажется придумал..



    > Все зависит от того, что ты ей вместо недостающих байт подсунешь.



    Если нули? Кстати если твоя функция припишет в конец итоговой сигнатуры лишние нули и учтет это при подсчёте длины сигнатуры, то это, вобщем-то, на результат работы функции, работающей с полученной сигнатурой не отразится т.к. нули там считаются за любой байт и условие всегда будет верно.
     
  16. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Моя функция ничего никуда не приписывает, она получает четыре символа в регистре eax и выдает два байта в регистре ax.
     
  17. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Black_mirror

    Попытался собрать всё в кучу, ошибки конечно же присутствуют, но самое главное что после работы твоей процедуры я не могу байты привести в правильный вид

    xchg al,ah в конце явно недостаточно.
    Код (Text):
    1.  
    2. include '%fasminc%/win32axp.inc'
    3.  
    4. .data
    5.  
    6. src db 'sign1 = 9A FF FF 00 00 9A FFFF 0000 5589 E531 ::::FF0000',0
    7.     db 'sign 2=A1::::::::C1::::A3::::::::83::::::::75::575133C0BF',0
    8.     db 'sign3 =A1::::::::C1::::A3::::::::575133C0BF::::::::B9::::::::3BCF76',0,0
    9. buff      rb  1000h
    10. flag dd 0
    11.  
    12. .code
    13.  
    14. align 4
    15. start:
    16.   mov esi,src
    17. @loop:
    18.   mov edi,buff
    19. @find_first_byte_sign_name:
    20.   lodsb
    21.   cmp al,20h     ; если пробел, то проверять следующий символ
    22.   je @find_first_byte_sign_name
    23.   cmp al,09h     ; если табуляция, то проверять следующий символ
    24.   je @find_first_byte_sign_name
    25. @find_signature_start:
    26.   test al,al
    27.   jz @test       ; если 0, то проверить следующий символ на равенство 0
    28.   cmp al,'='
    29.   je @found
    30.   stosb
    31.   lodsb
    32.   jmp @find_signature_start
    33. @found:
    34.   xor eax,eax
    35.   stosb
    36. ;---------------------------
    37. @loop3:
    38.  xor eax, eax
    39.  mov ecx, 4
    40.  and [flag],eax
    41. @@:
    42.  shl eax, 8
    43. @skip:
    44.  lodsb
    45.  test al, al
    46.  jnz @ok
    47.  mov ecx,1
    48.  mov [flag],1
    49.  jmp @done
    50. @ok:
    51.  cmp al, 20h
    52.  je @skip
    53.  cmp al, 09h
    54.  je @skip
    55. @done:
    56.  loop @B
    57. ; -----------------------------------
    58. ;hextonum:;(eax - four char):ax - num
    59. ;A..F  -> a..f
    60. mov ecx,40404040h ;перевод букв в верхний регист
    61. and ecx,eax       ;также могут буть заменены и некоторые другие символы
    62. shr ecx,1         ;но на правильность работы функции это никак не влияет
    63. not ecx
    64. and eax,ecx
    65. ;char -> BCD
    66. lea edx,[eax-'0000']
    67. or edx,80808080h ;для избежания распространения переноса в соседние байты
    68. lea ebx,[edx-'AAAA'+'0000'] ;принадлежит ли байт диапазону A..F
    69. lea ecx,[edx-'GGGG'+'0000']
    70. xor ebx,ecx ;bit7=1 if A..F
    71. lea ecx,[edx-0A0A0A0Ah] ;принадлежит ли байт диапазону 0..9
    72. xor ecx,edx ;bit7=1 if 0..9
    73. not eax ;bit7=1 if not digit
    74. xor ecx,ebx ;буква или цифра
    75. and eax,ecx ;bit7=1 if digit
    76. ;if A..F then sub 7
    77. and ebx,80808080h ; сдвигаем интервал A..F к интервалу 0..9
    78. shr ebx,4
    79. sub edx,ebx
    80. shr ebx,3
    81. add edx,ebx
    82. ;create mask
    83. and eax,80808080h ;обнуляем все символы не цифры
    84. mov ecx,eax
    85. shr ecx,7
    86. sub eax,ecx
    87. and eax,edx ;not digit -> 0
    88. ;BCD -> num
    89. mov edx,eax ;в каждом байте теперь по одной 16-ричной цифре
    90. shl edx,12
    91. add eax,edx
    92. mov al,ah
    93. rol eax,8
    94.  
    95. ;xchg al,ah
    96.  
    97. ;ret
    98. ; -----------------------------------
    99.   mov WORD [edi], ax
    100.   cmp [flag],1
    101.   je @loop
    102.   inc edi
    103.   inc edi
    104.   jmp @loop3
    105. ;--------------------------------------------------------------------- -----------------
    106. @test:
    107.   mov al, BYTE [esi+1]
    108. ;@test2:
    109.   test al, al
    110.   jnz @loop
    111. @exit:
    112.  
    113.   invoke ExitProcess, 0
    114.  
    115. .end start
     
  18. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Black_mirror

    > Моя функция ничего никуда не приписывает, она получает четыре символа в регистре eax и выдает два байта в регистре ax.



    Я имел ввиду если в конце сигнатуры я не доберу байты до четырёх, то в eax у меня вместо них окажутся нули и соответственно твоя процедура после преобразования тоже должна приписать нули в конце сигнатуры и они как бы лишние, но это не страшно.
     
  19. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Asterix





    Нужно либо заменить код накапливающий символы:
    Код (Text):
    1.   xor eax,eax
    2.   mov ecx,4
    3. .l0:
    4.   lodsb  
    5.   cmp al,20h
    6.   jz .l0
    7.   cmp al,9
    8.   jz .l0
    9.   test al,al
    10.   jz .l1
    11.   ror eax,8
    12.   loop .l0
    13. .l1:
    14.   shl ecx,3
    15.   ror eax,cl




    Либо код в конце моей процедуры:
    Код (Text):
    1.   mov edx,eax
    2.   shr edx,4
    3.   add eax,edx
    4.   mov ah,al
    5.   shr eax,8
    6.   xchg al,ah
     
  20. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576
    Black_mirror

    > Либо код в конце моей процедуры



    Спасибо, сделал именно так.

    Но чтобы отлавливать конец подстроки я такого нагородил, что теперь не радостно мне..