Какие регистры должны быть сохранены функцией x86?

Я пишу функцию в сборке x86, которая должна вызываться из кода c, и мне интересно, какие регистры мне нужно восстановить, прежде чем я вернусь к вызывающей стороне.

В настоящее время я только восстанавливаю esp а также ebpв то время как возвращаемое значение находится в eax,

Есть ли какие-либо другие регистры, о которых мне следует беспокоиться, или я могу оставить в них то, что мне нравится?

3 ответа

Решение

Используя 32-битный ABI Microsoft (cdecl или же stdcall или другие соглашения о вызовах), EAX, EDX а также ECX являются скретч-регистрами (вызов закрыт). Другие целочисленные регистры общего назначения сохраняются при вызове.

Коды условий в EFLAGS являются замкнутыми. DF=0 требуется при звонке / возврате, чтобы вы могли использовать rep movsb без cld первый. Стек x87 должен быть пустым при вызове или при возврате из функции, которая не возвращает значение FP. (Возвращаемые значения FP входят в st0, с незаполненным стеком x87.) XMM6 и 7 сохраняются при вызове, остальные - это незаполненные регистры.

За пределами Windows большинство 32-битных соглашений о вызовах (в том числе i386 System V в Linux) согласны с этим выбором EAX, EDX и ECX в качестве системного вызова, но все регистры xmm являются системным вызовом.


Для x64 под Windows вам нужно только восстановить RBX, RBP, RDI, RSI, R12, R13, R14, а также R15, XMM6..15 сохраняются при вызове. (И вам нужно зарезервировать 32 байта теневого пространства для использования вызываемой стороной, независимо от того, есть ли какие-либо аргументы, которые не помещаются в регистрах.) Xmm6..15 сохраняются вызовом.
См. https://en.wikipedia.org/wiki/X86_calling_conventions для получения дополнительной информации.

Другие операционные системы используют x86-64 System V ABI (см. Рисунок 3.4), где целочисленные регистры с сохранением вызовов RBP, RBX, RSP, R12, R13, R14, а также R15, Все регистры XMM/YMM/ZMM являются замкнутыми.

EFLAGS и стек x87 такие же, как и в 32-разрядных соглашениях: DF=0, флаги условий помечены, а стек x87 пуст. (Соглашения x86-64 возвращают значения FP в XMM0, поэтому регистры стека x87 всегда должны быть пустыми при вызове / возврате.)


Ссылки на официальные документы по соглашениям о вызовах см. На https://stackru.com/tags/x86/info.

32-bit: EBX, ESI, EDI, EBP
64-bit Windows: RBX, RSI, RDI, RBP, R12-R15, XMM6-XMM15
64-bit Linux,BSD,Mac: RBX, RBP, R12-R15

Подробнее см. " Ресурсы по оптимизации программного обеспечения " от Agner Fog. Соглашения о вызовах описаны в этом файле PDF.

Если вы не уверены в ситуации с регистрами, приведенные ниже инструкции могут легко спасти день.

PUSHA/PUSHAD - Нажмите все общие регистры
POPA/POPAD - Pop все общие регистры

Эти инструкции выдвигают и выдвигают регистры общего назначения и регистры SI/ESI, DI/EDI в определенном порядке.

Порядок инструкций PUSHA/PUSHAD следующий.

Opcode  Instruction  Clocks   Description

60      PUSHA        18       Push AX, CX, DX, BX, original SP, BP, SI, and DI
60      PUSHAD       18       Push EAX, ECX, EDX, EBX, original ESP, EBP ESI, and EDI

И порядок для инструкции POPA / POPAD выглядит следующим образом. (в обратном порядке)

Opcode   Instruction   Clocks   Description

61       POPA          24       Pop DI, SI, BP, SP, BX, DX, CX, and AX
61       POPAD         24       Pop EDI, ESI, EBP, ESP(***),EBX, EDX, ECX, and EAX

*** Значение ESP сбрасывается, а не загружается в ESP.

Другие вопросы по тегам