ФЭНДОМ


Общие сведения Править

С точки зрения прикладного программиста, процессор располагает 16-ю 32-разрядными регистрами общего назначения (РОН, GPR), из которых три на деле имеют специальные функции:

  • общие регистры R0–R12;
  • указатель стека SP, он же регистр R13;
  • регистр связи LR, он же регистр R14;
  • счётчик команд PC, он же регистр R15.

Первые 13 регистров с точки зрения архитектуры являются абсолютно равноправными, за исключением двух моментов:

  • в командах набора ARM LDRD и STRD, оперирующих сразу парой регистров, указывается всегда регистр с чётным номером, а пару с ним составляет следующий за ним регистр с нечётным номером (заметим, что в аналогичных командах набора Thumb-2 это правило не действует: оба используемых регистра указываются там явным образом);
  • в почти всех командах набора Thumb и в некоторых командах Thumb-2 могут использоваться регистры R0-R7, но не могут регистры с большими номерами.

Остальные три регистра имеют специальное назначение. Счётчик команд как РОН использоваться не может, а в командах применяется для достижения специальных целей, причём возможности его использования зависят от вида команды и от используемой системы команд. LR может использоваться как РОН в тех случаях, когда он не применяется по своему прямому назначению. Возможность такого использования для SP определяется версией архитектуры и используемой системой команд. В частности, в архитектуре ARMv7-M при записи в SP младшие два бита принудительно устанавливаются в 0, что ограничивает возможности его применения как обычного РОНа. Подробнее об использовании этих регистров сказано ниже.

Как уже отмечалось, в системе команд Thumb свободно могут использоваться лишь регистры R0–R7, называемые также младшими регистрами. Явный доступ к старшим регистрам в Thumb крайне ограничен и возможен лишь в некоторых командах. Система команд Thumb-2 преодолела это ограничение, однако для доступа к старшим регистрам в ней применяются новые 32-разрядные команды. Таким образом, при оптимизации кода, написанного для системы команд Thumb-2, надо избегать использования старших регистров, чтобы по возможности использовались 16-разрядные команды набора Thumb. Система команд ARM ограничений на доступ к регистрам не имеет.

С точки зрения системного программиста, процессор имеет большее число регистров общего назначения, хотя в каждый конкретный момент времени доступны лишь 16 из них. В процессорах A- и R-профилей их имеется либо 31, либо 33 в зависимости от того, реализован режим монитора или нет. Это число получается следующим образом:

  • регистры R0–R7 и PC существуют в единственном экземпляре, общем для всех режимов;
  • регистры R8–R12 существуют в двух экземплярах: для режима обработки быстрого прерывания (FIQ) и для всех остальных режимов;
  • регистры LR и SP являются общими для режимов пользователя и системы, но существуют отдельно для каждого другого режима, т.е. в сумме их имеется 6 или 7 пар.

Когда необходимо указать, регистр какого именно режима используется, в документации используется запись вида LR_svc (в данном случае она указывает на регистр LR режима супервизора).

В процессорах M-профиля имеется 16 или 17 регистров. R0–R12, LR и PC существуют в одном экземпляре, а SP — в одном или двух: указатель основного стека имеется всегда, а указатель стека процесса всегда присутствует в архитектуре ARMv7-M, но отсутствует в некоторых разновидностях архитектуры ARMv6-M (в документации указатели стека обозначаются как SP_main и SP_process либо MSP и PSP). В режиме обработчика всегда используется указатель основного стека; в режиме потока может использоваться как он, так и указатель стека процесса, что определяется содержимым управляющего регистра CONTROL. Для доступа к конкретному указателю стека привилегированный код может воспользоваться инструкциями MRS и MSR.

Заметим, что документация на архитектуру ARMv7-M несколько противоречива: в одном месте утверждается, что в режиме обработчика всегда используется указатель основного стека, а в другом – что если в режиме обработчика регистр CONTROL задаёт использование стека процесса, реакция процессора будет непредсказуемой. Таким образом, во избежание возможных проблем необходимо обеспечить, чтобы регистр CONTROL в режиме обработчика всегда задавал использование основного стека.

Особые случаи использования регистров Править

Счётчик команд PC (R15) Править

Регистр PC (Program Counter) используется для хранения адресов выполняющихся команд. При последовательном выполнении команд он последовательно увеличивается, при переходах и прерываниях в него загружается новое значение.

Многие команды запрещают программисту явно использовать PC или налагают на это определённые ограничения, что всегда оговаривается в описаниях конкретных команд. Нарушение этих правил обычно ведёт к непредсказуемым результатам.

В тех случаях, когда описание команды не налагает ограничений на использование PC, применяются изложенные ниже правила.

Считывание счётчика команд Править

Считывание PC используется главным образом для позиционно-независимой адресации, включая позиционно-независимые переходы, загрузку констант (так называемых литералов; на языке ассемблера эти операции задаются командами вида LDR Rn, =const) и вычисление адресов других команд и ячеек памяти (для этого обычно используется псевдокоманда ADR, транслируемая в зависимости от значения смещения в команду ADD или SUB).

