На главную
Подписка
Новости










Главная / MS-DOS / MS-DOS. РУКОВОДСТВО РАЗРАБОТЧИКА / Глава 3 / Переключение контекста и переключение стека Сделать домашней страницей Добавить в избранное Написать писмо

НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Переключение контекста и переключение стека

В связи с тем, что большинство тем, обсужденных в этой главе, относятся к операциям между отдельными программами с отдельными стеками, процесс переключения заслуживает некоторого внимания. Переключение стека, или переход от одного стека к другому является частью большой темы, называемой переключением контекста (context switching).


Если отобразить сегменты, в которых выполняется программа, как ее контекст, то можно увидеть, что при многих обстоятельствах бывает необходимо изменять полный контекст программы. Примерами этого могут служить вызовы резидентных подпрограмм, вызывающих библиотеки RTL и использующие некоторые типы оверлеев или сопрограмм. (Сопрограмма является структурной единицей программы, которая используется для описания логически параллельных действий и вызывается подобно подпрограмме. В отличие от подпрограммы, каждый вызов сопрограммы возобновляет ее выполнение с точки последнего возврата. Сопрограмма представляет собой вид специального оверлея, который не имеет связей порождающая-порожденная подпрограммы). В этом случае, когда одна подпрограмма получает управление, она желает установить для выполнения свои собственные сегмент данных, внешний сегмент и сегмент стека. Во время получения управления из другой программы наверняка известно только то, что ее программный сегмент и указатель инструкции установлены в надлежащие значения. Обратимся к листингу 3-9. После вызова функции загрузки и выполнения программы контекст вызывающей программы был сброшен и этот листинг показывает как устанавливать контекст программы. Пример, приведенный в листинге 3-9, несколько неудачен тем, что не сохраняет контекст предыдущей программы, а просто перезаписывает его.


При получении управления, если необходимо сохранить целый набор регистров, наиболее легким способом выполнения этого является способ, заключающийся в том, чтобы сначала установить новый стек программы и затем записать в него эти регистры. Поскольку значения стекового сегмента и указателя стека не могут быть сохранены в стеке вызывающей программы (в связи с отсутствием способа получения их обратно) и поскольку они не могут быть сохранены в новом стеке (который еще не установлен), параметры стека должны сохраняться в памяти. Если в виде исключения поместить в один и тот же сегмент программные коды и данные, то для сохранения старых стекового сегмента и указателя стека и установке новых стекового сегмента и указателя стека может быть использована последовательность программных кодов, показанная в листинге 3-11.



             Листинг 3-11. Переключение стека для программы типа .EXE
         ----------------------------------------------------------------
         enter:   mov   cs:old_stk_seg,ss  ; Сохранение значений старого
                  mov   cs:old_stk_ptr,sp  ; стека
                  mov   ss,cs:new_stk_seg  ; загрузка значений нового
                  mov   sp,cs:new_stk_ptr  ; стека
                  push  ds        ; регистры стекового сегмента
                  push  es
                  push  ax        ; начало записи в стек общих регистров
                  ...
                  push  bp
                  push  si
                  push  di
                  ...
         body:<тело программы>    ; здесь начинается тело программы
                  ...
                  pop   di        ; начало восстановления общих регистров
                  pop   si
                  pop   bp
                  ...
                  pop   ax
                  pop   es        ; восстановление регистров сегмента
                  mov   ss,cs:old_stk_seg  ; восстановление старых зна-
                  mov   sp,cs:old_stk_ptr  ; чений стека
                  jmp   exit               ; обход памяти данных
         old_stk_seg    dw   ?    ; стековый сегмент вызывающей программы
         old_str_ptr    dw   ?    ; указатель стека вызывающей программы
         ; стековый сегмент подпрограммы
         new_stk_seg    dw   segment stack
         ; указатель стека подпрограммы
         new_stk_ptr    dw   top_of_stack
         exit:                             ; позиция выхода
                  ret             ; возврат в вызывающую программу
         ----------------------------------------------------------------

Программные коды в листинге 3-11 зависят от имеющихся значений для стекового сегмента и указателя стека, уже размещенных в памяти. Для резидентных подпрограмм и подпрограмм RTL это должно быть выполнено с помощью процесса инициализации. Надлежащие значения в память для программ типа .EXE операционная система MS-DOS помещает в процессе настройки.


В связи с тем, что подпрограммы типа .COM не могут содержать значения сегмента, эти подпрограммы требуют другого способа переключения стеков. Запоминание значений для вершины стека в памяти не вызывает проблем, за исключением адреса начала сегмента. Т.к. подпрограммы типа .COM для своих целей совместно используют один и тот же сегмент, то значение стекового сегмента может быть получено из регистра программного сегмента. К несчастью, семейство микропроцессоров 8086 не поддерживает пересылку из регистра сегмента в регистр сегмента, поэтому значение может быть передано косвенным путем. В связи с отсутствием регистра, в котором можно было бы сохранить значение, значение передается через память, используя кодовый сегмент. Для реализации этого способа начинайте подпрограмму со следующей инструкции:



          mov   cs:new_stk_seg,cs   ; получение нового стекового сегмента

Если необходимо, то для переключения стеков в программе можно разработать два макроса, содержащих требуемые программные коды. Первый макрос включает программный код из входа в тело программы, а второй макрос программный код из выхода из тела программы. Оба макроса должны соответствовать именам переменных стека в области данных, а второй макрос, кроме того, должен принимать метку вершины стека top_of_stack как параметр для включения в предложение dw для указателя нового стека new_stk_ptr. В эти макросы не должна входить инструкция RET. Это позволит использовать эти макросы для выхода как с помощью инструкций JMP и IRET, так и с помощью инструкции RET.


Для файлов типа .EXE второй макрос должен также принимать как параметр имя стекового сегмента. Пример описанных выше макросов для файлов типа .COM содержится в листинге 3-12 (INIT28), приводимом позднее в этой главе.


НАЗАД СОДЕРЖАНИЕ ВПЕРЁД

Hosted by uCoz