GCC не сохраняет / не восстанавливает зарезервированные регистры при вызовах функций

У меня есть сценарий в GCC, вызывающий у меня проблемы. Я получаю не то поведение, которого я ожидаю. Подводя итог ситуации, я предлагаю несколько новых инструкций для x86-64, которые реализованы в симуляторе оборудования. Чтобы протестировать эти инструкции, я беру существующий исходный код C и вручную кодирую новые инструкции с использованием шестнадцатеричного числа. Поскольку эти инструкции взаимодействуют с существующими регистрами x86-64, я использую списки ввода / вывода / закрытия для объявления зависимостей для GCC.

Что происходит, так это то, что если я вызываю функцию, например printf зависимые регистры не сохраняются и не восстанавливаются.

Например

register unsigned long r9  asm ("r9")  = 101;
printf("foo %s\n", "bar");
asm volatile (".byte 0x00, 0x00, 0x00, 0x00" : /* no output */ : "q" (r9) );

101 был назначен на r9, а встроенная сборка (в данном примере - подделка) зависит от r9. Это работает правильно при отсутствии printf, но когда он есть, GCC не сохраняет и не восстанавливает r9, и к моменту вызова моей пользовательской инструкции существует другое значение.

Я подумал, что, возможно, GCC мог тайно изменить присвоение переменной r9, но когда я это сделаю

asm volatile (".byte %0" : /* no output */ : "q" (r9) );

и посмотрите на вывод сборки, он действительно использует% r9.

Я использую gcc 4.4.5. Как вы думаете, что может происходить? Я думал, что GCC всегда будет сохранять и восстанавливать регистры при вызове функций. Есть ли способ добиться его соблюдения?

Спасибо!

РЕДАКТИРОВАТЬ: Кстати, я компилирую программу вот так

gcc -static -m64 -mmmx -msse -msse2 -O0 test.c -o test

person hayesti    schedule 28.07.2011    source источник


Ответы (2)


В разделе 3.2.1 ABI говорится:

Регистры% rbp,% rbx и от% r12 до% r15 «принадлежат» вызывающей функции, и вызываемая функция требуется для сохранения их значений. Другими словами, вызываемая функция должна сохранять значения этих регистров для вызывающей стороны. Остальные регистры «принадлежат» вызываемой функции. Если вызывающая функция хочет сохранить такое значение регистра при вызове функции, она должна сохранить это значение в своем локальном стековом фрейме.

поэтому не следует ожидать, что регистры, отличные от% rbp,% rbx и от% r12 до% r15, будут сохранены вызовом функции.

person AProgrammer    schedule 28.07.2011
comment
Спасибо за ясность, я не знал об этом. В качестве последующего вопроса: существует ли простой (однострочный) способ запросить сохранение пользовательского набора регистров перед printf и восстановление после printf? - person hayesti; 28.07.2011

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

person R.. GitHub STOP HELPING ICE    schedule 28.07.2011
comment
Спасибо, я даже не знал, что есть сохраненные регистры вызывающего / вызывающего абонента! - person hayesti; 28.07.2011