Организация ЭВМ и систем: Курс лекций (Позиционные системы счисления. Процессоры семейства IA-32. Лазерные принтеры), страница 60

Оператор

                p(a, b, c)

транслируется в

                PUSH    a
                PUSH    b
                PUSH    c
                CALL    p

Это значит, что параметры, переданные процедуре p, находятся в стеке в обратном порядке, и, в предположении, что каждый из параметров имеет размер два байта, а процедура является дальней, после выполнения команды call стек будет выглядеть следующим образом:

Адрес

Значение

SP+10

SP+8

a

SP+6

b

SP+4

c

SP+2

адрес возврата (CS)

SP

адрес возврата (IP)

Кроме того, по соглашению PASCAL стек от параметров очищает сама процедура. Таким образом, процедура p будет иметь следующий вид:

p               PROC    FAR
                PUSH    BP
                MOV     BP, SP
a               EQU     [BP+8]
b               EQU     [BP+6]
C               EQU     [BP+4]
 
; Основная часть процедуры
; Регистр BP изменять нельзя,
; так как он адресует стековый кадр с параметрами
 
                POP     BP
                RET     6
p               ENDP

Тот же самый код большинство трансляторов способны порождать по усложнённой форме директивы PROC:

p               PROC    PASCAL, a:WORD, b:WORD, c:WORD
 
; Основная часть процедуры
; Регистр BP изменять нельзя,
; так как он адресует стековый кадр с параметрами
 
                RET
p               ENDP

Последняя команда RET будет автоматически заменена транслятором на

                RET     6

Главный недостаток соглашения PASCAL заключается в сложности создания процедур с переменным количеством параметров. Действительно, количество параметров процедура определяет, как правило, по некоторому числу первых обязательных параметров. Но в случае переменного количества параметров процедура не будет знать положения первого из них в стеке.

Данная проблема решается с помощью обратного порядка передачи параметров в стек, в результате которого параметры оказываются в стеке в прямом порядке. Такое соглашения применяется в языке программирования C, а также PROLOG и ряде других. По данному соглашению стек от параметров очищает вызывающая процедура.

Оператор

                p(a, b, c)

транслируется в

                PUSH    c
                PUSH    b
                PUSH    a
                CALL    p
                ADD     SP, 6           ; очистка стека

В прежних предположениях, после выполнения команды call стек будет выглядеть следующим образом:

Адрес

Значение

SP+10

SP+8

c

SP+6

b

SP+4

a

SP+2

адрес возврата (CS)

SP

адрес возврата (IP)

Процедура p имеет следующий вид:

p               PROC    FAR
                PUSH    BP
                MOV     BP, SP
a               EQU     [BP+4]
b               EQU     [BP+6]
C               EQU     [BP+8]
 
; Основная часть процедуры
; Регистр BP изменять нельзя,
; так как он адресует стековый кадр с параметрами
 
                POP     BP
                RET
p               ENDP

Тот же самый код большинство трансляторов способны порождать по усложнённой форме директивы proc:

p               PROC    C, a:WORD, b:WORD, c:WORD
 
; Основная часть процедуры
; Регистр BP изменять нельзя,
; так как он адресует стековый кадр с параметрами
 
                RET
p               ENDP

Соглашение C имеет ещё одно преимущество перед соглашением PASCAL. Стек не очищается от параметров вызываемой процедурой, поэтому, если необходимо вызвать несколько функций с одними и теми же параметрами, можно не заполнять стек каждый раз заново, то есть последовательность команд

                p1(a, b, c)
                p2(a, b, c)

можно транслировать не в

                PUSH    c
                PUSH    b
                PUSH    a
                CALL    p1
                ADD     SP, 6
                PUSH    c
                PUSH    b
                PUSH    a
                CALL    p2
                ADD     SP, 6

а в

                PUSH    c
                PUSH    b
                PUSH    a