Использование 4-битного регистра PowerPC CR0 от GCC - PullRequest
0 голосов
/ 25 мая 2018

Я хочу создать функции, которые сохраняют / восстанавливают состояние регистров процессора через компилятор GCC.В PowerPC это 8 условных 4-битных регистров ('cr0' - 'cr7'), я хочу получить их значения и сохранить их в памяти.Мое решение (которое не работает):

register int cr0 __asm__("cr0");

Это работает с регистрами общего назначения ('r1' - 'r30'), после того как регистр определен, так что его можно использовать любым способом.Но при компиляции приведенного выше кода происходит сбой со следующей ошибкой:

hello.c: In function ‘foo’:
hello.c:58:22: error: register specified for ‘cr0’ isn’t suitable for data type
         register int cr0 __asm__("cr0");

Я предполагаю, что проблема в том, что регистр cr0 имеет ширину 4 бита, поэтому его нельзя поместить в 32-битную переменную int.(16 и 8 бит тоже не удалось)

Как решить эту проблему?Есть ли обходной путь с 4-битными целыми числами в GCC?Или как обратиться к полному cr 32-битному регистру, а не только к его частям?

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Я хочу создать функции, которые сохраняют / восстанавливают состояние регистров ЦП с помощью компилятора GCC.

Register- asm локальные переменные для этой цели бесполезны.

Они гарантированно находятся в указанном регистре, только если он используется в качестве операнда для оператора расширенного asm ( gcc manual ).Это позволяет компилятору разливать / перезагружать регистр через вызовы функций, если это необходимо.

Что более важно для вашего случая, присвоение нового значения локальной переменной register-asm внутри функции приведет к сохранению / восстановлению компиляторомзначение вызывающего абонента в функции пролог / эпилог.См. этот пример в проводнике компилятора Godbolt :

int call_clobbered(int x) {
    register int a asm("r2") = 123;
    asm("" :: "r"(a)); // force the compiler to have the value in the register
    return a;
}

   # gcc4.8.5 -O3 -mregnames
    li %r2,123
    li %r3,123      # return-value register
    blr


int call_preserved(int x) {
    register int a asm("r22") = 123;
    asm("" :: "r"(a)); // force the compiler to have the value in the register
    return a;
}

   # gcc4.8.5 -O3 -mregnames
    stwu %r1,-48(%r1)
    stw %r22,8(%r1)     # save caller's r22
    li %r22,123
    li %r3,123
    lwz %r22,8(%r1)     # restore caller's r22
    addi %r1,%r1,48     # deallocate stack space
    blr

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

Кроме того, вы все равно не хотите сохранять / восстанавливать все 8 полубайтов CR отдельно!Сохраните весь 32-битный регистр как обычный человек.Или, что еще лучше, сделайте вашу функцию переключения контекста реальной функцией, вызываемой сгенерированным компилятором кодом, чтобы вам не приходилось сохранять / восстанавливать регистры с закрытыми вызовами.(Поскольку компилятор ожидает, что ваша функция затрет все эти регистры, прежде чем он вернется.)

Я не знаю соглашений о вызовах PowerPC, но я предполагаю, что весь CR - это вызовзатерт.На ISA с одним регистром FLAGS / код состояния он всегда перекрывается при вызове.


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

Чтобы сохранить / восстановить весь CR, см. этот краткий справочник ISA PPC .

Использование mfcr r1 ( перейти от CR ), чтобы скопировать все 32 бита в целочисленный регистр (который затем можно сохранить в памяти).Используйте mtcr r1 до и переходите к CR при восстановлении.Работает с любым регистром;r1 это просто пример.

0 голосов
/ 25 мая 2018

Расширение gcc register int cr0 __asm__("cr0"); используется для назначения специального регистра для переменной C (локальной или даже глобальной).Его нельзя использовать для ваших целей, потому что указанный вами регистр действительно не подходит для хранения значений типа int.Существуют и другие ограничения на набор регистров, которые можно использовать таким образом, это не универсальный способ сохранения значений регистров.

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

...