/ / Извикване на функция C от събрание - превключване на конвенцията за обаждания - c, assembly, linux-kernel, nasm

Извикване на функция С от събрание - превключване на конвенцията за обаждания - c, assembly, linux-kernel, nasm

Имам монтажна програма за 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 за всичките ви други функции, не виждам причина да не искате да промените това за една конкретна функция.