Как стать автором
Обновить

Комментарии 31

Шикарно! Всё разъяснили. Как раз перехожу на 64 бита при написании программ, очень хороший ликбез!
размер большинства типов (char, short, int, float) в языке Си/Си++ остался прежним на 64-битных системах


После этой фразы становится ясно, что автор имеет в виду ровно один компилятор, в ровно одной конфигурации, а «64-битной системой» называет ровно одну архитектуру. В gcc и llvm, например, размер int будет регулироваться настройками при сборке. Про различные calling conventions (передачу через регистры vs стек) в разных ОС и на разных архитектурах — почему-то вообще умолчали…
Цитирую. «И еще хочу сразу заметить, что статья посвящена языку Си/Си++ и среде разработки Visual Studio.»

Но в целом, хотелось бы, конечно, и про другие компиляторы и архитектуры услышать.
А еще там есть в хабракате «Различия в использовании стека Win32 и Win64 приложениями». На картинку что ли про Windows пририсовать. :)
Собственно говоря, автор в первом же абзаце честно пишет "… статья посвящена языку Си/Си++ и среде разработки Visual Studio 2010" так что к чему данный упрек?
> Хотя аргументы могут быть переданы в регистрах, компилятор все равно резервирует для них место в стеке, уменьшая значение регистра RSP (указателя стека).

Заменяем слово «компилятор» на Visual Studio и получаем правдивое предложение.

> Компилятор использует при вызове данной функции 48 байт.

gcc использует 24. Ха-ха.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Страница — 4K (в x86 без large pages). 16 байт — параграф.
НЛО прилетело и опубликовало эту надпись здесь
Маленькое уточнение — такое поведение следствие MS ABI. Но, например, на Linux используется AMD ABI, там через регистры передается до 6 параметров и нет необходимости резервировать в стеке место под те параметры, которые переданы в регистрах.
Ведь если параметры передаются через стек — код функции короткий и нет необходимости сохранять аргументы в памяти (стеке),


..«передаются через регистры», наверное?

Спасибо, очень интересно.
«Ведь если параметры передаются через стек — код функции короткий и нет необходимости сохранять аргументы в памяти (стеке), а количество используемой функцией стековой памяти сокращается. „
Наверное Вы все же имели ввиду
“Ведь если параметры передаются через РЕГИСТРЫ — код функции короткий и нет необходимости сохранять аргументы в памяти (стеке), а количество используемой функцией стековой памяти сокращается. „
Спасибо. Переписал предложение.
Меня, конечно, заминусуют, но я таки напишу.
В этой статье, помимо нюансов выделения памяти в стеке, мне понравился один момент — отказ в Win64 от различных типов соглашений о вызове ( stdcall, cdecl, fastcall, thiscall и так далее ) в пользу одного (модифицированого fastcall). Вот взял Microsoft и решил, что эта неразбериха с кучей стандартов мешает — и отказался от неё в пользу одного четкого решения. Пошел на риск обратной несовместимости, обязал программеров лишний раз подумать. Ради нового лучшено стандарта, ради улучшения качества кода в будущем.

Вы можете хотя бы теоретически представить, что подобный шаг когда-либо будет сделан в Линуксе? Да ни в жизни! Найдется куча сторонников каждого типа вызовов! Каждый будет отстаивать свою точку зрения, хвалить своё болото. Все компиляторы и языки программирования будут вынуждены поддерживать все типы вызовов. Ради поддержки старого кода невозможно будет выкинуть это из ядра. Если даже какой-нибудь дистрибутив невероятной джедайской силой воли ведущего разработчика перейдет на единое соглашение — тут же возникнет несколько форков и группа разработчиков разбежится по этим форкам в равных пропорциях.

Это я все к чему? Майкрософт, имея сравнительно немного людей, работающих над операционкой (ну пусть пару десятков тысяч) определяет вектор развития на годы вперед, не боится отказываться от старого, задавать стандарты и говорить: «если Вы это не поддерживаете — Вам нет места под нашей операционкой». Линукс так не может. Под его крышей есть место всем. Это конечно хорошо, с одной стороны, но с другой — багаж обратной совместимости давит все сильней, приходится тянуть за собой кучу старого кода, поддерживать массу дистрибутивув, версий ядра и отдельных программ и т.д. И в итоге, сообщество Линукс, имея миллионы пользователей (львиная доля которых — программисты и администраторы) не может похвастаться столь решительными шагами в какую-либо сторону прогресса.

Да, поддержка всяких новых фич в Линуксе появляется раньше Винды, делаются успешные демки и в фич-листе гордо ставиться галочка «поддерживается». Но стандартом это не становиться, каждый придумывает свой велосипед, пользуется фичей 2% от всех линукс-пользователей и она либо умирает в муках, либо как-то развивается, но значительно медленее, чем в 5 раз худшая изначально фича от Майкрософта, вошедшая в Винду и используемая сотнями миллионов людей ежедневно.
«Вы можете хотя бы теоретически представить, что подобный шаг когда-либо будет сделан в Линуксе? Да ни в жизни!»
Это бездоказательный наезд!
очень даже основательный ибо в линуксе ничего не может быть запрещено всем сообществом, поэтому запрет использования других соглашений не состоится
помоему ядром все еще плотно занимается товарищ Линус, думаю его послушаются многие, так что — безосновательно заявляете
Вроде в amd64 в linux тоже один тип вызова, не? Наоборот для amd64 в Microsoft выпендрились и не стали использовать универсальное соглашение о вызовах, а изобрели свой велосипед.
«А нельзя ли выкинуть труп петуха, традиционно замурованного в левую пассажирскую дверцу»? Убогие, тупые твари, чтоб им в аду сгореть.… Петух, етить, — это вообще история. Он нужен для совместимости с версией одна тысяча двадцать седьмого года. Не могут историю, блин, изучить, а рассуждать лезут. Ламерьё.
© баян о покупке автомобиля
Насчёт обратной совместимости есть одна штука, которой я не могу никак понять.
В своё время в ранних процах x86 архитектур были введены «продвинутые» команды типа movsb, pusha и т.п., которые представляли собой просто аппаратное совмещение команд «поменьше-попроще». Служило всё это для ускорения выполнения прог.

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

