Вызов функции LStrLen сделан с префиксом System, иначе компилятор не сможет распознать ее. LStrLen реализована в модуле System.
Секция VAR удалена, поскольку мы не ссылаемся ни к каким переменным по имени.
Code: |
function CharPos16(Chr : Char; const Str : AnsiString) : Cardinal; asm push ebx push esi mov esi,edx mov ebx,eax //StrLenght := Length(Str); mov eax,esi //call System.@LStrLen //************* test eax,eax jz @LStrLenExit mov eax,[eax-$04] @LStrLenExit : //************* mov edx,eax //if StrLenght > 0 then test edx,edx jle @Else1Begin //I := 0; xor eax,eax //repeat @RepeatBegin : //Inc(I); inc eax //until((Str[I] = Chr) or (I > StrLenght)); cmp bl,[esi+eax-$01] jz @If2 cmp edx,eax jnl @RepeatBegin //if I <= StrLenght then @If2 : cmp edx,eax jnl @Exit //Result := I //else //Result := 0; xor eax,eax pop esi pop ebx ret //else //Result := 0; @Else1Begin : xor eax,eax @Exit : pop esi pop ebx end; |
Первая вещь, которую мы сделаем, это сделаем функцию LstrLen inline. Сделаем это путем трассировки и копированием ее тела из окна CPU view. Она состоит из четырех строк.
Code: |
test eax,eax jz +$03 mov eax,[eax-$04] ret |
Если указатель, переданный через EAX, в функцию LStrLen имеет nil, то ничего не делается, а просто производится возврат из функции. Если же указатель действительный, то длина строки расположена, в 4 предшествующих строке байтах. Эти 4 байта возвращаются, через регистр EAX. Для превращения этой функции в inline функцию, мы заменим вызов этой функции этими четырьмя строками. Инструкция JZ передает управление на инструкцию RET. Взамен инструкции RET мы передадим управление на метку LStrLenExit. Инструкция RET осуществляет возврат из функции. Данная инструкция RET должна быть удалена, иначе она вернет управление в CharPos, это не то, что мы хотим. А вот так наша встроенная (inline) функция должна выглядеть.
Code: |
test eax,eax jz @LStrLenExit mov eax,[eax-$04] @LStrLenExit :
function CharPos17(Chr : Char; const Str : AnsiString) : Cardinal; asm push ebx push esi mov esi,edx mov ebx,eax //StrLenght := Length(Str); mov eax,esi //************* test eax,eax //jz @LStrLenExit jz @Else1Begin mov eax,[eax-$04] //@LStrLenExit : //************* mov edx,eax //if StrLenght > 0 then //test edx,edx //jle @Else1Begin //I := 0; xor eax,eax //repeat @RepeatBegin : //Inc(I); inc eax //until((Str[I] = Chr) or (I > StrLenght)); cmp bl,[esi+eax-$01] jz @If2 cmp edx,eax jnl @RepeatBegin //if I <= StrLenght then @If2 : cmp edx,eax jnl @Exit //Result := I //else //Result := 0; xor eax,eax pop esi pop ebx ret //else //Result := 0; @Else1Begin : xor eax,eax @Exit : pop esi pop ebx end; |
Теперь мы видим, что Паскаль строка; IF STRLENGHT > 0 THEN, проверяет длину точно также, как первая строка во встроенной LStrLen. Проверка Str на nil вполне достаточно ;-). Вторая строка удалена и первая изменена, чтобы переход был на @Else1Begin вместо простого выхода из встроенной StrLen функции, если Str равен nil. Теперь нет надобности в метке LStrLenExit.
Code: |
function CharPos18(Chr: Char; const Str: AnsiString) : Cardinal; asm push ebx push esi mov esi,edx mov ebx,eax //StrLenght := Length(Str); //mov eax,esi //if StrLenght > 0 then //test eax,eax test esi,esi jz @Else1Begin //mov eax,[eax-$04] mov eax,[esi-$04] mov edx,eax //I := 0; xor eax,eax //repeat @RepeatBegin : //Inc(I); inc eax //until((Str[I] = Chr) or (I > StrLenght)); cmp bl,[esi+eax-$01] jz @If2 cmp edx,eax jnl @RepeatBegin //if I <= StrLenght then @If2 : cmp edx,eax jnl @Exit //Result := I //else //Result := 0; xor eax,eax pop esi pop ebx ret //else //Result := 0; @Else1Begin : xor eax,eax @Exit : pop esi pop ebx end; |
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!