Имам монтажна програма за Linux x64където аз препращам аргументи към функциите чрез регистрите, като по този начин използвам определена определена конвенция за обаждания, в този случай fastcall.Сега искам да се обадя на C функция от монтажното приложение който, да рече, очаква 10 аргумента. Трябва ли да превключа cdecl
за това и да мине аргументите чрез стека, независимо от факта, навсякъде другаде в моята кандидатура Аз ги преминавам през регистрите? Възможно ли е да се смесват свикване конвенции в едно приложение?
Отговори:
2 за отговор № 1Предполагам, че до fastcall, имате предвид конвенцията за извикване на amd64, използвана от SysV ABI (т.е. какво използва Linux), където се предават първите няколко аргумента rdi
, rsi
, и rdx
.
ABI е малко сложно, следното е опростяване. Може да искате да прочетете спецификацията за детайли.
Като цяло, първите няколко (най-ляво) цяло число или показалец аргументи се поставят в регистрите rdi
, rsi
, rdx
, rcx
, r8
, и r9
, Аргументите с плаваща точка се предават xmm0
да се xmm7
, Ако пространството на регистъра е изчерпано, допълнителните аргументи се предават през стека от дясно на ляво. Например, за да се обадим на функция с 10 целочислени аргумента:
foo(a, b, c, d, e, f, g, h, i, k);
ще ви трябва код така:
mov $a,%edi
mov $b,%esi
mov $c,%edx
mov $d,%ecx
mov $e,%r8d
mov $f,%r9d
push $k
push $i
push $h
push $g
call foo
add $32,%rsp
За вашия конкретен пример, на getnameinfo
:
int getnameinfo(
const struct sockaddr *sa,
socklen_t salen,
char *host,
size_t hostlen,
char *serv,
size_t servlen,
int flags);
Ще минеш sa
в rdi
, salen
в rsi
, host
в rdx
, hostlen
в rcx
, serv
в r8
, servlen
в r9
и flags
на стека.
2 за отговор № 2
Да разбира се. Конвенцията за обажданията се прилага на база функционалност. Това е напълно валидно приложение:
int __stdcall func1()
{
return(1);
}
int __fastcall func2()
{
return(2);
}
int __cdecl main(void)
{
func1();
func2();
return(0);
}
-1 за отговор № 3
Можете, но не е нужно.
__attribute__((fastcall))
иска само първите два параметъра да се предават в регистрите - всичко останало автоматично ще бъде предавано на стека, точно както при cdecl
, Това се прави, за да не се ограничи броят на параметрите, които могат да бъдат дадени на функция, като се избере определена конвенция за обаждания.
Във вашия пример с 10 параметъра за функция, която се нарича с fastcall
конвенцията за обаждания, първите два параметъра ще бъдат предадени в регистрите, а останалите 8 автоматично в стека, както при стандартните конвенции за обаждания.
Както сте избрали да използвате fastcall
за всичките ви други функции, не виждам причина да не искате да промените това за една конкретна функция.