Не возвращаемое значение в регистре EAX после вызова метода?
Я написал библиотеку подключения, которая проверяет таблицу импорта dll исполняемых файлов PE, чтобы создать библиотеку, которая позволяет изменять параметры и возвращаемые значения. У меня есть несколько вопросов о том, как возвращаемое значение передается функции.
Я узнал, что возвращаемое значение функции сохраняется в регистре аккумуляторе. Так всегда бывает? Если нет, то как компилятор знает, где искать результат функции?
Как насчет размера возвращаемого типа? Целое число легко поместится, но как насчет большей структуры? Резервирует ли вызывающий объект пространство стека, чтобы вызываемый им метод мог записать результат в стек?
4 ответов
это все конкретных вызовах.
для большинства соглашений о вызовах числа с плавающей запятой возвращаются либо в FPU-стеке, либо в регистрах XMM.
вызов функции, возвращающей структуру
some_struct foo(int arg1, int arg2);
some_struct s = foo(1, 2);
будет скомпилирован в некоторый эквивалент:
some_struct* foo(some_struct* ret_val, int arg1, int arg2);
some_struct s; // constructor isn't called
foo(&s, 1, 2); // constructor will be called in foo
редактировать: (добавлена информация)
просто для уточнения: это работает для всех структур и классов, даже когда sizeof(some_struct) <= 4
. Поэтому, если вы определяете небольшой полезный класс как ip4_type
С unsigned
поле и некоторые конструкторы / преобразователи в/trom unsigned
, in_addr
, char*
ему будет не хватать эффективности по сравнению с использованием raw unigned
значение.
Если функция становится встроенной, результат не сохраняется в eax, также если результаты передаются по ссылке / указателю, этот регистр не будет использоваться.
посмотрите, что происходит с функцией, которая возвращает двойные (на 32-битной машине)
double func(){
volatile double val=5.0;
return val;
}
int main(){
double val = func();
return 0;
}
двойники не в eax.
func():
pushq %rbp
movq %rsp, %rbp
movabsq 17315517961601024, %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, -24(%rbp)
movsd -24(%rbp), %xmm0
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
subq , %rsp
call func()
movsd %xmm0, -24(%rbp)
movq -24(%rbp), %rax
movq %rax, -8(%rbp)
movl , %eax
leave
ret
вы задаете вопросы об ABI (двоичном интерфейсе приложения). Это зависит от операционной системы. Тебе стоит поискать. Вы можете найти хорошую информацию и ссылки на другие документы по адресуhttp://en.wikipedia.org/wiki/X86_calling_conventions
чтобы ответить на ваш вопрос, да, насколько я знаю, все популярные операционные системы используют реестр для возврата результата.
Это действительно зависит от соглашения о вызовах, но, как правило,EAX
используется для 32-разрядных и меньших интегральных типов данных, значения с плавающей запятой, как правило, используют регистры FPU или MMX, а 64-разрядные интегральные типы, как правило, используют комбинацию EAX
и EDX
вместо. Затем возникает проблема сложных типов классов / структур, и в этом случае компилятор может решить оптимизировать возвращаемое значение и использовать дополнительный выходной параметр в стеке вызовов для передачи возвращаемого объекта по ссылке к звонящему.