Запись в стек в Extern 8086 Процедура неактивна через MOV [BP],AL
Проблема:
Неактивная запись в стек во внешней процедуре
Код:
Внутри процедуры extern, которая просит пользователя ввести строку, а затем вернуть ее в стек через стек.
Строка определяется в сегменте данных с именем, отличным от имени сегмента данных в файле основной процедуры.
Data_segment_name_ext segment para
ORG 10H
Str DB 20,?,20 DUP (?)
Data_segment_name_ext ends
и объявление сегмента стека:
Stack_segment_name segment para stack
db 64 dup(0) ;define your stack segment
Stack_segment_name ends
Первоначально в начале процедуры я объявил ее общедоступной и установил для BP значение Stack top:
PUBLIC MyProc
Code_segment_name segment
MyProc PROC FAR
assume SS:Stack_segment_name,CS:Code_segment_name,DS:Data_segment_name_ext
PUSH BP
MOV BP,SP
Строка читается функцией AH=0x0A, прерывание 0x21
LEA DX,Str
MOV AH,0Ah
INT 21H
Попытка сохранить строку в стек, используя следующий цикл:
MOV CX,22 ; The string length
MOV SI,00 ; used as an index
TRA1:
DEC BP
MOV AL,Str[SI] ; Str is defined in the data segment
MOV [BP],AL
INC SI
LOOP TRA1
отладка программы с использованием кода 4.01 и MASM 6.11 приводит к следующему:
1-строка читается правильно и сохраняется в DS и смещается в Str [Фактическая строка начинается через два байта после максимальной длины, фактического количества]
2-Странное поведение при записи строки в стек:
Пусть SP первоначально =0xBA после цикла BP=0xA4 (т. Е. 0xBA-0x16(длина строки)). Сегмент стека дампов в SS:0xA4. Отображение данных за 8 байтов до SS: SP и правильные данные записываются после этого.
если str='ABCDEFGHIJ' только 'GHIJ' сохраняются в стеке
>DB SS:0xA4
SS:00A4 00 00 00 00 00 00 00 00 00 00 4A 49 48 47 E7 05 ..........JIHG..
SS:00B4 7E 00 FD 05 02 02 00 00 0A 00 0C 06 B8 E7 05 8E ~...............
Примечание: 060C:000A был CS:IP перед выполнением удаленного вызова к внешней процедуре и успешно передается @SP=0xC0(т. Е. На SS: 0xBC, SS: 0xBD, SS: 0xBE, SS: 0xBF)
3-замена MOV [BP],AL на MOV [BP],33h приводит к тому же поведению, 33h не записывается в первые 8 байтов вокруг старого TOS
4-Enforcing SS (то есть MOV SS:[BP],AL) также беспомощен, поскольку происходит то же самое поведение
Я знаю, что могу вернуть параметры альтернативными способами, но почему это происходит?
2 ответа
Поскольку цель вашей процедуры MyProc - вернуть строку через стек, вы неизбежно должны сохранить ее выше адреса возврата, помещенного в стек call
инструкция. Этот код делает это:
sub sp, 22
call MyProc
Теперь вместо ввода через дополнительный буфер в DS вы можете упростить задачу и вводить ее непосредственно в пространство, которое вы освободили в стеке.
mov ax, 20
sub sp, ax
push ax ;This sets up the correct buffer DOS expects
call MyProc
...
MyProc PROC FAR
assume SS:Stack_segment_name,CS:Code_segment_name
PUSH BP
MOV BP,SP
push ds
push ss
pop ds
lea dx, [bp+6]
;String is being read by function AH=0x0A interrupt 0x21
MOV AH,0Ah
INT 21H
pop ds
...
Я вижу, что вы установили стек только 64 байта. Если вы планируете хранить строки в стеке, я советую вам увеличить этот размер.
Регистр SP указывает текущую позицию вершины стека. Все ниже этого сумматора еще не в стеке. Вы не можете использовать адреса ниже SP для хранения каких-либо данных, потому что они будут перезаписаны после того, как что-либо будет помещено в стек (например, когда генерируется прерывание).
Для хранения локальных переменных в стеке вы уменьшаете SP (SUB SP, 22
). Это то же самое, что вставить 22 байта в стек.
В конце процедуры вам нужно освободить локальные переменные. Для этого вы увеличиваете SP (ADD SP, 22
). Это удаляет 22 байта из стека.
Как только вы это сделаете, локальные переменные больше не будут доступны.
На следующем рисунке показано состояние стека:
- Начало выполнения MyProc.
- Выделено место для локальных переменных.
- Строка, скопированная в стек.
- Локальные переменные удалены из стека.
- Произошло прерывание: состояние стека внутри обработчика прерываний.
- Обработчик прерываний завершил выполнение, вернулся в MyProc.
Начиная с шага 4 память, используемая для строки "ABC..HJ", больше не принадлежит MyProc. На следующем шаге эта память используется для обработки прерывания.
Невозможно сохранить данные в текущем кадре стека и вернуть их таким образом из процедуры.