Нет такой вещи, как «Abi64». Поскольку вы отметили вопрос MASM, мы можем догадаться, что вы используете платформу Windows, и, очевидно, «64» означает, что это 64-разрядный код, так что это существенно сужает возможности. Тем не менее, есть еще два общих соглашения о вызовах для 64-битного кода в Windows. Один из них - __vectorcall
, а другой - соглашение о назначении Microsoft x64 (тот, который изначально был изобретен, чтобы сделать все другие соглашения об использовании устаревшими, но has hell, а не).
Поскольку соглашение о назначении Microsoft x64 является наиболее распространенным, и в этом конкретном случае использование __vectorcall
ничего не изменит, я предполагаю, что это тот, который вы используете. И тогда требуемый код становится абсолютно тривиальным. Все, что вам нужно сделать, это перейти от f1
к f2
, так как стек будет настроен одинаково. Первые два параметра f1
- это два параметра, которые должны быть переданы в f2
, а возвращаемое значение f2
- это возвращаемое значение f1
. Поэтому:
f1:
rex_jmp r8 ; third parameter (pointer to f2) is passed in r8
Это не только тривиальное писать, но она является наиболее оптимальной реализации для обоих размеров и скорости.
Вы даже можете изменить параметры v1
или v2
заранее, если вы хотите, например:
f1:
inc ecx ; increment v1 (passed in ecx)
; multiply v2 (xmm1) by v1 (ecx)
movd xmm0, ecx
cvtdq2ps xmm0, xmm0
mulss xmm1, xmm0
rex_jmp r8 ; third parameter (pointer to f2) is passed in r8
В случае, если вы хотите сделать что-то более сложное, вот как это будет работать:
f1:
sub rsp, 40 ; allocate the required space on the stack
call r8 ; call f2 through the pointer, passed in r8
add rsp, 40 ; clean up the stack
ret
Обратите внимание, что вам не нужен код пролога/эпилога, который вы указали в вопросе, хотя это ничего не повредит, если вы решите включить его.
Однако, перетасовка параметров, которые вы делали в примере кода, показанного в вопросе, это неправильный! В соглашении о вызове Microsoft x64 первые до четырех целых аргументов передаются в регистры слева направо в RCX, RDX, R8 и R9. Все остальные целочисленные аргументы передаются в стек.Первые четыре значения с плавающей запятой также передаются в регистры слева направо в XMM0, XMM1, XMM2 и XMM3. Остальные передаются в стек, а также слишком большие для регистров структуры.
Странно, однако, что слоты «исправлены», поэтому можно использовать только 4 общих регистраных аргумента, даже если у вас есть сочетание целых и аргументов fp. Таким образом:
╔═══════════╦══════════════════════════╗
║ ║ TYPE ║
║ PARAMETER ╠═════════╦════════════════╣
║ ║ Integer ║ Floating-Point ║
╠═══════════╬═════════╬════════════════╣
║ First ║ RCX ║ XMM0 ║
╠═══════════╬═════════╬════════════════╣
║ Second ║ RDX ║ XMM1 ║
╠═══════════╬═════════╬════════════════╣
║ Third ║ R8 ║ XMM2 ║
╠═══════════╬═════════╬════════════════╣
║ Fourth ║ R9 ║ XMM3 ║
╠═══════════╬═════════╩════════════════╣
║ (rest) ║ on stack ║
╚═══════════╩══════════════════════════╝
Не имеет значения, что второй параметр является первым передаваемым значением с плавающей запятой. Он не входит в XMM0, потому что это первое значение с плавающей запятой, оно идет в XMM1, потому что это второй параметр и, следовательно, во втором «слоте». (Это отличается от the x86-64 System V ABI, где первые 6 целых args идут в регистры, есть или нет аргументы FP).
Дополнительная документация по передаче параметров Windows доступна here, включая примеры.
Что такое бинарный интерфейс приложения на платформе, на которой вы находитесь? Это определит, где находятся параметры и что такое соглашение о вызове. –
@ DavidHoelzer Abi64 – helloFromTheOtherSide
что это? Нет такого ABI. –