Войти и оставить в сборе? - PullRequest
18 голосов
/ 02 мая 2011

Я читал Язык искусства ассемблера (Рэндалл Хайд, ссылка на Amazon ), и я попробовал консольное приложение в этой книге. Это была программа, которая создала новую консоль для себя, используя функции Win32 API. Программа содержит процедуру с именем LENSTR, которая хранит длину строки в регистре EBP. Код для этой функции следующий:

LENSTR PROC
ENTER 0, 0
PUSH  EAX
;----------------------
CLD
MOV   EDI, DWORD PTR [EBP+08H]
MOV   EBX, EDI
MOV   ECX, 100 ; Limit the string length
XOR   AL, AL
REPNE SCASB ; Find the 0 character
SUB   EDI, EBX ; String length including 0
MOV   EBX, EDI

DEC   EBX
;----------------------
POP   EAX
LEAVE
RET   4
LENSTR ENDP

Не могли бы вы объяснить здесь использование команд enter и leave?

Ответы [ 3 ]

40 голосов
/ 02 мая 2011

Enter создает кадр стека, а leave уничтожает кадр стека. С параметрами 0,0 для enter они в основном эквивалентны:

; enter
push ebp
mov ebp, esp

; leave
mov esp, ebp
pop ebp

Хотя он и не используется в опубликованном вами коде, enter поддерживает выполнение немного большего, чем простая комбинация push / mov, показанная выше. Первый параметр enter указывает объем пространства, выделяемого для локальных переменных. Например, enter 5, 0 примерно эквивалентно:

push ebp
mov ebp, esp
sub esp, 5

Enter также поддерживает такие языки, как Pascal, которые могут использовать вложенные функции / процедуры:

procedure X;
    procedure Y;
    begin
        { ... }
    end
begin
   { ... }
end

В таком случае Y имеет доступ не только к своим собственным локальным переменным, но также ко всем переменным, локальным для X. Они могут быть вложены на произвольную глубину, так что вы можете иметь Z внутри Y, который имел доступ к своим собственным локальным переменным, а также переменным Y и переменным X. Второй параметр enter указывает глубину вложенности, поэтому X будет использовать enter Sx, 0, Y будет использовать enter Sy, 1, а Z будет использовать enter Sz, 2 (где Sx, Sy и Sz означает размер переменных, локальных для X, Y и Z соответственно).

Это создаст цепочку стековых фреймов для предоставления Z доступа к локальным переменным Y и X и т. Д. Это становится довольно нетривиальным, если функции являются рекурсивными, поэтому вызов Z не может просто подняться по стеку к двум самым последним кадрам стека - ему необходимо пропустить кадры стека из предыдущих вызовов самого себя, и Вернитесь непосредственно к стеку фреймов для лексической родительской функции / процедуры, которая отличается от вызывающего в случае рекурсии.

Эта сложность также объясняет, почему C и C ++ запрещают вложенные функции. Учитывая наличие ввода / вывода, их довольно легко поддерживать на процессорах Intel, но может быть значительно сложнее на многих других процессорах, которые не имеют такой прямой поддержки.

Это также, по крайней мере, помогает объяснить еще одну ... особенность enter - для используемого здесь тривиального случая (т. Е. enter 0, 0) он немного медленнее, чем эквивалент, использующий push / mov.

14 голосов
/ 02 мая 2011

Это настройка стекового кадра (записи активации) для функции.Внутренне это обычно выглядит примерно так:

push( ebp );         // Save a copy of the old EBP value

mov( esp, ebp );     // Get ptr to base of activation record into EBP

sub( NumVars, esp ); // Allocate storage for local variables.

Затем, когда кадр стека должен быть снова разрушен, вы должны сделать что-то вроде следующего:

   mov( ebp, esp );    // Deallocate locals and clean up stack.

   pop( ebp );         // Restore pointer to caller's activation record.

   ret();              // Return to the caller.

Здесь - лучшее объяснение этого с использованием HLA.Хотя это хорошо объясняется в книге, которую вы читаете, у меня тоже есть эта книга, и я прочитал раздел, объясняющий ее.

0 голосов
/ 02 мая 2011

Войдите и оставьте просто установить кадр стека.Обычно компиляторы генерируют код, который напрямую манипулирует указателями фрейма стека, так как ввод и выход не совсем бывают быстрыми по отношению к mov / sub (хотя раньше это было в течение 286 дней :-)).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...