При использовании системы команд ARM считанное значение счётчика команд будет на 8 превышать адрес текущей команды (в которой осуществляется это считывание). Два младших бита PC всегда будут равны нулю, поскольку команды ARM всегда выровнены на границу слова.

Исключением из этого правила является сохранение PC с помощью команд STR и STM: записанное в память значение счётчика команд будет превышать адрес этих инструкций либо на 8, либо на 12 в зависимости от реализации. Если одна из них сохраняет значение PC, увеличенное на 8 или 12, то и другая будет сохранять значение, увеличенное на такую же величину. Заметим, что использование в команде STR счётчика команд в роли источника адреса, по которому будет производиться сохранение, подчиняется общему правилу: его содержимое будет на 8 больше адреса самой команды.

При считывании регистра PC в командах набора Thumb его значение само по себе будет превышать адрес текущей команды на 4, при этом младший бит будет равен нулю. Однако если PC используется в 16-разрядном варианте команды ADD Rd, PC, #const, предназначенной для вычисления адреса относительно текущего значения счётчика команд, у складываемого с константой значения PC принудительно обнуляется разряд 1. В результате значение PC, выровненное на границу слова, будет на 2 или 4 превышать адрес этой команды ADD в зависимости от её собственного адреса. Аналогичному принудительному выравниванию подвергается значение PC, используемое в качестве базового адреса в 16-разрядной команде LDR Rd, [PC, #imm8 * 4], что необходимо для корректной загрузки слова.

В системе команд Thumb-2, помимо двух приведённых выше случаев, принудительное выравнивание значения PC на границу слова выполняется при его использовании в качестве базового регистра в 32-разрядных инструкциях LDC, LDR, LDRB, LDRD, LDRH, LDRSB и LDRSH, а также при использовании для вычисления адреса в 32-разрядных вариантах команд ADD Rd, PC, #const и SUB Rd, PC, #const.

Запись в счётчик команд Править

Поскольку счётчик команд содержит адрес выполняемой команды, запись в него вызывает переход на команду по записываемому адресу. В командах, где он может явно указываться в качестве регистра-приёмника, используются следующие общие правила.

В арифметико-логических инструкциях набора ARM использование PC в качестве приёмника вызывает переход на соответствующий адрес. В ранних версиях (все варианты ARMv5 и раньше) записываемое в PC значение должно иметь нули в двух младших разрядах, иначе последствия будут непредсказуемыми. В версии ARMv6 два младших бита записываемого значения игнорируются и принудительно устанавливаются в 0. Наконец, в версии ARMv7 младший бит используется в качестве индикатора системы команд, активизируемой после перехода: если он равен нулю, по-прежнему будет использоваться система команд ARM (при этом бит 1 должен быть равен нулю), а если равен единице — система команд Thumb (тогда бит 1 является частью адреса перехода).

Специальным случаем является использование регистра PC в качестве приёмника в S-разновидностях команд обработки данных: в такой ситуации происходит возврат из прерывания, когда в PC заносится результат операции, а в регистр текущего состояния CPSR — содержимое регистра сохранённого состояния SPSR, при этом система команд устанавливается в соответствии со значением, загружаемым из SPSR. Подробнее об этом говорится в разделе «Обработка исключений». Заметим, что этот вариант загрузки PC может использоваться только при нахождении процессора в одном из режимов обработки прерываний, но не в режимах пользователя или системы, где нет SPSR.

Инструкции загрузки LDR и LDM также могут использоваться для перехода на заданный адрес. В версии ARMv4 два младших бита загружаемого адреса должны быть равны нулю, в противном случае результат будет непредсказуем. Начиная с версии ARMv5T, младший бит определяет систему команд, а бит 1 должен быть равен нулю, если загружаемый адрес задаёт систему команд ARM. Благодаря этому во всех версиях, начиная с ARMv5T, подобная загрузка может использоваться для возврата из подпрограммы независимо от того, какую систему команд использовала вызывающая программа; в версии ARMv4T переключение между системами команд возможно лишь с помощью инструкции BX, а также при возврате из прерывания.

В системе команд Thumb явная запись в PC возможна в 16-разрядных командах ADD и MOV, при этом младший бит записываемого значения игнорируется и принудительно устанавливается в 0. Переключение системы команд при этом не производится.

Загрузка PC из памяти возможна с помощью команды POP. В версии ARMv4T она игнорирует значение младшего бита загружаемого значения, принудительно устанавливая его в 0, а начиная с версии ARMv5T, использует его как индикатор системы команд, на которую выполняется переход.

В системе команд Thumb-2 возможность загрузки PC появилась и в команде LDR. Младший бит загружаемого значения рассматривается как индикатор системы команды. В отличие от системы команд ARM, в формально аналогичных командах обработки данных Thumb-2 использование PC как приёмника результата невозможно.

Указатель стека SP (R13) Править

Регистр SP предназначен для использования в качестве указателя стека.

