2017-01-19 2 views
0

У меня есть приложение для сборки для Linux x64, где я передаю аргументы функциям через регистры, поэтому я использую определенное определенное соглашение о вызове, в данном случае fastcall. Теперь я хочу вызвать функцию C из приложения сборки, которое, скажем, ожидает 10 аргументов. Должен ли я переключиться на cdecl для этого и передать аргументы через стек, независимо от того, что во всем остальном в моем приложении я передаю их через регистры? Разрешено ли смешивать вызовы в одном приложении?Вызов функции C из сборки - вызов вызова вызова

+2

Вы читали [спецификацию ABI] (http://refspecs.linuxfoundation.org/elf/x86-64-abi-0.99.pdf)? В нем говорится, как работать с функциями, которые принимают больше аргументов, чем доступные регистры. – fuz

ответ

2

Я полагаю, что азЬсаИ, вы имеете в виду соглашение amd64 вызова, используемую SysV ABI (то есть то, что использует Linux), где первые аргументы передаются в rdi, rsi и rdx.

ABI немного сложный, следующее упрощение. Возможно, вы захотите прочитать the specification.

Вообще говоря, первые несколько (Левые) целое число или указатель аргументы помещаются в регистры 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 на стеке.

+0

спасибо, но я использую nasm, а не газ. – Kooiomo

+0

@Kooiomo У вас возникли проблемы с пониманием синтаксиса газа? Если это так, я могу перевести примеры для вас. – fuz

+0

нет .............. – Kooiomo

2

Да, конечно. Соглашение о вызове применяется для каждой функции. Это совершенно применимое приложение:

int __stdcall func1() 
{ 
    return(1); 
} 

int __fastcall func2() 
{ 
    return(2); 
} 

int __cdecl main(void) 
{ 
    func1(); 
    func2(); 

    return(0); 
} 
+0

, если я беру 'getnameinfo' из C, мне нужно передать ** все ** аргументы через стек ему при вызове с Assembly? или мне разрешено передавать часть из них через регистры и часть через стек? или все аргументы через регистры? – Kooiomo

+0

@Kooiomo См. Мой ответ. – fuz

+0

@fuz, это точно не отвечает на мои 3 вопроса. – Kooiomo

-1

Вы можете, но вам не нужно.

__attribute__((fastcall)) только запрашивает первые два параметра, которые должны быть переданы в регистры - все остальное будет автоматически передаваться в стек, как с cdecl. Это делается для того, чтобы не ограничивать количество параметров, которые могут быть заданы для функции, путем выбора определенного соглашения о вызове.

В вашем примере с 10 параметрами для функции, вызываемой с помощью соглашения о вызове fastcall, первые два параметра будут передаваться в регистры, остальные 8 - автоматически в стеке, как и при стандартном соглашении о вызове.

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

+0

1) не eax, а rax. 2) почему? существуют регистры r1-r10 для x64 Linux. – Kooiomo

+0

ОП указана x64, 'fastcall' не стандартизирован, и ваш пример - это реализация MS, а не Sys V, которая будет использовать как минимум RDI и RSI в качестве первого и второго аргументов. –

Смежные вопросы