Надлежащее соглашение для обработки стека при управлении параметрами и адресом возврата

Каков наилучший способ справиться с наличием адреса возврата вызывающей функции поверх любых параметров, которые были помещены в стек, когда вам нужно получить доступ к параметрам «ниже» в стеке? Я использую процессор S12 Motorola/Freescale. (S12 имеет: регистр D с 16 битами, состоящий из регистров A и B, каждый из которых имеет 8 бит. Регистры индексов X и Y по 16 бит, программный счетчик и указатель стека) Пример кода:

MAIN ORG    $1500        ;Set the start of the program 
     LDD    #SomeValue   ;Load the D register with a value
     PSHD                ;Push D onto the stack
     JSR    ROUTINE      ;Go to the subroutine - pushes the PC to the SP
END_MAIN    END

ROUTINE     
     PULD                ;Pull the top of the stack into the D register
                         ;D now holds the address for returning to the 
                         ;main function. 
     PSHD                ;Push the return address back onto the stack
END_ROUTINE RTS          ;Return to Main routine

Проблема в том, что вершина стека содержит адрес следующей инструкции, что затрудняет маневрирование. Например, если мне нужен параметр, который находится под адресом, мне придется либо вручную настроить SP (что кажется довольно хакерским), либо мне придется вытащить вершину стека и сохранить его в регистре, который принимает пространство. Изюминкой последнего подхода является сохранение адреса возврата в переменной. К сожалению, объявленные здесь переменные являются глобальными по своему охвату, что не кажется идеальным.

ReturnAddress EQU $2000        ;Declare variable at address $2000
STD           ReturnAddress    ;Store the D register's contents in variable

Есть ли другой вариант, которого я здесь не вижу?


person acampb311    schedule 25.01.2017    source источник
comment
При использовании других архитектур хитрость заключается в доступе к стеку относительно указателя стека, у вас есть такой режим адресации? Быстрый поиск в Google говорит, что да, вы можете сделать что-то вроде LDAA 4, SP.   -  person Jester    schedule 25.01.2017
comment
Если я понимаю, о чем вы спрашиваете, я так думаю. Я считаю, что для этого стек должен быть сначала загружен в один из индексных регистров. РЕДАКТИРОВАТЬ В этом случае можно ли получить доступ к нужным параметрам в подпрограмме, а затем вытолкнуть их из стека после возобновления исходной процедуры?   -  person acampb311    schedule 25.01.2017
comment
Обратитесь к своему руководству, в котором я гуглил, прямо говорится, что вы можете использовать SP.   -  person Jester    schedule 25.01.2017
comment
Ура, я только сейчас изучаю ассемблер, и, думаю, у меня возникли проблемы с формулировкой того, что именно я искал. Так что RTFM был не совсем моим решением.   -  person acampb311    schedule 25.01.2017


Ответы (1)


Благодаря некоторому вкладу Jester довольно просто иметь возможность наблюдать за тем, что происходит в стеке, и использовать содержащиеся в нем параметры. Я написал простую программу, демонстрирующую передачу параметров по значению и ссылке.

QUOTIENT    EQU     $1000       ;Variable to hold our QUOTIENT
REMAINDER   EQU     $1002       ;Variable to hold our REMAINDER

MAIN        ORG     $2000       ;Set the start of the program
            LDD     #!50        ;Load the D register with a value (16 bits)
            PSHD                ;Push D onto the stack (16 bits)
            LDD     #!10        ;Load the D register with a value (16 bits)
            PSHD                ;Push D onto the stack (16 bits)
            LDD     #QUOTIENT   ;Load the D register with an address (16 bits)
            PSHD                ;Push D onto the stack (16 bits)
            LDD     #REMAINDER  ;Load the D register with an address (16 bits)
            PSHD                ;Push D onto the stack (16 bits)
            JSR     DIVIDE      ;Push the PC onto the stack (16 bits).
            LEAS $0A, SP         ;Instead of PULD 5x, thanks Jester
END_MAIN    END


;******************************************************************************;
;DIVIDE - This routine expects the following parameters to be on the stack:
; STACK
;( 0 ) - (16 bits for return address)
;( 2 ) - (16 bits of address to store the REMAINDER (ANSWER var reference))
;( 4 ) - (16 bits of address to store the QUOTIENT (ANSWER var reference))
;( 6 ) - (16 bits for divisor)
;( 8 ) - (16 bits for dividend)
;******************************************************************************;
DIVIDE      LDD     8,SP       ;Loads the dividend (50)
            LDX     6,SP       ;Loads the divisor (10)
            IDIV               ;Divide
            LDY     4,SP       ;Get the address of the Quotient
            STX     0,Y        ;Store at that address
            LDY     2,SP       ;Get the address of the remainder
            STD     0,Y        ;Store at that address
END_DIVIDE  RTS
person acampb311    schedule 25.01.2017
comment
Обратите внимание, что вы обычно отбрасываете элементы из стека, настраивая указатель стека. Пять инструкций PULD обычно записываются как LEAS 10, SP. - person Jester; 26.01.2017
comment
Спасибо за предложение! - person acampb311; 26.01.2017