Ситуация после правки Беспощадным выглядит несколько странно: вопроса нет, но есть ответ )) Код (Text): .data szString db "10 sym str",0 subStr1 db 10 dup(0) subStr2 db 10 dup(0) subStr3 db 10 dup(0) subStr4 db 10 dup(0) subStr5 db 10 dup(0) subStr6 db 10 dup(0) .code ;##################################################################### ### split proc push esi push edi cld lea esi,szString ;исходная строка lea edx,subStr1 ;адрес первого приёмника @@: mov edi,edx ;передаём адрес приемника в подпрограмму call next_substr ;вызов подпрограммы cmp al,20h ;если al==20h - значит есть ещё подстрока lea edx,[edx+10] ;адрес следующего приёмника je @B ;пока есть подстроки - крутим цикл pop edi pop esi ret next_substr: ;получение подстроки lodsb ;al - очередной байт строки stosb ;сохраняем в приёмнике cmp al,20h ;проверка на пробел jne @F ; mov byte ptr [edi],0 ;если символ - пробел, завершаем подстроку нулём ret ;и возврат @@: test al,al ;если не пробел - проверяем на конец строки jnz next_substr ;если не конец - продолжаем цикл заполнения подстроки ret ;если конец строки - возвращаемся в первый цикл split endp разбивает строку на подстроки по пробелам.
Да, весьма странно - че даосу не понравилось-то? Ну а вопрос ножно узнать по названию темы =) Спасибо, cresta
Блин... я на ФАсме процу переписал, так она по "внутренним" ret'ам не туда возвращается... такое ощущение, что call не ложит в стэк адрес возврата Наверное я туплю :/ Завтра в отладчике посмотрю...
LOL Версия фасма? Там ret идёт как макрос (как в масме) и вставляет код эпилога функции. Используй retn 0 (если не ошибаюсь либо опкод (можно оформить как макрос: macro nret { db $CB (или $C3?) }
Версия 1.66. Впрочем, на других (1.64, 1.65) тоже самое. А разве CB и C3 это не retf и retn ? Впрочем: результат один - error при запуске exe'шника :/ Итак: входная строка "1234 678 0" 1. Все 3 ret'а Выводит только 1234. В отладчике: сначала все идет нормально - прога получает первую подстроку "1234", заканчавает ее нулем, затем идет возврат не туда куда надо Все 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 Наверно все дело в mov'е этом =) Исходник в аттаче. _1051799082__splittest.asm
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.
Чтобы не путаться с lea/mov, вот этот кусок: Код (Text): mov edi, edx call n_sub cmp al, 20h mov edx, [edx+N]; <------- je @b замени на такой: Код (Text): mov edi, edx call n_sub add edx, N cmp al, 20h je @b
Дело в том, что в при вызове процы 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]
И еще - раз уж я оформил все это в виде процедуры, то не нужно ли вначале процы сохранить флаги и регистры, а перед выходом восстановить их? Вообще-то esi и edi сохраняются, а затем восстанавливаются, а вот, например, edx - нет.
Как хочешь. В общем все WinAPI функции и так затирают все регистры, кроме esi, edi и ebx (а у меня еще ebx используется, как константа, равная нулю, так что осталось два регистра . Поэтому, если ты в проге активно используешь WinAPI, то смысла сохранять регистры, а тем более флаги, нет. Пора переходить на 64-битные процессоры. Там этих регистров - устанешь считать
Ура! 100 человек просмотрели эту тему =) Угу, понял... А че это у тебя ebx = const = 0 ? =)) И добавили "всего" восемь (вроде) регистров. И что бы их юзать надо WinXP 64-bit =) Ну или *nix какой
mov eax, NULL = 5 байтов mov eax, ebx = 2 байта Смотри статьи про оптимизацию Ага восемь, посмотри на аттач. Выдрано из документации по fasm'у. _2102224892__registers.JPG
Ну... согласен На то он и ассемблер, чтобы меньше =) А разница в размере между "push 0" и "push ebx" есть? Так... начнем. Начиная с rax и кончая rdi - это старые регистры, расширенные до 64 бит. r8 - r15 это те, про которые я и говорил... b, w, d - суффиксы для обращения к разным частям регистров.