Delphi + asm

Тема в разделе "WASM.ASSEMBLER", создана пользователем binary, 16 дек 2008.

  1. binary

    binary New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2008
    Сообщения:
    6
    Господа.
    Есть тупой вопрос.
    Я только начинаю в asm вникать...
    Так вот, написал я функцию перевода int в string... всё работает, в переменную S , благополучно помещаюься готовые символы, но поместить это в Result не удаётся ...в чемто затык

    Код (Text):
    1. function i2s(Value:Integer):String;
    2.  var s:array [0..18] of char;
    3. begin
    4.   Fillchar(s,18,0);
    5.   asm
    6.    lea edi,s  
    7.    mov eax,Value
    8.    xor ebx,ebx
    9.    mov edx,0
    10.    mov ecx,10
    11.    @main:
    12.    div ecx
    13.    push edx
    14.    xor edx,edx
    15.    inc ebx
    16.    cmp eax,0
    17.    jnz @main
    18.    @cvt:
    19.     pop eax
    20.     add eax,$30
    21.     mov byte ptr [edi],al
    22.     inc edi
    23.    dec ebx
    24.    test ebx,ebx
    25.    jnz @cvt
    26.   end;  // end asm
    27.   Result := s; // затык собственно тут, вылазит эксэпшн, то есть в S уже символы готовы.
    28. end; // end begin
     
  2. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    Код (Text):
    1. function IntToStr(Value:Integer):String;
    2. asm
    3.         XOR       ECX, ECX
    4.         PUSH      ECX
    5.         ADD       ESP, -0Ch
    6.  
    7.         PUSH      EBX
    8.         LEA       EBX, [ESP + 15 + 4]
    9.         PUSH      EDX
    10.         CMP       EAX, ECX
    11.         PUSHFD
    12.         JGE       @@1
    13.         NEG       EAX
    14. @@1:
    15.         MOV       CL, 10
    16. @@2:
    17.         DEC       EBX
    18.         CDQ
    19.         IDIV      ECX
    20.         ADD       DL, 30h
    21.         MOV       [EBX], DL
    22.         TEST      EAX, EAX
    23.         JNZ       @@2
    24.         POPFD
    25.         JGE       @@3
    26.         DEC       EBX
    27.         MOV       byte ptr [EBX], '-'
    28. @@3:
    29.         POP       EAX
    30.         MOV       EDX, EBX
    31.         CALL      System.@LStrFromPChar
    32.         POP       EBX
    33.         ADD       ESP, 10h
    34. end;
    35.  
    36. function StrToInt(Value: string): Integer;
    37. asm
    38.         XCHG     EDX, EAX
    39.         XOR      EAX, EAX
    40.         TEST     EDX, EDX
    41.         JZ       @@exit
    42.  
    43.         XOR      ECX, ECX
    44.         MOV      CL, [EDX]
    45.         INC      EDX
    46.         CMP      CL, '-'
    47.         PUSHFD
    48.         JE       @@0
    49. @@1:    CMP      CL, '+'
    50.         JNE      @@2
    51. @@0:    MOV      CL, [EDX]
    52.         INC      EDX
    53. @@2:    SUB      CL, '0'
    54.         CMP      CL, '9'-'0'
    55.         JA       @@fin
    56.         LEA      EAX, [EAX+EAX*4] //
    57.         LEA      EAX, [ECX+EAX*2] //
    58.         JMP      @@0
    59. @@fin:  POPFD
    60.         JNE      @@exit
    61.         NEG      EAX
    62. @@exit:
    63. end;
     
  3. binary

    binary New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2008
    Сообщения:
    6
    K10, спасибо.
    я это тоже видел в SysUtils.pas.
    Я просто хотел собственным способом конвертировать (((=
     
  4. VaStaNi

    VaStaNi Member

    Публикаций:
    0
    Регистрация:
    1 июн 2004
    Сообщения:
    203
    Адрес:
    Ukraine
    так тебе впору познакомиться с великолепными работами Владимира Кладова, который Delphi + asm уважает очень.
    Проект KOL + MCK самое то, а то что ты делаешь там есть, только вот насчет именно в asm не помню.
    Рекомендую http://www.kolnmck.ru/lessons/faq.shtml
     
  5. binary

    binary New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2008
    Сообщения:
    6
    VaStaNi, благодарю !!!
    Очччень в тему ресурс !!!
     
  6. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    Он там почти весь на асме. Но Int2Str и подобные преобразования в KOL мне что-то не понравились...
     
  7. binary

    binary New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2008
    Сообщения:
    6
    что то да, как-то грамоздко смотртся такое преобразование Int2Str:
    Код (Text):
    1. function Int2Str( Value : Integer ) : String;
    2. var Buf : array[ 0..15 ] of Char;
    3.     Dst : PChar;
    4.     Minus : Boolean;
    5.     D: DWORD;
    6. begin
    7.   Dst := @Buf[ 15 ];
    8.   Dst^ := #0;
    9.   Minus := False;
    10.   if Value < 0 then
    11.   begin
    12.     Value := -Value;
    13.     Minus := True;
    14.   end;
    15.   D := Value;
    16.   repeat
    17.     Dec( Dst );
    18.     Dst^ := Char( (D mod 10) + Byte( '0' ) );
    19.     D := D div 10;
    20.   until D = 0;
    21.   if Minus then
    22.   begin
    23.     Dec( Dst );
    24.     Dst^ := '-';
    25.   end;
    26.   Result := Dst;
    27. end;
     
  8. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    binary
    Затык в том, что нужно сохранять\восстанавливать регистры ebx\edi\esi, т.к. сама дельфя этого перед асм-вставками не делает, полагаясь на кодера ;)
     
  9. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    binary
    mov eax,Value - ну нужно, т.к. при fastcall параметр уже будет в EAX

    Fillchar(s,18,0); - зачем, если буфер потом заполняется?

    mov edx,0 - XOR EDX, EDX

    pop eax
    add eax,$30
    mov byte ptr [edi],al
    inc edi
    dec ebx
    test ebx,ebx // не нужно, .т.к DEC уже изменяет флаги
    jnz @cvt

    лучше что-то вроде

    // ESI - указатель на s
    // ECX - количесво символов (которое в EBX)
    POP EAX
    ADD EAX, '0'
    STOSB EAX

    Самое главное:
    В процедуре можно свободно оперировать регистрами EAX, EDX и ECX. Другие регистры (в твоем случае EBX и EDI) нужно в начале процедуры сохранять в стеке и перед выходом восстанавливать.

    Result := s; - скорее всего нужно SetString(s, <количесво_символов>)

    Вобще, зачем у тебя элементы сохраняются в стеке, потом вытаскиваются? Не лучше в одном цикле производить деление, преобразовывать в цифры и помещать в s ?
     
  10. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    Кстати вопрос: стоит ли заводить временный буфер of char, если можно сделать SetLength(Result,19), использовать её как буфер и после окончания асм-вставки укоротить при помощи SetLength(Result,ebx_который_надо где_то_сохранить)?
     
  11. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    K10
    Для чисто асм-функций да, а для асм-вставок не факт. В частности в данном варианте регистр eax перед FillChar "сам по себе" не сохраняется и соотв-но после FillChar в нем будет мусор. Именно из-за этих штучек лучше юзать не вставки, а нормальные асм-функции, чтобы не мешать пас- и асм-код ;)

    Сумневаюсь, тогда уж rep movsb + add esp ;)

    Можно, но о быстродействии как я понимаю тут речь вообще не идет ;)

    Конечно лучше, но символы формируются с конца и напрямую их в s не засунешь, нужно использовать ту же хитрость, что и в IntToStr - писать от конца к началу, но тогда от "собственного способа" практически ничего не останется :lol:

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

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    leo
    Копирование предложенным способом потребует вычисления длины ASCIIZ-строки, что само по себе зло и мерзость, плюс опять же создание AnsiString нужной длины и копирование в неё данных. Отрезание хвоста короткой строки - операция более быстрая, требует только изменения счётчика символов в строке и установки завершающего нулевого символа для совместимости с WinAPI.
     
  13. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    leo
    Ну да, я просто всегда делал полностью асм-функции...

    так заюзать тот же stosb с движением от конца?

    CyberManiac
    Да, точно, наверно можно даже не укорачивать, а просто поставить 0 в конце, поюзается да освободится вся целиком :)
     
  14. binary

    binary New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2008
    Сообщения:
    6
    дак я пробовал кнешно. по непонятным мне причинам, все те же манипуляции с Result-om что и с о временным буфером результатов не дают, Result не меняется ну никак, а буффер меняется (=
    Самое интересное, что если Result, например Pointer , то всё прекрасно работает, суну сразу в Result в асме, без всякого идусского 'Result:=s'

    по поводу скорости... ну кнешн, я хотелбы чтобы в итоге работало быстрее чем System.IntToStr (((=

    господа, пасибо всем ! А то я право уже за йадом пошёл в аптеку, или пат паровоз бы кинулся (=
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    CyberManiac
    Каким это предложенным и кем ? Подсчет результирующей длины делается в процессе получения символов и его можно заюзать в SetString\LStrFromPCharLen

    Во-первых, в пред.посте ты не упоминал о shortstring. Во-вторых, если в проге по умолчанию юзаются длинные строки, то один фиг при дальнейшем присваивании рез-та, например ShowMessage(I2S(i)); произойдет неявное преобразование короткой строки к AnsiString

    Кто-ж, спорит. Но кроме обрезки еще нуна переместить символы, т.к. их кол-во заранее не известно и первый полученный символ, он же последний в строке, нужно писать куда-то в конец этой строки. Или посоветуешь дополнить спереди пробелами, а затем вызвать TrimLeft ;) Или может предлагаешь пойти на грязный хак и обрезать не хвост, а голову (дописать перед первым символом байт длины и вернуть указатель на первый символ) ? Но в данном варианте, когда строка возращается через Result этот трюк не пройдет, тогда нужно юзать или var-параметр или же передавать в функцию указатель на буфер и возвращать pShortString, которая будет указывать куда-то внутрь этого буфера (тогда можно и константную AnsiString с-имитировать c RefCount=-1)
     
  16. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    binary
    Размечтался, борманы все же не зря свой хлеб столько лет кушают ;)

    Зря ты вообще со строками в асме связался, т.к. практически все строковые функции в дельфях - это несуществующие перегруженные функции, вместо которых в коде в зависимости от типа параметров подставляются недокументированные функции из system.pas типа LStrXXX
     
  17. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    попробуй это :))
     
  18. leo

    leo Active Member

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

    А, Y_Mur опередил со своей гипер(пупер)ссылкой :)
     
  19. binary

    binary New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2008
    Сообщения:
    6
    Брррр, мааать чесная .
    Как сказало бы подсказка в The Elder Scrolls III - Morrowind :
    "Вам необходимо поспать, чтобы обдумать полученные знания "
    %)

    ...блин точно, затык был в том что я не сохранял\восстонавливал ебх и едх