Разделение строки на подстроки

Discussion in 'WASM.BEGINNERS' started by LOL, May 12, 2006.

  1. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Hi all!



    []
     
  2. cresta

    cresta Active Member

    Blog Posts:
    0
    Joined:
    Jun 13, 2004
    Messages:
    2,257
    Ситуация после правки Беспощадным выглядит несколько странно: вопроса нет, но есть ответ :)))


    Code (Text):
    1. .data
    2.     szString    db  "10 sym str",0
    3.    
    4.     subStr1     db  10 dup(0)
    5.     subStr2     db  10 dup(0)
    6.     subStr3     db  10 dup(0)
    7.     subStr4     db  10 dup(0)
    8.     subStr5     db  10 dup(0)
    9.     subStr6     db  10 dup(0)
    10.    
    11. .code
    12.  
    13. ;#####################################################################  ###
    14. split proc
    15.     push    esi
    16.     push    edi
    17.     cld
    18.     lea     esi,szString        ;исходная строка
    19.     lea     edx,subStr1         ;адрес первого приёмника
    20.  @@:  
    21.     mov     edi,edx             ;передаём адрес приемника в подпрограмму
    22.     call    next_substr         ;вызов подпрограммы
    23.     cmp     al,20h              ;если al==20h - значит есть ещё подстрока
    24.     lea     edx,[edx+10]        ;адрес следующего приёмника
    25.     je      @B                  ;пока есть подстроки - крутим цикл
    26.     pop     edi
    27.     pop     esi
    28.     ret
    29.    
    30. next_substr:                    ;получение подстроки
    31.     lodsb                       ;al - очередной байт строки
    32.     stosb                       ;сохраняем в приёмнике
    33.     cmp     al,20h              ;проверка на пробел
    34.     jne     @F                  ;
    35.     mov     byte ptr [edi],0    ;если символ - пробел, завершаем подстроку нулём
    36.     ret                         ;и возврат
    37.  @@:                            
    38.     test    al,al               ;если не пробел - проверяем на конец строки
    39.     jnz     next_substr         ;если не конец - продолжаем цикл заполнения подстроки
    40.     ret                         ;если конец строки - возвращаемся в первый цикл
    41. split endp




    разбивает строку на подстроки по пробелам.
     
  3. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Да, весьма странно - че даосу не понравилось-то? Ну а вопрос ножно узнать по названию темы =)



    Спасибо, cresta
     
  4. IceStudent

    IceStudent Active Member

    Blog Posts:
    0
    Joined:
    Oct 2, 2003
    Messages:
    4,300
    Location:
    Ukraine
    LOL



    Постоянное нарушение п 3.5 Правил форума.
     
  5. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Все. Понял.
     
  6. crypto

    crypto Active Member

    Blog Posts:
    0
    Joined:
    Dec 13, 2005
    Messages:
    2,533
    cresta

    Да, забавно...
     
  7. cresta

    cresta Active Member

    Blog Posts:
    0
    Joined:
    Jun 13, 2004
    Messages:
    2,257
    Что?
     
  8. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Блин... я на ФАсме процу переписал, так она по "внутренним" ret'ам не туда возвращается... такое ощущение, что call не ложит в стэк адрес возврата :)

    Наверное я туплю :/ Завтра в отладчике посмотрю...
     
  9. IceStudent

    IceStudent Active Member

    Blog Posts:
    0
    Joined:
    Oct 2, 2003
    Messages:
    4,300
    Location:
    Ukraine
    LOL



    Версия фасма? Там ret идёт как макрос (как в масме) и вставляет код эпилога функции. Используй retn 0 (если не ошибаюсь либо опкод (можно оформить как макрос:

    macro nret { db $CB (или $C3?) }
     
  10. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Версия 1.66. Впрочем, на других (1.64, 1.65) тоже самое.

    А разве CB и C3 это не retf и retn ? Впрочем: результат один - error при запуске exe'шника :/



    Итак: входная строка "1234 678 0"

    1. Все 3 ret'а

    Выводит только 1234. В отладчике: сначала все идет нормально - прога получает первую подстроку "1234", заканчавает ее нулем, затем идет возврат не туда куда надо :dntknw: Все ret'ы в отладчике выглядят так: "leave/retn 0C"

    2. Теперь с retn 0

    Error. В отладчике: возвращается вроде туда куда надо и "1234" получаем, ret выглядит как "retn", но дохнет на "mov edx, [edx+N]". N = 10. В оригинале вместо mov - lea, но у меня при этом вообще ничего не работало. Т.е. даже первая подстрока "1234" не выделялась...

    3. macro nret { db $CB }

    Error. В отладчике: ret выглядит как retf, дохнет здесь же, где и retf :/

    4. macro nret { db $C3 }

    Error. В отладчике: ret выглядит как retn. Т.е. как и в случае 2. с retn 0. Дохнет там же :/ Попробовал вместо mov'а - lea, но результат такой же - error :dntknw:



    Наверно все дело в mov'е этом =)

    Исходник в аттаче.



    [​IMG] _1051799082__splittest.asm
     
  11. cresta

    cresta Active Member

    Blog Posts:
    0
    Joined:
    Jun 13, 2004
    Messages:
    2,257




    mov edx,[edx+N] и lea edx,[edx+N] - это совершенно разные вещи. Первая инструкция загружает в edx число, адрес которого edx+N, вторая - просто прибавляет к edx число N.

    Т.е. при mov ты ложишь в edx первые 4 байта приёмного буфера, а при lea ты заменяешь адрес одного приёмного буфера на адрес следующего буфера.



    Заменять lea edx,[edx+N] на add edx,N нельзя, т.к в отличие от lea, add меняет флаги, и это повлияет на переход je @B, который должен зависеть от cmp al, 20h, вызывая ошибку.

    Потому в оригинале и стоит lea.



    Потом, в аттаче нарисовано

    mov esi, [szString]

    mov edx, [szStr]

    что они означают в фасме, можно только догадываться. Эти две строки должны поместить в esi адрес твоей строки и в edx - адрес первого приёмного буфера. Поэтому проверь ещё раз, что делают эти две интсрукции, если не загружают адреса, то откорректируй их.



    P.S.

    Вообще, брось этот убогий фасм. Есть же нормальные ассемблеры masm, tasm.
     
  12. cresta

    cresta Active Member

    Blog Posts:
    0
    Joined:
    Jun 13, 2004
    Messages:
    2,257
    Чтобы не путаться с lea/mov, вот этот кусок:


    Code (Text):
    1. mov     edi, edx
    2. call    n_sub
    3. cmp     al, 20h
    4. mov     edx, [edx+N]; <-------
    5. je      @b




    замени на такой:


    Code (Text):
    1. mov     edi, edx
    2. call    n_sub
    3. add     edx, N
    4. cmp     al, 20h
    5. je      @b
     
  13. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Дело в том, что в при вызове процы split я ложу в стэк АДРЕС строки. Затем при mov esi, [szSring] в esi помещается значение szString, которое, в свою очередь, является адресом строки. Так что (наверное :) здесь все правильно.





    Да, да, да и еще раз да =) Я накодил не то, что хотел :))) Теперь все работает =) Спасибо



    add изменяет OF, SF, ZF, AF, CF, PF

    je прыгает при ZF = 0.

    При lea перед и после прибавления N флаг ZF = 1,

    а если использовать add, то add устанавливает ZF = 0

    Разобрался =) Отладчик рулит ;)



    P.S. А можно вопрос? Почему фасм "убогий"? Мне, например, нравится =)



    [ADD] Ага. Можно и так :) Впрочем я разобрался :) А что лучше из этих двух вариантов? (быстрее/меньше)[/ADD]
     
  14. cresta

    cresta Active Member

    Blog Posts:
    0
    Joined:
    Jun 13, 2004
    Messages:
    2,257
    Варинат с add edx,N меньше, вариант с lea edx,[edx+N] быстрее.
     
  15. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Спасибо :)
     
  16. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    И еще - раз уж я оформил все это в виде процедуры, то не нужно ли вначале процы сохранить флаги и регистры, а перед выходом восстановить их? Вообще-то esi и edi сохраняются, а затем восстанавливаются, а вот, например, edx - нет.
     
  17. mix_mix

    mix_mix Михаил

    Blog Posts:
    0
    Joined:
    Oct 8, 2005
    Messages:
    277
    Location:
    Токио
    Как хочешь. В общем все WinAPI функции и так затирают все регистры, кроме esi, edi и ebx (а у меня еще ebx используется, как константа, равная нулю, так что осталось два регистра :). Поэтому, если ты в проге активно используешь WinAPI, то смысла сохранять регистры, а тем более флаги, нет.

    Пора переходить на 64-битные процессоры. Там этих регистров - устанешь считать :)
     
  18. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Ура! 100 человек просмотрели эту тему =)

    Угу, понял...

    А че это у тебя ebx = const = 0 ? =))

    И добавили "всего" восемь (вроде) регистров. И что бы их юзать надо WinXP 64-bit =) Ну или *nix какой :)
     
  19. mix_mix

    mix_mix Михаил

    Blog Posts:
    0
    Joined:
    Oct 8, 2005
    Messages:
    277
    Location:
    Токио


    mov eax, NULL = 5 байтов

    mov eax, ebx = 2 байта

    Смотри статьи про оптимизацию :)



    Ага восемь, посмотри на аттач. Выдрано из документации по fasm'у.



    [​IMG] _2102224892__registers.JPG
     
  20. LOL

    LOL New Member

    Blog Posts:
    0
    Joined:
    Apr 28, 2006
    Messages:
    175
    Location:
    Russia
    Ну... согласен :) На то он и ассемблер, чтобы меньше =)

    А разница в размере между "push 0" и "push ebx" есть?



    Так... начнем.

    Начиная с rax и кончая rdi - это старые регистры, расширенные до 64 бит.

    r8 - r15 это те, про которые я и говорил...

    b, w, d - суффиксы для обращения к разным частям регистров.