Вот, бл*, почему он не "… Пошел на риск обратной несовместимости, обязал программеров лишний раз подумать. Ради нового лучшено стандарта, ради улучшения качества кода в будущем"???

P.S. Нынче в той конторе модно херачить каждый раз новую цоколёвку проца при изменении «чего-то там у него внутри». А давеча они даже изменили количество ног у процов соседних линеек на одну!
Вы неправы. Они пошли на это! И создали Itanium с архитектурой IA-64. Выбросили все устаревшее и вообще сделали хорошо. И именно этой архитектуре пророчили будущее и именно по этому не хотели затем признавать x86-64 за полноценного приемника x86.

Вот жаль только что не получилось. Совместимость для разработчиков и пользователей стала уже гораздо дороже всего остального.
>если Вы это не поддерживаете — Вам нет места под нашей операционкой

Под операционкой я остался как одной из используемых, а вот их систем программирования стараюсь избегать. Если у них хватает наглости плевать на программистов, то пусть, есть иные решения.
Мне не понятно почему было решено выбрать именно 4 регистра и именно эти (допустим про RCX понятно)? почему нельзя было для параметров использовать регистры от R15 и вниз до нужного количества параметров, и сделать одну команду которая выгрузит на стек их все вместе (pusha )? почему параметры с плавающей запятой только 4 почему не все 8 (или просто все регистры сопроцессора)…
И если подумать, то окажется что fastcall подходит для функций которые не вызывают другие функции, иначе сохранение параметров ест весь профит… и как я понимаю если вызвать из одной функции несколько других то параметры будут многократно сохраняться и восстанавливаться?
Я за одно универсальное решение, но я против плохо обдуманных решений…
>> Мне не понятно почему было решено выбрать именно 4 регистра
Эвристика, вероятно подкрепленная некоей статистикой.

x86 — 2 регистра из 8 (fastcall)
68k (gcc) — 4 из 16 (на Amiga более гибко)
ARM — 4 из 16
x86-64 — 4 из 16
Power/PPC — 8 из 32
Sparc — 8 из 32

наблюдается очевидная закономерность, из которой выбиваются только

MIPS — 4 из 32
CELL SPU — 72 из 128

>> почему нельзя было для параметров использовать регистры от R15 и вниз до нужного количества параметров

Команды с r8..r15 длинее на 1 байт

>> сделать одну команду которая выгрузит на стек их все вместе

Это очень олдскульно.
Сделать одну команду можно, как сделано в 68k или ARM, только геморно.
push-ы на OoO x86 ренеймятся и выполняются независимо друг от друга.
На том же 68040 отдельные операции move были быстрее 1 жирной movem, которая по маске сохраняет любую комбинацию регистров.
>> Смысл использования такого неэкономного механизма я не уловил. Что-то говорится про унификацию и упрощение отладки

printf("%d %d %d %d %d", 1, 2, 3, 4, 5);
и т.п.

Прошу развить мысль. Вновь не улавливаю. :(

Вот есть:
void Foo1(int a, int b, int c);

void Foo2(int a, int b, int c)
{
  Foo1(a, b, c);
  // a, b, c - больше не используем
  . . .
}


В данном случае в стек переменные не сохраняем, но место резервируем. Зачем? Что это дает?
В упомянутом мною случае будет цикл по памяти от &arg[1] до &arg[5]
поэтому аргументы они должны лежать в памяти.

В отладочном режиме агрументы также будут лежать в памяти чтобы их смотреть
в отладчике.

В релизном режиме для одних функций это нужно, для других не нужно.
Естественно желание унифицировать всё это безобразие.
Не вижу ничего страшного в 40 байтовом стеке.

У Sparc и PPC стековый фрейм начинается от сотни байт и никого это вообще не волнует
По PPC ABI резервируется место под 8 64 битных аргументов + 6 дополнительных 64битных полей для разных указателей.
Размер структуры 'S' из-за изменений правил выравнивания и изменения размера члена 'b' вырастет с 12 до 24 байт при перекомпиляции в 64-битном режиме. Структура передается в функцию по значению
А как же http://msdn.microsoft.com/ru-ru/library/ms235286.aspx
Любые аргументы, не равные 8 байтам или 1, 2, 4 или 8 байтам, передаются по ссылке. Попыток разместить один аргумент по нескольким регистрам не происходит.
?
Неожиданный некрокомментарий :). Я уже даже не помню, про что писал в этой статье. Прошу провести самостоятельный эксперимент с Visual Studio и потом привести результаты и теоретическое обоснование.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий