Перейти к содержанию
    

Возврат структуры из функции

Компилатор формирует при вызове функции место в стеке и передает адрес на эту область в функцию. В самой функции структура - локальная переменная (в стеке). Для возвращения структуры компилятор копирует поля локальной структуры по тому адресу, который предоставила функция. По сути у функции есть еще один "невидимый" входной параметр - адрес для возврата.

Не смотрел в листинг, но сомневаюсь что компилятор что-то передаёт неявно в функцию (кроме указателя this член-функциям), так как соглашения вызова расписаны и там нет предусмотрено это. Да и незачем.

Если функция возвращает структуру, то она "сама об этом знает". И она знает, что вызывающая функция позаботилась о месте в стеке, и просто вычисляет адрес, исходя из SP в точке входа в функцию. Думаю так.

Вообще - это дефолтный способ передачи и возврата параметров в функцию - через стек. И только оптимизатор заменяет стек на входе и выходе функции на регистры (если может и это не запрещено опциями).

Так что компилятор в точке вызова функции по дефолту должен сперва сформировать стековый фрейм для возвращаемого значения (вне зависимости от его типа), а потом поместить в него входные аргументы вызова.

 

И ещё замечание: насколько я знаю, некоторые компиляторы (согласно соглашениям вызова) могут возвращать не в одном регистре, а в паре. Т.е. в IAR for ARM - если возвращаемое значение - long long, то используется

регистровая пара R0:R1, а не стек. То же самое и для структур - если размер структуры влезает в одну регистровую пару, то она будет возвращена через регистры (один R0 или пару R0:R1), а не через стек.

 

Вроде так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не смотрел в листинг, но сомневаюсь что компилятор что-то передаёт неявно в функцию

Вот неверующих-то развелось :) Вообще-то, это в документации на ABI прописано. Вот пример:

 

typedef struct {
  int a;
  int b;
  int c;
} T;

T my_func (int a)
{
  T v;

  v.a = a;
  v.b = ~a;
  v.c = -a;
  return v;
}

static T s;

void my_func1(int a)
{
  s = my_func(a);
}

 

а вот фрагмент вызова ф-ции:

 

; 30   : 
; 31   :   s = my_func(a);

    mov    eax, DWORD PTR _a$[ebp]
    push    eax
    lea    ecx, DWORD PTR $T792[ebp]
    push    ecx
    call    _my_func
    add    esp, 8
    mov    edx, DWORD PTR [eax]
    mov    DWORD PTR _s, edx
    mov    ecx, DWORD PTR [eax+4]
    mov    DWORD PTR _s+4, ecx
    mov    edx, DWORD PTR [eax+8]
    mov    DWORD PTR _s+8, edx

 

push eax - педерача параметра "a"

lea и push ecx - неявная передача указателя на область стека для возврата структуры

затем вызов функции, и копирование результата в статическую переменную.

 

А вот если бы структура состояла бы из двух int, а не трех - то все бы упростилось. Оба поля вернулись бы в edx:eax без стека и неявных указателей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не смотрел в листинг, но сомневаюсь что компилятор что-то передаёт неявно в функцию (кроме указателя this член-функциям), так как соглашения вызова расписаны и там нет предусмотрено это. Да и незачем.

В компиляторе VC 2005 в функцию передается на регистре адрес зарезервированный области. Возможно, в более поздних версиях и других компиляторах этого нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возможно, в более поздних версиях и других компиляторах этого нет.

Везде есть. Совместимость то по ABI у них полная.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А никто так и не делает. Возвращают данные, которые компилятор неявно копирует из локальной переменной в lvalue, указатель на который также неявно передается в ф-цию. То есть, возвращаются только данные.

 

Компилятор ничего подобного не делает, и никаких "неявных адресов возврата" в функцию не передается.

 

Функция находит свои параметры, локальные переменные и результат относительно указателя стека.

 

 

В компиляторе VC 2005 в функцию передается на регистре адрес зарезервированный области. Возможно, в более поздних версиях и других компиляторах этого нет.

Какой еще зарезервироавнной области? Что вы такое говорите? "С" calling convention никто не отменял и компилятор того что вы говорите просто не может делать. Я думаю вы неправильно поняли листинг.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Какой еще зарезервироавнной области? Что вы такое говорите? "С" calling convention никто не отменял и компилятор того что вы говорите просто не может делать. Я думаю вы неправильно поняли листинг.
Ох уж эти сказочники :rolleyes: 'Не может, не может', еще и "С" calling convention сюда приплели :biggrin:

Вот, выдержка из вашего любимого calling conversion (прямо с сайта MS)

On x86 plaftorms, all arguments are widened to 32 bits when they are passed.

Return values are also widened to 32 bits and returned in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair.

Larger structures are returned in the EAX register as pointers to hidden return structures. Parameters are pushed onto the stack from right to left. Structures that are not PODs will not be returned in registers.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...