Ответ 1
Я попытаюсь объяснить это, вернув код обратно в C.
Справочник по набору инструкций Intel (том 2 из Руководство для разработчиков программного обеспечения) неоценим для такого рода обратного проектирования.
REPNE SCASB
Логика для REPNE и SCASB в сочетании:
while (ecx != 0) {
temp = al - *(BYTE *)edi;
SetStatusFlags(temp);
if (DF == 0) // DF = Direction Flag
edi = edi + 1;
else
edi = edi - 1;
ecx = ecx - 1;
if (ZF == 1) break;
}
Или проще:
while (ecx != 0) {
ZF = (al == *(BYTE *)edi);
if (DF == 0)
edi++;
else
edi--;
ecx--;
if (ZF) break;
}
Длина строки
Однако приведенного выше недостаточно, чтобы объяснить, как он вычисляет длину строки. Основываясь на наличии not ecx
в вашем вопросе, я предполагаю, что фрагмент принадлежит этой идиоме (или подобной) для вычисления длины строки с помощью REPNE SCASB
:
sub ecx, ecx
sub al, al
not ecx
cld
repne scasb
not ecx
dec ecx
Перейдя на C и используя нашу логику из предыдущего раздела, получим:
ecx = (unsigned)-1;
al = 0;
DF = 0;
while (ecx != 0) {
ZF = (al == *(BYTE *)edi);
if (DF == 0)
edi++;
else
edi--;
ecx--;
if (ZF) break;
}
ecx = ~ecx;
ecx--;
Упрощение использования al = 0
и DF = 0
:
ecx = (unsigned)-1;
while (ecx != 0) {
ZF = (0 == *(BYTE *)edi);
edi++;
ecx--;
if (ZF) break;
}
ecx = ~ecx;
ecx--;
Примечания:
- в двухзначной нотации, переворачивание бит
ecx
эквивалентно-1 - ecx
. - в цикле
ecx
уменьшается до того, как цикл прерывается, поэтому он уменьшает наlength(edi) + 1
в целом. -
ecx
никогда не может быть нулевым в цикле, поскольку строка должна занимать все адресное пространство.
Итак, после цикла выше ecx
содержит -1 - (length(edi) + 1)
, который совпадает с -(length(edi) + 2)
, который мы переворачиваем биты, чтобы дать length(edi) + 1
, и, наконец, декремент, чтобы дать length(edi)
.
Или перестроить цикл и упростить:
const char *s = edi;
size_t c = (size_t)-1; // c == -1
while (*s++ != '\0') c--; // c == -1 - length(s)
c = ~c; // c == length(s)
И инвертирование счета:
size_t c = 0;
while (*s++ != '\0') c++;
который является функцией strlen
из C:
size_t strlen(const char *s) {
size_t c = 0;
while (*s++ != '\0') c++;
return c;
}