Не возвращаемое значение в регистре 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 вместо. Затем возникает проблема сложных типов классов / структур, и в этом случае компилятор может решить оптимизировать возвращаемое значение и использовать дополнительный выходной параметр в стеке вызовов для передачи возвращаемого объекта по ссылке к звонящему.