воскресенье, 27 февраля 2011 г.

Отличия ADDR и OFFSET

Проясним момент насчет различия операторов ADDR и OFFSET в программах, написанных на Ассемблере.
Первоочередное назначение данных операторов - это получение адреса переменной в памяти.
В программах на ассемблере могут присутствовать как локальные так и глобальные переменные.
Глобальные переменные существуют в памяти на протяжении всего времени выполнения программы, локальные - только во время выполнения процедуры, в которой они определены, и удаляются как только она завершит работу. Поэтому адреса глобальных переменных известны уже на стадии ассемблирования, тогда как адреса локальных переменных в стеке станут известны только во время выполнения программы, а точнее при выполнении процедуры, в которой эти переменные объявлены.
Что касается операторов, то OFFSET вычисляет адрес уже размещенных к началу выполнения программы переменных, а это значит что данный оператор можно использовать для вычисления адресов только глобальных переменных.
С помощью оператора ADDR можно получить адрес локальной переменной.
Но почему так получается, что с помощью ADDR можно узнать адрес локальной пременной, а с помощью OFFSET - нельзя. Дело в том, что ассемблер, встретив оператор ADDR, использующийся с локальной переменной, генерирует последовательность инструкций
lea eax, localVar
push eax
ну а инструкция lea уже делает свое дело. Т.к. ADDR превращается в выше указанную посдедовательность инструкций, данный оператор можно использовать только с директивой invoke для передачи адреса переменной в качестве параметра. Присваивание регистру полученного таким способом адреса невозможно. ADDR можно так же использоваться и с глобальными переменными. В этом случае ассемблер сгенерирует
push offset globalVar
И в отличие от OFFSET, ADDR не умеет вычислять смещения меток, определенных далее в коде.
mov eax, offset l1 ; так можно
invoke Foo, ADDR l1; так нельзя
l1:
xor ebx, ebx
invoke Foo, ADDR l1; так можно