Windows 64 ABI, правильное использование регистра, если я НЕ вызываю Windows API?

Как мне подсказали в другом вопросе, я проверил Windows ABI, и я немного запутался в том, что я могу и не могу делать, если сам не вызываю Windows API.

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

При проверке регистрационной информации в ABI по адресу https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx

Я немного запутался в том, что относится ко мне, если я

1) Не вызывать Windows API из кода ASM

2) Не возвращайте значение и принимайте единственный параметр.

Вот что я понимаю, все ли я правильно понимаю?

RAX: я могу перезаписать это без сохранения, так как функция не ожидает возвращаемого значения

RCX: мне нужно сохранить это, так как именно здесь будет передан единственный параметр int, тогда я могу перезаписать его, а не восстановить

RDX/R8/R9: Не следует инициализировать, так как в моем методе нет таких параметров, я могу перезаписать их и не восстанавливать их

R10/R11: я могу перезаписать их, не сохраняя их, если вызывающему абоненту это нужно, он отвечает за их сохранение

R12/R13/R14/R15/RDI/RSI/RBX: я могу перезаписать их, но сначала мне нужно сохранить их (или я могу просто не сохранять их, если я не вызываю Windows API?)

RBP / RSP: Я полагаю, я не должен их трогать?

Если да, то я прав, что это правильный способ справиться с этим (если меня не волнует время, затрачиваемое на сохранение данных, и нужно как можно больше доступных регистров)? Или есть способ использовать еще больше регистров?

; save required registers

push r12
push r13
push r14
push r15
push rdi
push rsi
push rbx

; my own array processing code here, using rax as the memory address passed as the first parameter
; safe to use rax rbx rcx rdx r8 r9 r10 r11 r12 r13 r14 r15 rdi rsi giving me 14 64bit registers
; 1 for the array address 13 for processing
; should not touch rbp rsp

; restore required registers


pop rbx
pop rsi
pop rdi
pop r15
pop r14
pop r13
pop r12

2 ответа

Решение

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

Вы можете свободно использовать RAX, RCX, RDX, R8, R9, R10 а также R11, Последние два должны сохраняться вызывающей стороной, если это необходимо, а не вашей функцией.

В большинстве случаев эти регистры (или их субрегистры, такие как EAX) достаточно для моих целей. Мне почти никогда не нужно больше.

Конечно, если какой-либо из них (например, RCX) содержат аргументы для вашей функции, это зависит от вас, чтобы сохранить их для себя, пока они вам нужны. Как вы это делаете, также зависит от вас. Но если ты push убедитесь, что есть соответствующий pop где-то.

Используйте эту страницу MSDN в качестве руководства.

TL;DR: если вам нужны регистры, помеченные как сохраненные, вставьте / вытолкните их в правильном порядке. С вашим кодом вы можете без проблем использовать упомянутые вами 14 регистров. Вы можете коснуться RBP, если сохраните его, но не касайтесь RSP в принципе никогда.

Это имеет значение, если вы называете Windows API, но не так, как я предполагаю. ABI говорит, что регистры вы должны сохранить. Информация о сохранении означает, что вызывающий абонент знает, что существуют регистры, которые вы не измените. Вам не нужно вызывать какие-либо функции Windows API для этого требования.

Идея в качестве аналога (да, я знаю...): Вот пять разноцветных стопок заметок. Вы можете использовать любой из них, но если вам нужен красный или синий, можете ли вы сохранить верхний в безопасном месте и положить его обратно, когда вы остановитесь, так как мне нужны номера телефонов на них. Что касается других цветов, мне все равно, они были просто бумажкой, и я написал информацию в другом месте.

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

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

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

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