Единственной инструкцией набора ARM, неявно использующей SP по прямому назначению, является весьма специфическая команда SRS, доступная только в привилегированных режимах и появившаяся в ARMv6. В остальном же никаких специальных команд для работы со стеком у набора ARM нет; вместо них применяются обычные команды загрузки и записи данных, в которых SP указывается в качестве базового регистра. Благодаря этому возможна организация стека, растущего вверх или вниз, причём SP может указывать как на последнее использованное в стеке слово, так и на первое ещё не использованное. Более того, технически в качестве указателя стека можно использовать любой из регистров общего назначения, кроме PC. Это облегчается тем обстоятельством, что прерывания и вызовы подпрограмм не используют стек, сохраняя адрес возврата в регистре LR, а состояние прерванной программы — в регистре SPSR.

В системе команд Thumb, напротив, имеются специальные команды POP и PUSH, использующие SP как указатель стека. Стек растёт вниз, а значение SP указывает на последнее помещённое в него слово.

Использование SP в 16-разрядных командах обработки данных очень ограничено. В 32-разрядных командах во многих случаях применение SP в качестве приёмника результата запрещено (в аналогичных командах набора ARM он может использоваться свободно).

Когда SP используется по прямому назначению, он должен содержать значение, кратное 4, поскольку обращение к стеку выполняется словами. В некоторых версиях архитектуры, например, в ARMv7-M, при записи в SP два младших разряда принудительно сбрасываются. Однако, если нужна гарантия переносимости кода между разными версиями архитектуры, программист должен сам гарантировать, что помещаемые в SP значения никогда не будут содержать единиц в двух младших битах.

Регистр связи LR (R14) Править

Регистр LR (Link Register) используется в следующих случаях:

  • в инструкциях BL и BLX;
  • при выполнении прерываний.

Перечисленные выше команды применяются для вызова подпрограмм, при этом в LR помещается адрес инструкции, следующей за командой BL или BLX.

В случае возникновения исключения в процессорах A- и R-профилей в LR заносится значение PC, на 4 или 8 превосходящее адрес команды, выполняемой непосредственно перед исключением; подробнее об этом говорится в разделе «Обработка исключений в A- и R-профилях». В процессоре M-профиля при исключении в LR заносится специальный код, называемый в документации EXC_RETURN и определяющий, как необходимо выполнять возврат из обработчика данного исключения. Подробнее об этом сказано в разделе «Обработка исключений в M-профиле».

Стандартные соглашения о связях Править

Хотя при создании своей ОС программист волен определять собственные соглашения о связях и правила использования регистров, есть смысл придерживаться правил, разработанных компанией ARM и поддерживаемых всеми популярными трансляторами для этой архитектуры. Вкратце они заключаются в следующем:

  • В качестве указателя стека всегда используется регистр SP (R13). Стек растёт вниз, SP указывает на последнее используемое слово. Эти правила полностью соответствуют аппаратным требованиям набора команд Thumb.
  • Для передачи параметров в вызываемую подпрограмму могут использоваться регистры R0–R3. Если необходимо передать параметр, по размерам превышающий слово, при использовании обычного порядка слов «младший–старший» младшее слово помещается в регистр с меньшим номером; при использовании порядка «старший–младший» — в регистр со старшим номером. Если параметров слишком много, дополнительные параметры передаются через стек. Кроме того, при наличии арифметического сопроцессора для передачи параметров могут использоваться его регистры, но их использование здесь не обсуждается.
  • Возврат результатов осуществляется через регистры R0–R3.
  • Вызываемая подпрограмма обязана сохранять значения регистров R4–R11, а также корректно восстанавливать значение указателя стека.
  • Регистры R0–R3, R12 и LR, а также флаги регистра состояния вызываемой подпрограммой могут свободно изменяться.
  • Компоновщик при связывании вызовов подпрограмм может использовать регистр R12 в качестве рабочего, поэтому подпрограммы не могут рассчитывать на сохранность его содержимого, если используют вызовы подпрограмм из других модулей.
  • В ряде систем R7 хранит значение, зависящее от системы (например, адрес локальной памяти потока — TLS). В таких системах изменять этот регистр обычно запрещается.

Указатель стека сам по себе всегда должен быть выровнен на границу слова. Тем не менее, в некоторых случаях требуется его выравнивание на границу двойного слова. Для контроля за соблюдением выравнивания на границу двойного слова объектные модули могут снабжаться специальными атрибутами, которые контролируются компоновщиком. Последний, в частности, не должен допускать вызова подпрограмм, расположенных в модуле, требующем выравнивания стека на границу двойного слова, из подпрограмм, относящихся к модулю, обеспечивающему выравнивание лишь на границу слова. Компиляторы языков высокого уровня обычно снабжают свои файлы соответствующими атрибутами сами; при программировании на языке ассемблера это является задачей программиста. Например, транслятор ассемблера фирмы KEIL имеет для этого директивы PRESERVE8 (модуль обеспечивает выравнивание стека на границу двойного слова) и REQUIRE8 (модуль требует выравнивания стека на границу двойного слова).

Обнаружено использование расширения AdBlock.


Викия — это свободный ресурс, который существует и развивается за счёт рекламы. Для блокирующих рекламу пользователей мы предоставляем модифицированную версию сайта.

Викия не будет доступна для последующих модификаций. Если вы желаете продолжать работать со страницей, то, пожалуйста, отключите расширение для блокировки рекламы.