Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
Углубился я в дизассемблер 10.03.05 04:30 Число просмотров: 2701 [Heller]
Автор: Heller <Heller> Статус: Elderman
|
Для начала простой пример. Дано: a - int, проверка условия - if (a) (пример немного не в тему - привожу для дальнейшего сравнения):
cmp dword ptr [a (004225d8)],0
je main+25h (00401035)
Те же условия, но проверка (!a):
cmp dword ptr [a (004225d8)],0
jne main+25h (00401035)
При отрицании единственное что изменилось, это проверка с JE на JNE. В общем, именно так, как я писал уже выше.
Заменив в этих примерах "int a" на "int *a" не зменилось вообще ничего - код остался совершенно таким же. Компилятор при построении экзэшника не сделал разницы между указателем и обычным int'ом.
Вообще для любых целых типов он просто урезает/дополняет значение до dword. Например, для char'а это инструкция movsw.
Для вещественных чисел алгоритм более мудрёный:
fld dword ptr [a (00426968)]
fcomp dword ptr [__real@4@00000000000000000000 (0042301c)]
fnstsw ax
test ah,40h
В этом случае сравнение идёт по регистру SWR (пример дан для float). Всякие doubl'ы и прочие, видимо, работают аналогично, но я не стал разбираться - не то сейчас интересно. Кстати, для сравнений он всегда, не только с вещественными числами, но и с целыми, испольует test. Исключение составляет только тот случай, когда под переменную изначально выделено 4 байта - в этом случае используется cmp. Ну да это я так, к слову.
В общем, как это всё работает, понятно. Теперь про сравнения "==". Начну с простого int'аб сравнивая его с "0":
cmp dword ptr [a (00426968)],0
jne main+25h (00401035)
Для "!=" jne меняется на je. То есть, вообще говоря, компилятору исключительно пофик как именно идёт сравнение. "0" он и есть "0", а сравнение идёт обычным cmp, приводя изначально любое данное к dword.
Для полноты картины упомяну и про вещественные типы. В случае сравнения "==0" или "!=0" код получается такой же, как и приведённый выше (там где сравнивается SWR). А вот если проверка идёт уже с конкретным значением, например "==1", то компилятор уже не заморачивается и использует всё тот же cmp.
Теперь сравнение указателей. Приведу сразу общий случай:
Код на Си:
int *a,*b;
void main() {
if (a==b) {return;}
}
Соответственно на АСМе:
mov eax,[a (00426b94)]
cmp eax,dword ptr [b (00426b98)]
jne main+29h (00401039)
jmp main+2Bh (0040103b)
Теперь изврат:
if (a==((void *)0))
На АСМе. Вы будете смеяться:
cmp dword ptr [a (00426b94)],0
jne main+25h (00401035)
Тот же результат даёт сравнение с NULL. Причём совершенно пофик, что именно я с ним сравниваю, указатель или "обыкновенный" тип. И даже скажу больше: при сравнении с NULL типа float мы получаем всё те же самые fld и fcomp.
Получается, что следующие записи эквивалентны: (a), (a!=0), (a!=NULL). От следующих: (!a), (a==0), (a==NULL) они отличаются только иструкцией je вместо jne. При этом Си'шный тип (указатель/не указатель, char/не char) вообще оказывается не существенным.
|
|
|