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

Тема в разделе "WASM.BEGINNERS", создана пользователем LOL, 12 май 2006.

  1. mix_mix

    mix_mix Михаил

    Публикаций:
    0
    Регистрация:
    8 окт 2005
    Сообщения:
    277
    Адрес:
    Токио


    push 0 = 2 байта

    push ebx = 1 байт + скорость



    +8 регистров SSE

    еще неизвестно, что с fpu и соотв. mmx
     
  2. LOL

    LOL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2006
    Сообщения:
    175
    Адрес:
    Russia
    thx.



    А, ну да.

    Только почему
    ?



    [ADD] :))) Сначала в отладчике посмотрел, что и вправду mov eax, 0 по размеру больше, чем mov eax, ebx. Потом спросил про push 0 и push ebx. Вот нет чтобы сразу в отладчике посмотреть =))) Так нет, сначала спросил - а потом посмотрел :dntknw: Зато "что быстрее" узнал :)[/ADD]
     
  3. mix_mix

    mix_mix Михаил

    Публикаций:
    0
    Регистрация:
    8 окт 2005
    Сообщения:
    277
    Адрес:
    Токио
    Ну, не написано, может еще fpu-регистры появились. А если появились, то увеличилось и кол-во mmx регистров, т.к. они представляют собой младшие 64 бита fpu-регистров.
     
  4. LOL

    LOL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2006
    Сообщения:
    175
    Адрес:
    Russia
  5. LOL

    LOL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2006
    Сообщения:
    175
    Адрес:
    Russia
    А че все спят что-ли? =)
     
  6. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    cresta





    Вспоминаем азы программирования на ассемблере:

    mov eax,[var] - поместить в EAX значение по адресу переменной var

    mov eax,var - поместить в ЕАХ адрес переменной var



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

    В тасме (в режиме IDEAL - единственно правильном и корректном режиме) — то же самое, как и в фасме.





    fasm не убог, это давно стало истиной де-факто. А masm отличается большим количеством багов и именно "убогими" возможностями макро.



    LOL



    Да.





    Да, но r12-r15 "зарезервированы" для сохранения (как в stdcall ebx,esi,edi.



    А добавлены только XMM, количество FPU/MMX регистров осталось прежним.
     
  7. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    IceStudent



    mov eax,[var] - поместить в EAX значение по адресу переменной var

    mov eax,var - поместить в ЕАХ адрес переменной var




    вспоминаем азы программирования:

    mov eax, dword ptr[var]

    mov eax, var

    обе инструкции загружают в eax дворд, расположеный по адресу переменной var.

    Чтобы загрузить адрес переменной, а не дворд по этому адресу, умные дяди специально придумали инструкцию lea, LoadEffectiveAddress.

    lea eax,var - помещает в eax адрес переменной var.

    можно воспользоваться и таким способом:

    mov eax,offset var.



    P.S.

    это дурное влияние фасма сказывается. вы уже не помните, что такое lea и что такое mov, какая разница между ними.

    А бажный фасм со своим кривым пониманием инструкций действительно убогий. Да и пример с ret в этом топике наглядно показывает это.
     
  8. LOL

    LOL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2006
    Сообщения:
    175
    Адрес:
    Russia
    cresta



    Сомневаюсь, что IceStudent этого не помнит =) А вот я... Я начал изучать асм по рассылке Калашникова. Правда всю ее я не прочитал :) Но он использовал для загрузки адреса именно offset вместе с mov (№004 - "(3) mov dx,offset My_string") Так что ФАсм здесь не причем :)

    И lea во всей рассылке встречалась ровно один раз ("lea dx,Mess_hello ;!!! LEA DX вместо MOV DX, OFFSET") =)



    А вот баги - это действительно неприятно :/



    Вот чего я толком не понял, так это про эти ret / retn 0

    По идее (ну... как я думаю) асм должен заменять ret на retn или retf в зависимости от процедуры. Почему он этого не делает?

    А также - почему мы пишем retn 0 ??? 0 указывет на то, сколько надо убрать из стэка байт. Т.к. у n_sub нет параметров, то пишется 0 ? Тогда почему 0, ведь call должен ложить в стэк адрес возврата и когда мы возвращаемся обратно, то он должен оттуда убираться, а при retn 0 ничего не будет убираться из стэка?

    Попытаюсь высказаться более понятно :) Итак. При вызове процы split в стэк кладется алрес возврата. Далее идут различные операции. Затем call'ом вызывается n_sub и при этом в стэк кладется еще один адрес возврата. Так? Затем снова к.л. действия и наконец должен идти возврат ret'ом с убиранием из стэка одного адреса возврата. Но при retn 0 (имхо) ничего не убирается. Как так? Будто call не ложит ничего в стэк :)



    Сорри, за громадное количесвто глупых вопросов...
     
  9. asd

    asd New Member

    Публикаций:
    0
    Регистрация:
    12 мар 2005
    Сообщения:
    952
    Адрес:
    Russia
    retn x убирает из стека адрес возврата + х баит
     
  10. LOL

    LOL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2006
    Сообщения:
    175
    Адрес:
    Russia
    ok. с этим понятно =) thx

    Ответ на вторую часть вопроса есть :)
     
  11. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    cresta



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





    О ней никто не забывал, но это "runtime" вычисление, а зачем заставлять процессор это делать, если можно получить адрес переменной при компиляции?





    Повторяю, синтаксис фасма базируется на синтаксисе тасма в режиме IDEAL. Зазгляните в мануалы интела и посмотрите, какой у них синтаксис. Явно не masm.





    Между прочим NRET я для масма написал себе, т.к. он так же генерил освобождение стекового фрейма.
     
  12. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257




    Вот что сгенерил масм на код процедуры split из первого ответа:


    Код (Text):
    1. 0040179A   . 56             PUSH ESI
    2. 0040179B   . 57             PUSH EDI
    3. 0040179C   . FC             CLD
    4. 0040179D   . 8D35 CD304000  LEA ESI,DWORD PTR DS:[4030CD]
    5. 004017A3   . 8D15 D8304000  LEA EDX,DWORD PTR DS:[4030D8]
    6. 004017A9   > 8BFA           MOV EDI,EDX
    7. 004017AB   . E8 0A000000    CALL InputBox.004017BA
    8. 004017B0   . 3C 20          CMP AL,20
    9. 004017B2   . 8D52 0A        LEA EDX,DWORD PTR DS:[EDX+A]
    10. 004017B5   .^74 F2          JE SHORT InputBox.004017A9
    11. 004017B7   . 5F             POP EDI
    12. 004017B8   . 5E             POP ESI
    13. 004017B9   . C3             RETN
    14. 004017BA  /$ AC             /LODS BYTE PTR DS:[ESI]
    15. 004017BB  |. AA             |STOS BYTE PTR ES:[EDI]
    16. 004017BC  |. 3C 20          |CMP AL,20
    17. 004017BE  |. 75 04          |JNZ SHORT InputBox.004017C4
    18. 004017C0  |. C607 00        |MOV BYTE PTR DS:[EDI],0
    19. 004017C3  |. C3             |RETN
    20. 004017C4  |> 84C0           |TEST AL,AL
    21. 004017C6  |.^75 F2          \JNZ SHORT InputBox.004017BA
    22. 004017C8  \. C3             RETN




    Где здесь освобождение фрейма по ret?

    В отличие от фасма, масм отсебятину не втыкает к код: ему сказали - ret, они и сделал ret (retn).







    О ленящихся заботится томаш со своим фасмом: специально для них mov eax, dword ptr[var] превратили в mov eax,[var], что неявно может привести к ошибке (особенно у начинающих), связанной с размером загружаемого операнда. Масм такую херню не позволит, тем самым предотвращая возможные ошибки.
     
  13. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Если же волнует освобождение стекового фрейма в процедурах, которые принимают через стек параметры (как например у LOL), то не надо проецировать на масм ограниченность фасма и изобретать макросы NRET - в масме есть такая штука:

    option prologue : none

    option epilogue : none

    и никаких стековых фреймов не формируется и не освобождается.
     
  14. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine

    Код (Text):
    1. masm:
    2. func proc var
    3.   ret
    4. func endp
    5.  
    6. fasm:
    7. proc func var
    8.   ret
    9. endp
    10.  
    11. masm:
    12. 0001100B  /$  55            PUSH    EBP
    13. 0001100C  |.  8BEC          MOV     EBP,ESP
    14. 0001100E  |.  C9            LEAVE
    15. 0001100F  \.  C2 0400       RETN    4
    16.  
    17. fasm:
    18. 0001105F  /$  55            PUSH    EBP
    19. 00011060  |.  89E5          MOV     EBP,ESP
    20. 00011062  |.  C9            LEAVE
    21. 00011063  \.  C2 0400       RETN    4




    В данном случае код одинаков. Про prologue/epilogue я знаю, но NRET использовался в большой функции, где самому следить за стеком было бы накладно, поэтому от стекового фрейма не отказывался. Хотя в фасме возможен фрейм на esp-регистре, что и сделал S_T_A_S_ пару лет назад.





    В размер ЕАХ не ошибится никто, следовательно dword ptr избыточен в данном случае.




    Код (Text):
    1. varb db 0
    2. vard dd 0
    3.  
    4. mov  eax,[varb]
    5. mov  eax,[vard]


    Результат компиляции для масма и фасма одинаков: успешен при vard и ошибка размера операнда при varb. Где предотвращение масма? И от чего оно?





    В фасме она тоже есть.



    Где ограниченность фасма? Она лишь в одном (пока): отсутствие отладочной информации, что связано с его кроссплатформенностью. Да и то, она обходится.
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Ну вот опять никчемные дискусии - уже не раз вопрос "правильного" синтаксиса пережевывали и все равно каждый остался при своем мнении. Но я тоже не могу удержаться от флейма и не вставить свое словечко ;))

    Можно говорить о "чистом асме" максимально приближенном к железу и оперирующим только адресами\смещениями и мнемониками инструкций\регистров x86, а можно говорить об Х-асме как языке программирования со своими прибамбасами и элементами HLL. "Железному" асму неведомы абстрактные типы и объявления переменных, поэтому например строчки
    Код (Text):
    1. myInt dd 0
    2. myStr db "Hello, World!",0
    "железный" асм должен 1) интерпретировать просто как директиву выделения и инициализации в области данных или кода соответсвующего количества байт и 2) myInt\myStr должен рассматривать не как какие-то "переменные" определенного типа, а просто как метки, т.е. мнемонические обозначения адресов памяти. Соответсвенно и мнемоники mov eax,myInt и mov eax,myStr означают загрузку в регистр адреса соответсвующей метки, а инструкции mov eax,[myInt] и mov eax,[myStr] - загрузку в регистр 4-х байт по соответсвующим адресам. С точки зрения железа все просто, логично и однозначно. Например, для чего спрашивается специально указывать mov eax,dword ptr [myStr] если в IA-32 есть один единственный вариант трактовки mov r32,m32 и ничего другого кроме dword этой интсрукцией в r32 засунуть в принципе невозможно ;)

    Но это невозможно для тех, кто опирается на железо и руководствуется первоисточниками - мануалами от Intel и AMD. А как же быть с "широкими массами", привыкшими к HLL, к типированным переменным, к тому что компилятор за них все проверит и подскажет что не так ? Да никак, просто создать убогий гибрид куцего HLL и железного асма ;) Пусть нелогично, зато привычно и необычно, есть над чем глову поломать и толстые книги пописать :)) Привычно в инструкциях mov eax,myInt и необычно в lea eax,[myInt+1] или mov al,byte ptr [myInt+1] - в первом случае myInt это значение переменной, а во втором - адрес, какое-то "раздвоение личности". Гибрид он и есть гибрид, и хваленая проверка типов на деле не всегда логично работает. Например, ml.exe (v 6.14.8444) нормально проглатывает mov eax,[myInt+1] бе всякого dword ptr (хотя именно здесь и может закрасться ошибка), но почему-то ругается на mov al,[myInt+1] (хотя по железной логике x86 тут ошибки быть не может и никакого byte ptr тут по идее не требуется).



    Ну и разумеется отдельная песня о ret. Тут уж я вообще не понимаю, как можно переопределять макросами инструкции x86 - остается выбросить на помойку мануалы Intel и AMD и заново учиться прибамбасам и загадочным ноу-хау очередного Х-асм. Неужели нельзя спец.мнемонику придумать: не знаю как в последних версиях фасма, а в 1.56 вроде как инструкцию ret = retn никто не переопределял и для выхода из stdcall-процедуры использовался макрос return. Это как раз великий заботливый masm всегда грешил такой подменой понятий. Неужели и у Томаша в погоне за "бездумно-ленивым" электоратом крыша поехала :)))
     
  16. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    IceStudent



    интересно :) взял мою фразу из поста о процедуре без параметров, откомпилировал процедуру с параметрами и предъявляешь как одинаковый код :))))

    Я уже упоминал отдельным постом, что если есть параметры, то для этого в масме существует option prologue.

    А если в фасме есть такая директива, почему же не посоветовал автору топика использовать её?





    Речь не о размере eax, а о размере var. И очень можно даже ошибиться, если переменных сотня - другая, и они разных типов. И dword указывает на размер var, а не размер eax.



    leo





    Если myInt - это dd, то данная метка известна компилятору как dword. Потому и ругается, что пытаешься в al затолкать дворд.

    Если в программе сотня-другая переменных разной размерности, ты что, помнишь их всех? Вот для этого и существует проверка, т.к. можно просто ошибиться в размере переменной.



    И вообще, хотел бы я посмотреть как бы вы отлаживали программу, в которой гипотетически заблокирована ошибка error A2070: invalid instruction operands :)
     
  17. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    leo



    Народ выпросил совместимость с масмом. Его синтаксис (правда, подключаемый), определение структур, и переопределение ret тоже :dntknw:





    Так фасм ведёт себя точно так же.



    cresta



    С параметрами или без - насчёт этого я в курсе, я про своё писал, почему не стал использовать без пролога/эпилога.





    Потому что тогда теряется удобство стекового фрейма.
     
  18. LOL

    LOL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2006
    Сообщения:
    175
    Адрес:
    Russia
    :) Никак не ожидал, что из банального вопроса получится такая оживленная дискуссия :))) Ну раз разбираться, то разбираться до конца ;)



    1. Что такое стэковый фрейм? В нем хранятся переменные, переданные процедуре. Хотя... они ж в стэке. Локальные переменные или что?



    2. Ну а на мой вопрос так ни кто и не ответил :dntknw:(( Правда я его неправильно задал :) Почему вместо ret генерируется leave / retn 0C? И каким образом это связано со стэковым фреймом? "Команда leave выполняет действия, противоположные действиям последней команды enter. Она логически уничтожает созданный командой enter стековый кадр со всеми содержащимися в нем локальными переменными и подготавливает стек к выполнению команды irct, завершающей переход в вызывающую процедуру". Почему в отладчике нету команды enter и irct ? Вместо enter'а этот стэковый фрейм создает call ?



    3.




    fasm: mov eax, DWORD [var]

    masm: mov eax, DWORD PTR [var]

    Это же вроде одно и тоже? Тогда о чем спор? Боишься не уследить за размерами всех переменных - пиши там дворд, ворд и т.д.



    4.


    А что она (и ее аналог в фасме) дает-то???



    5.


    а) А вот в mov al,[myInt+1], имхо, это уже в философию :). Согласно определению cresta, а также его же фразе о том, что
    , это не что иное, как "загрузить в al (размер которого известен) байт расположенный по адресу [myInt+1]" И какая разница какой тип у myInt, ведь myInt указывает в данном случаем всего лишь на адрес!



    б) Ошибка если переменная myInt имеет размер, например, 1 байт, а асм сочтет ее за дворд? Ну так опять же - myInt указывает на адрес - если хочешь байт, то и пиши byte ptr и т.д.



    Пожалуйста, помимо споров ответьте и на мои вопросы, ok?
     
  19. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    LOL

    1. Глянь в книжку. Стековый фрейм - это указатель на стек в момент входа в процедуру, который сохраняется в ebp. К локальным переменным теперь можно обращаться через [ebp-XXX] (адресуя стек выше адреса возврата), а к аргументам - [ebp+XXX].



    2.


    Забота компилятора.





    Потому что вместо неё push ebp/mov ebp,esp, что одно и то же.





    Об опциональности скобок в mov eax,var, что разъяснил leo :)



    4. Не создаёт фрейм, ты сам будешь писать mov eax,[esp+4+N] вместо mov eax,arg1 и следить за стеком (если он изменился, то изменять N в зависимости от разницы в esp на момент входа в подпрограмму.
     
  20. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    LOL



    Скорее тогда наоборот - не пиши ничего. Потому как например есть:
    Код (Text):
    1.  
    2. var db ?
    3.  


    а где-то вдали что-то вроде
    Код (Text):
    1.  
    2. mov al, [var]
    3. or  al, al
    4. jz  anylabel
    5.  


    а потом через пару дней тебе вдруг надо изменить на
    Код (Text):
    1.  
    2. var dd ?
    3.  


    ассемблер тебя будет хулить, и будет прав - а вдруг не отловил по ошибке? Размер переменной поменялся, а проверишь только младший байт :dntknw:

    А вот если написано
    Код (Text):
    1.  
    2. mov al, byte[var]
    3.  


    ассемблер молчит - откуда ему знать что ты имел ввиду?

    Такие ошибки (по собственному опыту скажу) очень тяжко ловить.



    С другой стороны если нужен БАЙТ - независимо от размера переменной - пиши байт, и будет щастье! Так что проблемы по-моему нет.





    Нет. Например во всех вменяемых Це-компиляторах фрейм создается:
    Код (Text):
    1.  
    2. push ebp
    3. mov ebp, esp
    4. sub esp, sizeoflocals
    5.  


    что полность идентично
    Код (Text):
    1.  
    2. enter 0, sizeoflocals
    3.  


    только эффективней. А вместо leave подставляют
    Код (Text):
    1.  
    2. mov esp, ebp
    3. pop ebp
    4.  


    По той же причине. Но если компилятор не только вменяемый, но и оптимизирующий, то он такой фигней вовсе не занимается, а пишет в прологе
    Код (Text):
    1.  
    2. sub esp, sizeoflocals
    3.  


    а в эпилоге
    Код (Text):
    1.  
    2. add esp, sizeoflocals
    3.  


    но считается, что для человека это труднее, поскольку адресация идет через esp, который может меняться на протяжении функции. Хотя я, например, никакой сложности здесь не ощущаю.