Косвенно-регистровый режим со смещением
Адрес операнда образуется путем сложения регистра и
адресного поля команды. Этот режим наиболее богат возможностями и, в зависимости
от стиля использования, имеет много других названий, например базовая
адресация или индексная адресация.
Адресное поле необязательно содержит полноценный адрес и может быть укороченным.
Команды id/st процессора SPARC, используемые
в примере 2.2, реализуют косвенно-регистровую адресацию с 13-разрядным
смещением.
Возможные варианты использования этого режима адресации многочисленны.
Например, если смещение представляет собой абсолютный адрес начала массива,
а в регистре хранится индекс, этот режим может использоваться для индексации
массива. В этом случае смещение должно представлять собой полноценный
адрес.
3 другом случае, в регистре может храниться указатель на структуру Данных,
а смещение может означать смещение конкретного поля относительно начала
структуры. Еще один вариант -- регистр хранит указатель на стековый кадр
или блок параметров процедуры, а смещение -адрес локальной переменной
в этом кадре или определенного параметра.
В этих случаях можно использовать (и обычно используется) укороченное
смещение.
Стековый кадр
Стековый кадр является стандартным способом выделения
памяти под локальные переменные в алголоподобных процедурных языках (С,
C++, Pascal) и других языках, допускающих рекурсивные вызовы.
Семантика рекурсивного вызова в алголоподобных языках требует, чтобы каждая
из рекурсивно вызванных процедур имела собственную копию локальных переменных.
В SPARC это достигается сдвигом регистрового окна по регистровому файлу
(рис. 2.9), но большинство других процессоров такой роскоши лишены и вынуждены
выделять память под локальные переменные в стеке, размещаемом в ОЗУ.
Рис. 2.9. Регистровый стек процессора SPARC
Для этого вызванная процедура уменьшает (если стек растет
вниз) указатель стека на количество байтов, достаточное, чтобы разместить
переменные. Адресация этих переменных у некоторых процессоров (например,
у PDP-11) происходит относительно указателя стека, а у большинства — например,
у МС680хО и VAX, с большим количеством регистров или у х86, указатель
стека которого нельзя использовать для адресации со смещением — для этой
цели выделяется отдельный регистр (рис. 2.10, пример 2.4).
Пример 2.4. Формирование, использование
и уничтожение стекового кадра. Код на языке С и результат его обработки
GNU С 2.7.2.1 (комментарии автора)
#include <stdio.h>
# include <strings.h>
/* Фрагмент примитивной реализации сервера SMTP (RFC822)
*/
int parse_line(FILE * socket)
{
/* Согласно RFC822, команда имеет длину не более 4 байт,а вся строка —
не более 255 байт V char cmd[5], args [255]; fscanf (socket, "%s
%s\n", cmd, args);
if (stricmpfcmd, "HELO")==0) {
fprintf (socket, "200 Hello, %s, glad to meet you\n", args);
return 200;
)
/* etc */
fprintf (socket, "500 Unknown command %s\n", cmd);
return 500;
.file "sample" gcc2_compiled. : _ gnu_compiled_c : .text LCO:
.ascii "%s %s\12\0" LCI:
.ascii "HELCAO" LC2:
.ascii "200 Hello, %s, glad to meet you\12\0" LC3:
.ascii "500 Unknown command %s\12\0"
.align 2, 0x90 .globl _parse_line _parse_line:
; x86 имеет для этой цели специальную команду enter, но она может ; формировать
кадры размером не более 255 байт. В данном случае кадр ; имеет больший
размер, и его необходимо формировать вручную.
pushl %ebp ; Сохраняем указатель кадра
; вызвавшей нас подпрограммы.
movl %esp, %ebp ; Формируем указатель нашего кадра
subl $264,%esp ; И сам кадр. ; Конец пролога функции
leal -264 (%ebp) , %еах ; Помещаем в стек указатель на args • pushl %eax
leal -8 (%ebp) , %еах ; ... на cmd
pushl %eax
pushl $LCO ; на строковую константу
; Наши собственные параметры тоже адресуются относительно кадра. movl
8(%ebp),%eax ; Параметр socket мы тоже проталкиваем pushl %eax ; в стек
call fscanf ; Вызов (параметры в стеке) addl $16,%esp ; очищаем стек
; в языке С переменное количество параметров, поэтому вычищать их из
; стека должна вызывающая процедура. Вызываемая просто не знает,
; СКОЛЬКО ИХ бЫЛО.
pushl $LC1
leal -8(%ebp),%eax
pushl %eax
call _stricmp
addl $8,%esp
movl %eax,%eax ; выключенная оптимизация в действии :)
; А ведь недалеки времена, когда компиляторы только такое и умели ; генерировать.
testl %eax,%еах
jne L14
leal -264(%ebp),%еах
pushl %eax
pushl $LC2
movl 8(%ebp),%eax
pushl %eax
call _fprintf
addl $12,%esp
; Обратите внимание, что компилятор не стал генерировать второй эпилог
; функции на втором операторе return.
movl $200,%eax
jmp L13
» Выравнивание потенциальных точек перехода на границу слова полезно:
» процессор не будет тратить дополнительный цикл шины на чтение » невыровненной
команды. Для выравнивания используется команда NOP ; (код операции 0x90).
align 2,0x90 L14:
leal -8(%ebp),%еах
Pushl %eax
Pushl $LC3
movl 8(%ebp),%eax pushl %eax
call _fprintf
addl ?12,%esp
movl $500,%eax
jmp L13
.align 2,0x90 L13:
; Команда leave совершает действия, обратные прологу функции: ; Она эквивалентна
командам: move %ebp, %esp; pop %ebp. ; Размер кадра явным образом не указывается,
поэтому ограничений ; на этот размер в данном случае нет.
leave
ret
Рис. 2.10. Стековый кадр
Примечание
Обратите внимание, что программа из примера 2.4 содержит серьезнейшую
ошибку. В комментариях сказано, что команда обязана иметь длину не более
4 байт, а вся строка вместе с аргументами не более 255. Если программа-клиент
на другом конце сокета (сетевого соединения) соответствует RFC822 [RFC822],
так оно и будет. Но если программа требованиям этого документа не соответствует,
нас ждет беда: нам могут предложить более длинную команду и/или более
длинную строку. Последствия, к которым это может привести, будут более
подробно разбираться в главе 12.
Но вернемся к стековым кадрам.
Стековые кадры в системе команд SPARC
Микропроцессоры SPARC также не могут обойтись без стекового кадра. Во-первых,
не всегда локальные переменные процедуры помещаются в восьми 32-разрядных
локальных регистрах. Именно такая процедура приведена в примере 2.4. Во-вторых,
нередки ситуации, когда в качестве параметров надо передать по значению
структуры, для которых 6 регистров-параметров тоже не хватит. В-третьих,
глубина регистрового файла ограничена и при работе рекурсивных или просто
глубоко вложенных процедур может исчерпаться. В-четвертых, в многозадачной
системе регистровый файл может одновременно использоваться несколькими
задачами. Все эти проблемы решаются при помощи создания стекового кадра
[www.sparc.com v9].
Для этой цели используются регистры Isp (о6) и %fp (i6). Команда save
%sp, -96 %sp делает следующее: она складывает первые два операнда, сдвигает
стековый кадр и помещает результат сложения в третий операнд. Благодаря
такому порядку исполнения отдельных операций, старый %sp становится %fp,
а результат сложения помещается уже в новый %sp.
Самую важную роль стековые кадры играют при обработке переполнений регистрового
файла. Регистровый файл SPARC представляет собой кольцевой буфер, доступность
отдельных участков которого описывается привилегированными регистрами
CANSAVE и CANRESTORE. Окна, находящиеся между значениями этих двух регистров,
доступны текущей программе (рис. 2.11). На рисунке показано состояние
регистрового файла, в котором текущий процесс может восстановить один
стековый кадр (CANRESTORE=1) и сохранить три (CANSAVE=3). Регистр OTHERWIN
указывает количество регистровых окон, занятых другим процессом. Регистровое
окно w4 на рисунке (обозначенное как перекрытие) занято лишь частично.
Текущее окно, частично занятое окно и участки регистрового файла, описанные
перечисленными регистрами, в сумме должны составлять весь регистровый
файл, так чтобы соблюдалось отношение CANSAVE + CANRESTORE + OTHERWIN
= NWINDOWS - 2, Где NWINDOWS- количество окон (на рисунке регистровый
файл имеет 8 окон, т. е. 128 регистров).
Рис. 2.11. Регистровый файл SPARC в виде кольцевого буфера.
Регистры CANSAVE и CANRESTORE (цит. по [www.sparc.com v9])
Когда же программа пытается сдвинуть свое окно за описанные
границы (в ситуации, изображенной на рис 2.11 это может произойти после
вызовов четырех вложенных процедур или после возврата из двух процедур
— текущей и соответствующей окну w7), генерируются исключительные состояния
заполнения окна (window fill) и сброса окна (window spill). При этом вызывается
системная процедура, которая освобождает окна из интервала OTHERWIN, сбрасывая
их содержимое в стековые кадры соответствующих процедур и при заполнении
восстанавливает содержимое принадлежащего нам окна из соответствующего
кадра.
В многозадачной системе заполнение и сброс окна может произойти в любой
момент, поэтому пользовательская программа всегда должна иметь по стековому
кадру на каждое из используемых ею регистровых окон, а указатель на этот
кадр должен всегда лежать в %sp соответствующего окна. При этом очень
важно, чтобы создание стекового кадра и сдвиг регистрового окна производились
одной командой.
|