Информация

Дата основания
Местоположение
США
Сайт
www.intel.ru
Численность
5 001–10 000 человек
Дата регистрации

Блог на Хабре

Обновить
Комментарии 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. Ха-ха.
А сколько в аналогичном использует gcc в 32 битной системе?
Мне казалось что 16, из-за выравнивания на границе страницы памяти, но это так, теория, на практике не проверял.
Страница — 4K (в x86 без large pages). 16 байт — параграф.
> Заменяем слово «компилятор» на Visual Studio и получаем правдивое предложение

Согласен, я бы даже в теги его добавил — как и слово windows )
Маленькое уточнение — такое поведение следствие 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 и потом привести результаты и теоретическое обоснование.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.