Что такое архитектура x86. Windows x64 или x86 - какой ставить? Пара слов о некоторых пикантных особенностях DDR и QDR протоколов


В наше время существует две самые популярные архитектуры процессоров. Это x86, которая была разработана еще 80х годах и используется в персональных компьютерах и ARM - более современная, которая позволяет сделать процессоры меньше и экономнее. Она используется в большинстве мобильных устройств или планшетов.

Обе архитектуры имеют свои плюсы и минусы, а также сферы применения, но есть и общие черты. Многие специалисты говорят, что за ARM будущее, но у нее остаются некоторые недостатки, которых нет в x86. В нашей сегодняшней статье мы рассмотрим чем архитектура arm отличается от x86. Рассмотрим принципиальные отличия ARM или x86, а также попытаемся определить что лучше.

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

На данный момент существуют два типа архитектур: CISC (Complex Instruction Set Computing) и RISC (Reduced Instruction Set Computing). Первая предполагает, что в процессоре будут реализованы инструкции на все случаи жизни, вторая, RISC - ставит перед разработчиками задачу создания процессора с набором минимально необходимых для работы команд. Инструкции RISC имеют меньший размер и более просты.

Архитектура x86

Архитектура процессора x86 была разработана в 1978 году и впервые появилась в процессорах компании Intel и относится к типу CISC. Ее название взято от модели первого процессора с этой архитектурой - Intel 8086. Со временем, за неимением лучшей альтернативы эту архитектуру начали поддерживать и другие производители процессоров, например, AMD. Сейчас она является стандартом для настольных компьютеров, ноутбуков, нетбуков, серверов и других подобных устройств. Но также иногда процессоры x86 применяются в планшетах, это довольно привычная практика.

Первый процессор Intel 8086 имел разрядность 16 бит, далее в 2000 годах вышел процессор 32 битной архитектуры, и еще позже появилась архитектура 64 бит. Мы подробно рассматривали в отдельной статье. За это время архитектура очень сильно развилась были добавлены новые наборы инструкций и расширения, которые позволяют очень сильно увеличить производительность работы процессора.

В x86 есть несколько существенных недостатков. Во-первых - это сложность команд, их запутанность, которая возникла из-за длинной истории развития. Во-вторых, такие процессоры потребляют слишком много энергии и из-за этого выделяют много теплоты. Инженеры x86 изначально пошли по пути получения максимальной производительности, а скорость требует ресурсов. Перед тем, как рассмотреть отличия arm x86, поговорим об архитектуре ARM.

Архитектура ARM

Эта архитектура была представлена чуть позже за x86 - в 1985 году. Она была разработана известной в Британии компанией Acorn, тогда эта архитектура называлась Arcon Risk Machine и принадлежала к типу RISC, но затем была выпущена ее улучшенная версия Advanted RISC Machine, которая сейчас и известна как ARM.

При разработке этой архитектуры инженеры ставили перед собой цель устранить все недостатки x86 и создать совершенно новую и максимально эффективную архитектуру. ARM чипы получили минимальное энергопотребление и низкую цену, но имели низкую производительность работы по сравнению с x86, поэтому изначально они не завоевали большой популярности на персональных компьютерах.

В отличие от x86, разработчики изначально пытались получить минимальные затраты на ресурсы, они имеют меньше инструкций процессора, меньше транзисторов, но и соответственно меньше всяких дополнительных возможностей. Но за последние годы производительность процессоров ARM улучшалась. Учитывая это, и низкое энергопотребление они начали очень широко применяться в мобильных устройствах, таких как планшеты и смартфоны.

Отличия ARM и x86

А теперь, когда мы рассмотрели историю развития этих архитектур и их принципиальные отличия, давайте сделаем подробное сравнение ARM и x86, по различным их характеристикам, чтобы определить что лучше и более точно понять в чем их разница.

Производство

Производство x86 vs arm отличается. Процессоры x86 производят только две компании Intel и AMD. Изначально эта была одна компания, но это совсем другая история. Право на выпуск таких процессоров есть только у этих компаний, а это значит, что и направлением развития инфраструктуры будут управлять только они.

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

Количество инструкций

Это главные различия архитектуры arm и x86. Процессоры x86 развивались стремительно, как более мощные и производительные. Разработчики добавили большое количество инструкций процессора, причем здесь есть не просто базовый набор, а достаточно много команд, без которых можно было бы обойтись. Изначально это делалось чтобы уменьшить объем памяти занимаемый программами на диске. Также было разработано много вариантов защит и виртуализаций, оптимизаций и многое другое. Все это требует дополнительных транзисторов и энергии.

ARM более прост. Здесь намного меньше инструкций процессора, только те, которые нужны операционной системе и реально используются. Если сравнивать x86, то там используется только 30% от всех возможных инструкций. Их проще выучить, если вы решили писать программы вручную, а также для их реализации нужно меньше транзисторов.

Потребление энергии

Из предыдущего пункта выплывает еще один вывод. Чем больше транзисторов на плате, тем больше ее площадь и потребление энергии, правильно и обратное.

Процессоры x86 потребляют намного больше энергии, чем ARM. Но на потребление энергии также влияет размер самого транзистора. Например, процессор Intel i7 потребляет 47 Ватт, а любой процессор ARM для смартфонов - не более 3 Ватт. Раньше выпускались платы с размером одного элемента 80 нм, затем Intel добилась уменьшения до 22 нм, а в этом году ученые получили возможность создать плату с размером элемента 1 нанометр. Это очень сильно уменьшит энергопотребление без потерь производительности.

За последние годы потребление энергии процессорами x86 очень сильно уменьшилось, например, новые процессоры Intel Haswell могут работать дольше от батареи. Сейчас разница arm vs x86 постепенно стирается.

Тепловыделение

Количество транзисторов влияет еще на один параметр - это выделение тепла. Современные устройства не могут преобразовывать всю энергию в эффективное действие, часть ее рассеивается в виде тепла. КПД плат одинаковый, а значит чем меньше транзисторов и чем меньше их размер - тем меньше тепла будет выделять процессор. Тут уже не возникает вопрос ARM или x86 будет выделять меньше теплоты.

Производительность процессоров

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

Выводы

В этой статье мы рассмотрели чем отличается ARM от x86. Отличия довольно серьезные. Но в последнее время грань между обоими архитектурами стирается. ARM процессоры становятся более производительными и быстрыми, а x86 благодаря уменьшению размера структурного элемента платы начинают потреблять меньше энергии и выделять меньше тепла. Уже можно встретить ARM процессор на серверах и в ноутбуках, а x86 на планшетах и в смартфонах.

А как вы относитесь к этим x86 и ARM? За какой технологией будущее по вашему мнению? Напишите в комментариях! Кстати, .

На завершение видео о развитии арихтектуры ARM:

Когда-то я очень путался, увидев в описании программ x86 или x64 и не мог понять, почему если для 64-битной указывают x64, то для 32-битной x86, а не x32. Последнее должно быть намного привычнее и логичнее, а x86 не то что бы не запомнить, логике эта цифра не поддаётся: математически 86 больше чем 64, а на деле оказывается меньше в два раза. Из чисел "x86 x64 x32" таким образом можно даже загадку сделать. А ведь на самом деле...

x86 равна x32, а также равна и x64

При всей этой путанице на деле оказывается всё просто и как всегда ошибка идет за теми авторами, кто пишет вместе связку x86 и x64. Это попросту неправильно, несмотря на то, что так пишут практически все.

Дело в том, что x86 - это архитектура микропроцессора и аппаратная платформа, которая применима к тридцати двух битным и к шестидесяти четырех битным программам. Название x86 получено от наименования первого процессора intel i8086 и ряда последующих, в которых в конце всегда приписывалась 86. Через какое-то время цифровые обозначения новых процессоров стали заменяться именами, так публика узнала о Pentium и Celeron, но платформа x86 не изменилась до наших дней.

Значения два, а обозначения три? x86, x32 и x64 - как правильно писать?

И если x86 это архитектура процессора, то x32 и x64 это его разрядность – адресное пространство, а также количество информации, которую процессор в силах обработать за один такт.

Когда же пишут о совместимости программ указывая разрядность x86, подразумевая 32-битную платформу, это неправильно и только вводит в заблуждение. Правильно указывать х86_32bit или х86_64bit. Либо сокращенно интуитивно понятные x32 или x64.

Так что можно подытожить: сейчас x86 указывают по старинке (даже Майкрософт этим грешит), когда эта платформа была в единственном числе и 64-битных еще никто не знал. При появлении платформы x64 её стали указывать как есть, а прежняя 32-битная так и осталась в большинстве случаев как x86. И сейчас это не актуально, ошибочно и сбивает с толку тех, кто не понимает суть. А вы её теперь понимаете. :)

x32 или x64? Что выбрать? Что лучше?

Очень часто возникает вопрос, выбрать операционную систему x32 или x64? То есть тридцати двух битную или шестидесяти четырех битную?
Это вопрос риторический, теоретический и спорный. Очевидно, что x64 лучше, но не всегда и не в случае, если вы пользуетесь Windows. Нет, любая Windows x64 работает чуть шустрее чем Windows x32, но только если есть все программы и все драйвера под 64-битную систему. Очень часто, если компьютер современный, все системные драйвера к комплектующим у него обычно есть. Но проблема кроется тогда в программах и особенно видео и аудио кодеках. Обязательно чего-то да не будет. И если тридцати двух битные программы могут работать в системе x64, то драйвера и кодеки к ней обязательно нужны тоже x64. Год от года эта проблема исчезает, но до сих пор она не развеяна полностью. С системами x32 таких проблем нет и для дома лучше выбирать именно такую.
p.s. до 2010 года действительно существовала дилемма выбора 32-битной или 64-битной операционной системы. Причины описаны абзацем выше. Прошло с тех пор пять лет и такой проблемы уже не наблюдается. Безусловно, лучше поставить 64-битную даже не задумываясь, если, конечно же, не существует каких-то особых важных причин в пользу 32-битности.

Всем доброго времени суток дорогие посетители блога айтишнега… У меня довольно часто интересуются — x86 это 32 или 64 битная Windows? Поддаваясь логике — можно предположить что x86 явно больше чем x64, но на практике оказывается что x86 равно x32… но тогда почему так пишут и кому надо ударить по голове, чтобы такой путаницы не было?

А теперь давайте я просто взорву вам мозг — x86 равно x32, и внимание, равна x64 — вы были к такому готовы? — думаю нет… теперь давайте разбираться что, как и куда! Чтобы ответить на этот не самый простой вопрос нам нужно вернуться на несколько десятилетий назад, именно оттуда и идет вся эта заварушка.

По голове надо настучать авторам, которые пишут в требованиях к компьютеру x86 и x64 в связке. Писать такое — грубая ошибка, но этим грешат все… x86 — это архитектура процессора, которая отлично себя чувствует и на 64 битных процессорах и на 32 битных! Маркировка x86 пошла от названия первого процессора от компании Intel i8086 и более новых моделей. Потом первые цифры менялись и сокращенно их объединяли x86 на конце модели — этакая линейка процессоров. Конечно же это было очень давно и процессоры маркируются совершенно по другому, но x86 прочно засела в документации и частенько вводит людей в путаницу… которые особо то не интересовались архитектурой процессоров и не вникали в историю их создания

x86 это 32 или 64 битная Windows?

x86 — это не разрядность, а архитектура… но как показала практика — x86 приравняли к 32 битной операционной системе. Если пренебречь всеми правилами, то можно сказать да, x86 равна 32 битной системе в большинстве случаев.

Правильный вариант обозначения выглядел бы примерно так для 32 разрядной операционной системы (OS_WINDOWS_x86_32bit) или так для 64 битной (OS_WINDOWS_x86_64bit) , но у нас все поперепутали!

Тут еще нюанс в том, что 32 битные процессоры уже очень и очень продолжительное время были единственными на рынке, и они были архитектуры x86… а когда вышли 64 разрядные — их стали обозначать x64, а для 32 биток оставили все как есть!

x32 или x64 — Что лучше?

В плане производительности конечно же 64 разрядная операционная система имеет явное преимущество, а вот 32 разрядная ОС очень ужата в ресурсах оперативной памяти. 32 битка не может адресовать более 4 гигабайт оперативной памяти, но по факту она видит не более 3,25 гигабайт из четырех! Однако некоторые приложения могут не запуститься на 64 битной WIndows — что и является сдерживающим фактором перехода но новую ОС.

x86-64 - 64-битное расширение для архитектуры x86, разработанное компанией AMD, позволяющее выполнять программы в 64-разрядном режиме.

История

Оригинальная спецификация разработана компанией AMD в 2000 г. Первым процессором, реализовавшим архитектуру, стал AMD K8 (выпущен в 2003 г.).

В те годы (конец девяностых и начало двухтысячных) компании HP и Intel разрабатывали свою 64-битную архитектуру IA-64 (Intel Itanium). Но она была кардинально другой, основана на принципе VLIW (very long instruction word), и была несовместима с 32-битной архитектурой x86. Из-за того, что огромная масса ранее написанного софта не работала на IA-64, этой архитектуре не удалось завоевать популярность. Хотя в конце 2001 года для IA-64 была выпущена специальная версия Windows XP 64-bit for IA-64.

Архитектура x86 ведёт свою историю с 1978 г., начиналась как 16-битная, в 1985 г. стала 32-битной. Архитектура обладает большим количеством костылей для обратной совместимости. Ей предрекали смерть вместе с 32-разрядыми вычислениями. Однако появление x86-64 дало ей новую жизнь.

Именование

Существует несколько вариантов названий этой технологии, которые иногда приводят к путанице.

  • x86-64 - первоначальный вариант. Именно под этим названием фирмой AMD была опубликована первая предварительная спецификация.
  • x64 - официальное название версий операционных систем Windows, также используемое как название архитектуры фирмами Microsoft и Oracle.
  • AMD64 - после выпуска первых процессоров Clawhammer и Sledgehammer в названии архитектуры появилось название фирмы-разработчика AMD. Сейчас является официальным для реализации AMD.
  • EM64T - первое официальное название реализации Intel. Расшифровывалось как Extended Memory 64 Technology.
  • Intel 64 - текущее официальное название архитектуры Intel.

Иногда упоминание AMD вводит пользователей в заблуждение, вплоть до того, что они отказываются использовать дистрибутивы родных версий операционной системы, мотивируя это тем, что на их процессоре Intel версия для AMD не будет работать. На самом деле распространители ПО используют название amd64 лишь потому, что именно AMD была пионером в разработке этой технологии.

Часто пользователи путают архитектуру x86-64 с IA-64. Во избежание подобных ошибок следует помнить, что Intel 64 и IA-64 - это совершенно разные, несовместимые между собой микропроцессорные архитектуры. В 2017 году вы вряд ли встретите где-либо процессор архитектуры IA-64 (Itanium).

Распространённость

Суперкомпьютеры

В списке суперкомпьютеров TOP-500 архитектура x86-64 вытеснила ранее популярные RISC-архитектуры и 32-битные версии. Intel пыталась продвигать свой Itanium (макс. доля достигнута в 2004 г.), но безуспешно.

Дата-центры

Servers using x86 chips still maintain a more than 90 percent market share. http://www.common.org/servers/x86-servers-data-center/

Во всех дата-центрах корпорации Google сейчас используются процессоры Intel с известной всем архитектурой x86. Тем не менее, корпорация Google планирует использовать и альтернативные решения. https://habrahabr.ru/company/ibm/blog/282820/

В 2017 году алгоритмы обработки больших объёмов информации в подавляющем большинстве случаев выполняются именно на архитектуре x86-64, поэтому мы и рассматриваем её в магистратуре АиСОБОИ.

Регистры

Архитектура x86-64 имеет:

  • 16 целочисленных 64-битных регистров общего назначения (RAX, RBX, RCX, RDX, RBP, RSI, RDI, RSP, R8 - R15);
  • 8 80-битных регистров с плавающей точкой (ST0 - ST7);
  • 8 64-битных регистров MMX (MM0 - MM7, имеют общее пространство с регистрами ST0 - ST7);
  • 16 128-битных регистров SSE (XMM0 - XMM15);
  • 64-битный указатель RIP и 64-битный регистр флагов RFLAGS.

Операции над 64-битными регистрами (сложение, вычитание и пр.) работают столько же времени, сколько операции над 32-битными регистрами.

Может показаться удивительным, но операции над младшими 32-битными половинами регистров обнуляют старшие 32 бита. Например,

mov eax, ebx

автоматически занулит старшие биты в rax.

Так сделано для оптимизации. Это позволяет процессору разрывать цепочки зависимостей (не надо ждать, пока посчитаются старшие биты, для продолжения операций с младшими, потому что старшие почти наверняка никому не будут нужны).

Современный процессор устроен очень сложно. Модель процессора, описанная в руководстве по архитектуре, плохо описывает реальный механизм работы современного ядра. В частности, понятие регистров процессора не соответствует действительности, «в железе» нет такой вещи, как регистр eax или rax. Понятие регистров процессора виртуализируется. Эта технология называется переименованием регистров (register renaming). Декодер команд выделяет регистр из большого банка регистров. Когда инструкция завершается, значение этого динамически распределенного регистра записывается обратно в любой регистр, в котором в настоящее время хранится значение, скажем, rax. Чтобы сделать эту работу эффективно и одновременно выполнять несколько инструкций, очень важно, чтобы операции не имели взаимозависимости. Плохо, когда значение регистра зависит от других инструкций.

Инструкции

x86-64 относится к типу CISC (complex instruction set computing). Является чуть ли не единственной современной CISC-архитектурой. Другие популярные архитектуры строятся по принципу RISC (reduced instruction set computer).

При этом современные х86-процессоры, хотя и CISC-совместимы, но являются процессорами с RISC-ядром, и в формальном смысле считаются гибридными. В таких гибридных CISC-процессорах CISC-инструкции преобразовываются в набор внутренних RISC-команд, при этом одна команда x86 может порождать несколько RISC-команд, исполнение команд происходит на суперскалярном конвейере одновременно по несколько штук. Небольшие инструкции легко выполнять одновременно.

Инструкции кодируются последовательностью байт переменной длины, на практике от 1 до 15 байт.

Ликвидированные возможности

В x86-64 по сравнению с x86 удалили некоторые устаревшие инструкции. Это двоично-десятичная арифметика BCD и инструкции типа aam (ASCII adjust for multiplication). Большая часть устаревших инструкций, тем не менее, оставлена.

Режимы

Процессоры данной архитектуры поддерживают два режима работы: Long mode («длинный» режим) и Legacy mode («унаследованный», режим совместимости с 32-битным x86).

Long mode

«Длинный» режим - «родной» для процессоров x86-64. Этот режим даёт возможность воспользоваться всеми дополнительными преимуществами, предоставляемыми архитектурой. Для использования этого режима необходима 64-битная операционная система.

Этот режим позволяет выполнять 64-битные программы; также (для обратной совместимости) предоставляется поддержка выполнения 32-битного кода, например, 32-битных приложений, хотя 32-битные программы не смогут использовать 64-битные системные библиотеки, и наоборот. Чтобы справиться с этой проблемой, большинство 64-разрядных операционных систем предоставляют два набора необходимых системных файлов: один - для родных 64-битных приложений, и другой - для 32-битных программ.

Legacy mode

Данный «унаследованный» режим позволяет процессору выполнять инструкции, рассчитанные для процессоров x86, и предоставляет полную совместимость с 32-битным кодом и операционными системами. В этом режиме процессор ведёт себя точно так же, как x86-процессор, например Athlon или Pentium III, и дополнительные функции, предоставляемые архитектурой x86-64 (например, дополнительные регистры), недоступны. В этом режиме 64-битные программы и операционные системы работать не будут.

Этот режим включает в себя подрежимы:

  • Реальный режим (real mode)
  • Защищённый режим (protected mode)
  • Режим виртуального 8086 (virtual 8086 mode)

Реальный режим использовался в MS-DOS, в реальном режиме выполнялся код BIOS при загрузке компьютера. Защищённый режим используется в 32-битных версиях современных многозадачных операционных систем. Режим виртуального 8086 - подрежим защищённого, предназначался главным образом для создания т. н. «виртуальных DOS-машин». Если из 32-битной версии Windows вы запускаете 16-битное DOS-приложение, то работает эмулятор NTVDM, который использует этот режим процессора. Другой эмулятор, DOSBox, не использует этот режим V86, а выполняет полную эмуляцию.

Переход между режимами

Из длинного режима нельзя перейти в реальный или режим виртуального 8086 без перезагрузки. Поэтому в 64-битных версиях Windows не работает NTVDM и нельзя запускать 16-битные программы.

Самый современный процессор x86-64 полностью поддерживает реальный режим. Если загрузка выполняется через BIOS, то код загрузчика (из сектора #0) исполняется в реальном режиме. Однако если вместо BIOS используется UEFI, то переход в Long mode происходит ещё раньше, и никакого кода в реальном режиме уже не выполняется. Можно считать, что современный компьютер сразу начинает работать в 64-битном длинном режиме.

Трансляция адресов в памяти

Упрощённо говоря, процессор обращается к памяти через шину. Адресами памяти, которыми обмениваются в шине, являются физические адреса, то есть сырые числа от нуля до верхней границы доступной физической памяти (например, до 2 33 , если у вас установлено 8 ГБ оперативки). Ранее между процессором и микросхемами памяти располагался северный мост, но в реализации Intel начиная с Sandy Bridge он интегрирован на кристалл процессора.

Физические адреса являются конкретными и окончательными - без трансляции, без подкачки, без проверки привилегий. Вы выставляете их на шину и всё. Однако программы используют адреса логической памяти, которые должны быть оттранслированы в физические адреса до того, как будет выполнен доступ к памяти. Концептуально трансляция выглядит следующим образом:

Это не физическая схема, а только описание процесса преобразования адресов.

Трансляция начинается, когда CPU выполняет инструкцию, которая ссылается на адрес памяти. Первым шагом является перевод этого логического адреса в линейный адрес. Но, спрашивается, зачем это делать вместо того, чтобы напрямую использовать линейные адреса в программе? Это результат эволюции. Чтобы действительно понять смысл сегментации x86, нам нужно вернуться в 1978 год.

Сегментация памяти в реальном режиме

16-битный процессор 8086 использовал 16-битные регистры и мог напрямую адресовать только 2 16 байт памяти. Инженеры придумывали, как же можно заставить его работать с большим объёмом памяти, не расширяя разрядность регистров.

Были придуманы сегментные регистры, которые должны были задавать, к какому именно 64-килобайтному куску памяти относится данный 16-битный адрес.

Решение выглядит логичным: сначала вы устанавливаете сегментный регистр, по сути говоря “так, я хочу работать с куском памяти начиная с адреса X”; затем 16-битный адрес уже используется как смещение в рамках этого куска.

Всего предусматривалось сначала четыре 16-битных сегментных регистра, потом добавили ещё два:

  • CS = Code Segment
  • DS = Data Segment
  • ES = Destination Segment
  • SS = Stack Segment

Для вычисления линейного адреса ячейки памяти процессор вычисляет физический адрес начала сегмента - умножает сегментную часть виртуального адреса на число 16 (или, что то же самое, сдвигает её влево на 4 бита), а затем складывает полученное число со смещением от начала сегмента. Таким образом, сегменты частично перекрывались, и всего можно было адресовать около 1 МБ физической памяти. Спрашивается, почему не умножать значение сегментного регистра сразу на 65536, ведь тогда можно было бы адресовать 4 ГБ памяти. Тогда это было не нужно и только растило стоимость чипа.

В реальном режиме отсутствует защита памяти и разграничение прав доступа.

Программы были маленькие, поэтому их стек и код полностью помещались в 64 КБ, не было проблем. В языке C тех древних времён обычный указатель был 16-битный и указывал относительно сегмента по умолчанию, однако существовали также far-указатели, которые включали в себя значение сегментного регистра.

#include int main() { char far * p = (char far * ) 0x55550005 ; char far * q = (char far * ) 0x53332225 ; * p = 80 ; (* p) ++; printf ("%d" ,* q) ; return 0 ; }

Тут оба указателя указывают на один и тот же физический адрес 0x55555 .

Защищённый режим

В 32-битном защищенном режиме также используется сегментированная модель памяти, однако уже организованная по другому принципу: расположение сегментов описывается специальными структурами (таблицами дескрипторов), расположенными в оперативной памяти.

Сегменты памяти также выбираются все теми же сегментными регистрами. Значение сегментного регистра (сегментный селектор) больше не является сырым адресом, но вместо этого представляет собой структуру такого вида:

Существует два типа дескрипторных таблиц: глобальная (GDT) и локальная (LDT). Глобальная таблица описывает сегменты операционной системы и разделяемых структур данных, у каждого ядра своя. Локальная таблица может быть определена для каждой конкретной задачи (процесса). Бит TI равен 0 для GDT и 1 для LDT. Индекс задаёт номер дескриптора в таблице дескрипторов сегмента. Поле RPL расшифровывается как Requested Privilege Level.

Сама таблица представляет собой просто массив, содержащий 8-байтные записи (дескрипторы сегмента), где каждая запись описывает один сегмент и выглядит так:

Помимо базового адреса сегмента дескрипторы содержат размер сегмента (точнее, максимально доступное смещение) и различные атрибуты сегментов, использующиеся для защиты памяти и определения прав доступа к сегменту для различных программных модулей. Базовый адрес представляет собой 32-битный линейный адрес, указывающий на начало сегмента, а лимит определяет, насколько большой сегмент. Добавление базового адреса к адресу логической памяти дает линейный адрес (никакого умножения на 16 уже нет). DPL (Descriptor Privilege Level) - уровень привилегий дескриптора; это число от 0 (наиболее привилегированный, режим ядра) до 3 (наименее привилегированный, пользовательский режим), которое контролирует доступ к сегменту.

Когда CPU находится в 32-битных режимах, регистры и инструкции могут в любом случае адресовать всё линейное адресное пространство. Итак, почему бы не установить базовый адрес в ноль и позволить логическим адресам совпадать с линейными адресами? Intel называет это «плоской моделью», и это именно то, что делают современные ядра x86. Это эквивалентно отключению сегментации.

Длинный режим

На архитектуре x86-64 в длинном (64-битном) режиме сегментация не используется. Для четырёх сегментных регистров (CS, SS, DS и ES) базовый адрес принудительно выставляются в 0. Сегментные регистры FS и GS по-прежнему могут иметь ненулевой базовый адрес. Это позволяет ОС использовать их для служебных целей.

Например, Microsoft Windows на x86-64 использует GS для указания на Thread Environment Block, маленькую структурку для каждого потока, которая содержит информацию об обработке исключений, thread-local-переменных и прочих per-thread-сведений. Аналогично, ядро Linux использует GS-сегмент для хранения данных per-CPU.

Практика: просмотр регистров

(gdb) info registers rax 0x40052d 4195629 rbx 0x0 0 rcx 0x0 0 rdx 0x7fffffffde78 140737488346744 rsi 0x7fffffffde68 140737488346728 rdi 0x1 1 rbp 0x7fffffffdd80 0x7fffffffdd80 rsp 0x7fffffffdd80 0x7fffffffdd80 r8 0x7ffff7dd4e80 140737351863936 r9 0x7ffff7dea700 140737351952128 r10 0x7fffffffdc10 140737488346128 r11 0x7ffff7a32e50 140737348054608 r12 0x400440 4195392 r13 0x7fffffffde60 140737488346720 r14 0x0 0 r15 0x0 0 rip 0x400531 0x400531 eflags 0x246 [ PF ZF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0

Кольца защиты

Вы, вероятно, знаете интуитивно, что приложения имеют ограниченные полномочия на компьютерах Intel x86 и что только код операционной системы может выполнять определенные задачи. Как это работает? Уровни привилегий x86 - механизм, с помощью которого ОС и ЦП ограничивают возможности программ пользовательского режима. Существует четыре уровня привилегий: от 0 (наиболее привилегированных) до 3 (наименее привилегированных) и три основных ресурса: память, порты ввода-вывода и возможность выполнения определенных машинных инструкций. В любой момент времени процессор x86 работает на определенном уровне привилегий, который определяет, какой код может и не может сделать. Эти уровни привилегий часто описываются как защитные кольца, причем самое внутреннее кольцо соответствует самым высоким привилегиям. Большинство современных ядер x86 используют только Ring 0 и Ring 3.

Виртуальное адресное пространство

Хотя виртуальные адреса имеют разрядность в 64 бита, текущие реализации (и все чипы, которые находятся на стадии проектирования) не позволяют использовать всё виртуальное адресное пространство из 2 64 байт (16 экзабайт). Это будет примерно в четыре миллиарда раз больше виртуального адресного пространства на 32-битных машинах. В обозримом будущем большинству операционных систем и приложений не потребуется такое большое адресное пространство, поэтому внедрение таких широких виртуальных адресов просто увеличит сложность и расходы на трансляцию адреса без реальной выгоды. Поэтому AMD решила, что в первых реализациях архитектуры фактически при трансляции адресов будут использоваться только младшие 48 бит виртуального адреса.

Кроме того, спецификация AMD требует, что старшие 16 бит любого виртуального адреса, биты с 48-го по 63-й, должны быть копиями бита 47 (по принципу sign extension). Если это требование не выполняется, процессор будет вызывать исключение. Адреса, соответствующие этому правилу, называются «канонической формой». Канонические адреса в общей сложности составляют 256 терабайт полезного виртуального адресного пространства. Это по-прежнему в 65536 раз больше, чем 4 ГБ виртуального адресного пространства 32-битных машин.

Это соглашение допускает при необходимости масштабируемость до истинной 64-разрядной адресации. Многие операционные системы (включая семейство Windows NT и GNU/Linux) берут себе старшую половину адресного пространства (пространство ядра) и оставляют младшую половину (пользовательское пространство) для кода приложения, стека пользовательского режима, кучи и других областей данных. Конструкция «канонического адреса» гарантирует, что каждая совместимая с AMD64 реализация имеет, по сути, две половины памяти: нижняя половина «растет вверх» по мере того, как становится доступнее больше виртуальных битов адреса, а верхняя половина - наоборот, вверху адресного пространства и растет вниз.

Первые версии Windows для x64 даже не использовали все 256 ТБ; они были ограничены только 8 ТБ пользовательского пространства и 8 ТБ пространства ядра. Всё 48-битное адресное пространство стало поддерживаться в Windows 8.1, которая была выпущена в октябре 2013 года.

Структура таблицы страниц

Вместо двухуровневой системы таблиц страниц, используемой системами с 32-битной архитектурой x86, системы, работающие в длинном режиме, используют четыре уровня таблицы страниц.

Возможные размеры страниц:

  • 4 KB (2 12 байт) - наиболее часто используется (как и в x86)
  • 2 MB (2 21 байт)
  • 1 GB (2 30 байт)

Полная иерархия сопоставления страниц размером 4 КБ для всего 48-битного пространства займет немногим больше 512 ГБ ОЗУ (около 0.195% от виртуального пространства 256 ТБ).

Практика: как скоро оно упадёт?

Понятно, что данный код по стандарту некорректен, содержит Undefined Behavior, а раз так, то компилятор может сделать что угодно, например не упасть вообще. Но тем не менее, если запускать на x86-64, то падает оно в определённый момент...

#include #include char buf[ 1 ] ; #define PAGE_SIZE 4096 int main() { char * ptr = buf; for (;; ) { int offset = (intptr_t ) ptr % PAGE_SIZE; printf ("%p: offset = %d\n " , ptr, offset) ; * ptr = "a" ; // Segmentation fault expected! ++ ptr; } return 0 ; }

Организация стека и вызова функций

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

Стек в x86

Стек растёт вниз. Вершина стека на самом деле имеет наименьший адрес.

Используется специальный регистр rsp (Stack Pointer).

Инструкция

Push rax

эквивалентна

Sub rsp, 8 mov , rax

Инструкция

эквивалентна

Mov rax, add rsp, 8

Соглашение вызова в Linux

В Linux и других ОС используется соглашение System V AMD64 ABI.

Для простоты мы ограничимся целочисленными аргументами и указателями.

Первые шесть аргументов передаются через регистры:

Если этого не хватает, то седьмой аргумент уже передаётся через стек.

Если функция хочет использовать регистры rbx, rbp и r12–r15, она перед выходом обязана их вернуть в первоначальное состояние.

Возвращаемое значение до 64 бит сохраняется в rax, до 128 бит - в rax и rdx.

Фрейм стека

Для такой функции

long myfunc(long a, long b, long c, long d, long e, long f, long g, long h) { long xx = a * b * c * d * e * f * g * h; long yy = a + b + c + d + e + f + g + h; long zz = utilfunc(xx, yy, xx % yy) ; return zz + 20 ; }

стек будет иметь такой вид:

Красная зона (red zone)

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

Это оптимизация. Уменьшение и увеличение rsp - это уже две инструкции, их можно сэкономить.

Например:

long utilfunc(long a, long b, long c) { long xx = a + 2 ; long yy = b + 3 ; long zz = c + 4 ; long sum = xx + yy + zz; return xx * yy * zz + sum; }

Сохранение базового указателя фрейма

Указатель rbp (и его предшественник ebp на x86), будучи стабильной «привязкой» к началу фрейма стека во время выполнения функции, очень удобен для ручного программирования и для отладки. Однако некоторое время назад было замечено, что коду, который генерируется компилятором, rbp действительно не нужен (компилятор может легко отслеживать смещения из rsp).

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

gcc сохраняет базовый указатель по умолчанию на x86, но позволяет оптимизировать с помощью флага компиляции -fomit-frame-pointer .

Во всяком случае, еще одна «новинка», которую представил AMD64 ABI, делает базовый указатель явно необязательным. gcc придерживается этой рекомендации и по умолчанию опускает указатель фрейма на x64 при компиляции с оптимизацией. Он дает возможность сохранить его, указав флаг -fno-omit-frame-pointer .

Соглашение вызова в Windows

Ура, больше никаких cdecl/stdcall/fastcall/thiscall/register/safecall, осталось только одно соглашение вызова! Но нет, Microsot разработал vectorcall...

Первые четыре аргумента передаются через регистры: rcx, rdx, r8, r9.

Регистры rbx, rbp, rdi, rsi, rsp, r12, r13, r14 и r15 функция обязана вернуть в исходное состояние.

Практика: сумма чисел 3 : c3 ret

Системные вызовы

Механизмы выполнения системного вызова

Функции C

Когда вы вызываете какую-либо системную функцию, например open() , write() , getpid() из кода на C, вы на самом деле не делаете напрямую сам системный вызов. Просто так вызовом функции в режим ядра (ring 0) из пользовательского (ring 3) перейти не получится. Вызываются обычные функции, реализованные внутри стандартной библиотеки, а уже они внутри делают системный вызов тем или иным методом:

  • через программное прерывание,
  • через инструкцию syscall,
  • через инструкцию sysenter.

Программное прерывание

Прерывания - это как бы сигнал процессору, что надо прервать выполнение (их поэтому и назвали прерываниями) текущего кода и срочно сделать то, что указано в обработчике.

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

Программное прерывание - синхронное прерывание, которое может осуществить программа с помощью специальной инструкции.

В процессорах архитектуры x86 для явного вызова синхронного прерывания имеется инструкция int , аргументом которой является номер прерывания (от 0 до 255). В защищённом и длинном режиме обычные программы не могут обслуживать прерывания, эта функция доступна только системному коду (операционной системе).

В ОС Linux номер прерывания 0x80 используется для выполнения системных вызовов. Обработчиком прерывания 0x80 является ядро Linux. Программа перед выполнением прерывания помещает в регистр eax номер системного вызова, который нужно выполнить. Когда управление переходит в ring 0, то ядро считывает этот номер и вызывает нужную функцию.

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

  • Поместить номер системного вызова в eax .
  • Поместить аргументы в регистры ebx , ecx , edx , esi , edi , ebp .
  • Вызвать инструкцию int 0x80 .
  • Получить результат из eax .

Пример реализации mygetpid() (получение PID текущего процесса) на ассемблере (для системного вызова getpid используется номер 20):

Intel_syntax noprefix . globl mygetpid .text mygetpid: mov eax , 20 int 0x80 ret

Инструкция syscall

Это более современный метод, используется в 64-битном Linux, работает быстрее.

  • Номер системного вызова помещается в rax .
  • Аргументы записываются в rdi , rsi , rdx , r10 , r8 и r9 .
  • Затем вызывается syscall .
  • Результат в rax .

Пример реализации mygetpid() (получение PID текущего процесса) на ассемблере (для системного вызова getpid по таблице используется номер 39):

Intel_syntax noprefix . globl mygetpid .text mygetpid: mov rax , 39 syscall ret

Отслеживание системных вызовов

На Linux инструмент пользовательского режима strace позволяет отслеживать системные вызовы, которые выполняет данная программа.

Для многих пользователей операционной системы Windows не секрет, что существует две ее версии по типу разрядности. Это 32 битная и 64. Знать разрядность своей операционной системы нужно каждому, ведь при поиске и скачивании драйверов, программ и игр она учитывается.

Но с обозначениями разрядности системы, а также драйверов и программ существует некоторая путаница. Есть три обозначения двух разрядностей — x32, x64 и x86. По этой причине часто возникает вопрос 32 разрядная версия это x64 или x86?

Ответ на данный вопрос вы найдете в этой статье.

Второе обозначение 32 разрядной версии ПО

Чтобы впредь исключить путаницу обозначений разрядности программного обеспечения, к которому относится операционная система, драйвера, программы и игры, запомните, что существует две основные версии разрядности ПО — это 32 бита и 64 бита. 64 битная версия может обозначаться только как x64, а вот 32 битная может обозначаться как x32, так и x86.

Вот пример обозначения 64 битной версии драйвера для ноутбука на его официальном сайте:

А вот возможные варианты обозначения 32 битной версии:

Обозначение разрядности на сайте с драйверами

Обозначение разрядности в описании программы

Из всего вышеописанного можно сделать вывод, что 32 разрядная версия ПО это x86.

x64 обозначается 64 битная версия какого — либо программного обеспечения. Учтите это при подборе версии драйверов и любых других программ.

Для того, чтобы просмотреть какая у вас разрядность операционной системы, достаточно нажать правой кнопкой мыши по значку «Компьютер» на рабочем столе и выбрать «Свойства».