Любой процессор предоставляет как минимум один способ
такой адресации: адресация самих команд при их последовательной выборке
осуществляется при помощи счетчика команд с постинкрементом. У процессоров
с командами переменной длины величина постинкремента зависит от кода команды.
Некоторые процессоры позволяют использовать счетчик команд наравне со
всеми остальными регистрами общего назначения. Запись в этот регистр приводит
к передаче управления по адресу, который соответствует записанному значению.
Чтение из этого регистра позволяет узнать адрес текущей команды, что само
по себе не очень полезно и часто может быть сделано Другими способами.
Однако использование других режимов адресации со счетчиком команд порой
позволяет делать неожиданные, но весьма полезные трюки.
Литеральная и абсолютная адресация
в PDP-11 и VAX
VAX и PDP-11 не реализуют в чистом виде ни литерального, ни абсолютного
режимов адресации. Вместо этого литерал или адрес помещается в программную
память непосредственно за операндом и используется, соответственно, косвенно-регистровый
с постинкрементом и косвенный с постинкрементом режимы со счетчиком команд
Рис. 2.13. Реализация литеральной адресации через постинкрементную адресацию счетчиком команд
Использование счетчика команд в косвенно-регистровом режиме со смещением
позволяет адресовать код и данные относительно адреса текущей команды.
Такой режим адресации называется относительным. Программный модуль, в
котором используется только такая адресация, позиционно независим: его
можно перемещать по памяти, и он даже не заметит факта перемещения, если
только не получит управление в процессе самого перемещения, или не будет
специально проверять адреса на совпадение. Впрочем, почти такого же эффекта
можно достичь базовой адресацией.
Многие современные процессоры такого режима адресации для данных не предоставляют,
зато почти все делают нечто подобное для адресации кода. А именно, во
всех современных процессорах команды условного перехода используют именно
такую адресацию: эти команды имеют короткое адресное поле, которое интерпретируется
как знаковое смещение относительно текущей команды.
Дело в том, что основное применение условного перехода — это реализация
условных операторов и циклов, в которых переход осуществляется в пределах
одной процедуры, а зачастую всего на несколько команд вперед или назад.
Снабжать такие команды длинным адресным полем было бы расточительно и
привело бы к ненужному раздуванию кода.
Условные переходы на большие расстояния в коде встречаются относительно
редко, и чаще всего их предлагают реализовать двумя командами (пример
2.5).
Пример 2.5. Реализация условного перехода с длинным смещением
Beq distant_label ; Перейти, если равно
; реализуется как
Bneq $1 ; Перейти, если не равно
Jmp distant_label
; У команд безусловного перехода обычно используется длинное смещение
; или абсолютный адрес
$1:
Относительные переходы в системе команд
SPARC
У большинства CISC-процессоров адресное смещение в командах условного
перехода ограничено одним байтом. У SPARC такие команды используют адресное
поле длиной 22 бита. С учетом того факта, что команды у SPARC всегда выровнены
на границу слова (4 байта), такая адресация позволяет непосредственно
указать до 4М (4х220=4 194 304) команд или 16 Мбайт, т.е. целиком адресовать
сегмент кода большинства реально используемых программ (рис. 2.14).
Рис. 2.14. Формат команд условного перехода и вызова процессора SPARC
Команда вызова подпрограммы у SPARC также использует адресацию относительно счетчика команд, но адресное поле у нее 30-разрядное и интерпретируется как адрес слова, а не байта. При сложении смещения и счетчика команд возможные переполнения игнорируются, поэтому такой командой можно адресовать любое слово (т. е. любую команду) в 32-разрядном адресном пространстве. На первый взгляд, неясно даже, какая польза от того, что адресация производится относительно счетчика команд, а не абсолютно. Но в 64-разрядных процессорах SPARC v9 польза от этого большая — абсолютный 30-разрядный адрес позволял бы адресовать только первое гигаслово памяти, а относительное смещение адресует именно сегмент кода, в какой бы части 64-разрядного адресного пространства он бы ни находился. Программ, имеющих объем более одной гигакоманды, или даже половины гигакоманды, пока что не написано, поэтому 30-разрядного смещения практически достаточно для адресации в пределах любой современной программы.
Процессоры, не предоставляющие программисту прямого доступа к счетчику
команд, зачастую все-таки дают возможность записывать в него произвольные
значения при помощи специальных команд вычислимого перехода и вычислимого
вызова. Команды вычислимого вызова широко используются для реализации
указателей на функции из таблиц виртуальных методов в объектно-ориентированных
языках. Главное применение команд вычислимого перехода -- реализация операторов
switch языка C/C++ или case языка Pascal.