amd64, x86_64, x64, intel64

Что: e2185b7733f55709666d1f4f8a59adcf0eed4506

Когда: 2022-05-04 17:12:14+03:00

Темы: hate

amd64, x86_64, x64, intel64

https://en.wikipedia.org/wiki/X86-64
https://sourceware.org/binutils/docs/as/i386_002dISA.html
Ужасно бесит что буквально за пять минут можно встретить в разном софте
разные названия 64-бит x86 архитектуры. Лично для меня amd64 это то что
я пишу и в BSD встречаю. x86_64 это так в GNU/Linux мире принято (просто
создаётся впечатление). А x64... это нечто яростно выбешивающее меня.
Intel64 не встречал прежде, до чтения статьи на Wikipedia.

Оказывается... AMD64 и Intel64 вполне себе разные ISA! Судя по
Wikipedia, всякие штуки типа: не отличающегося на практике (хотя это и
undefined behaviour) значения, формата микрокода, ограничения вне 32-бит
режима -- выглядят как не существенными на практике для пользователя. Но
другие отличия вроде бы выглядят кардинально и серьёзно. Что же получается?
Что на самом деле нет одного amd64 (пускай и с расширениями, типа AVX)?
Есть действительно разные наборы команд и поведения для AMD и Intel
процессоров? Почему же я не встречаю intel64, а только amd64? Или
программистам приходится жутко страдать и делать CPU detection и
удовлетворять оба этих процессора? Или это как-раз то самое: мы работаем
на AMD64, но поддерживаем чётко-заданный-список-CPU? Звучит всё страшно
пугающе несовместимо.

А ещё, бывает, находятся особо умные, кто пишет "IA64", где-то, видимо,
предварительно увидев "IA32". Вот только IA64 это Itanium и совершенно
другая и несовместимая штука.

оставить комментарий

комментарий 0:

From: kmeaw
Date: 2022-05-05 21:27:51Z

> Почему же я не встречаю intel64, а только amd64?

Потому что AMD придумала набор инструкций для своего процессора
Athlon 64 с микроархитектурой K8, как новую версию K7 (Athlon XP),
значимыми отличаями которой были перенос контроллера памяти на кристалл
и те самые 64-битные расширения набора инструкций, названные AMD64.

> Есть действительно разные наборы команд и поведения для AMD и Intel
> процессоров?

На практике вне системного софта сложно столкнуться с разницей. Из
забавного вспомнил, что процессоры Intel и AMD отличаются поведением при
переполнении счётчика инструкций (EIP) - AMD генерирует исключение,
тогда как Intel просто продолжает выполнять код с (около)нулевого
адреса. Из-за этой разницы получилось взломать Xbox для запуска Linux
без необходимости вставлять в загрузчик проприетарный код или
использования взломанных ключей шифрования (что могло привести к
нарушению DMCA).

Ещё была проблема с инструкцией SYSRET на процессорах Intel. Эта
инструкция предназначена для возврата из системного вызова и копирует
адрес из регистра RCX в RIP, одновременно переключая сегмент кода. Но
если адрес оказался неканоничным (в диапозоне 0x0000_8000_0000_0000 …
0xFFFF_7FFF_FFFF_FFFF, иными словами, у которого биты 47…63 не равны
друг-другу), то будет сгенерировано исключение. Но на процессоре AMD это
происходит после выхода из привилегированного контекста, а на некоторых
процессорах Intel - после, что позволяет переписать одно слово в стеке.
А поскольку обычно SYSRET вызывают из ядра в тот момент, когда уже пора
обратно переключаться в пользовательский процесс, то у последнего есть
возможность непосредственно перед SYSCALL использовать произвольный
указатель на вершину стека просто загрузив его в регистр RSP, который
уже будет восстановлен к моменту вызова SYSRET, контролируя таким
образом адрес переписываемого слова. Пришлось и во FreeBSD, и в Linux, и
в Windows добавлять проверку адреса на каноничность перед SYSRET на
процессорах Intel.

Другая проблема появилась в процессорах Intel с переносом контроллера
прерываний APIC внутрь процессора (примерно в момент появления Pentium с
рабочим напряжением в 3.3 волта). Для настройки контроллера
использовались memory-mapped регистры по адресу 0xFEE0_0000…0xFEE0_1000.
Чтобы не сломать совместимость со старыми процессорами на платформах,
где APIC нет, Intel добавили возможность двигать это четырёхкилобайтное
окошко в другое место адресного пространства с помощью model-specific
registers, позволяя производителю оборудования избежать конфликта с
каким-нибудь другим устройством на шине. А потом на 20 лет все про это
забыли.

Но есть и другая история, без которой проблемы бы не возникло. Чтобы
обойти конкурентов, Intel ещё раньше выпустила процессор 386SL,
предназначенный для ноутбуков - его отличительной особенностью было
сниженное энергопотребление. Тогда впервые появился новый режим работы
процессора - SMM, позволяющий прошивке загрузить код и спрятать его от
ОС. Так, например, можно реализовать уход процессора в сон, когда
прошивка платформы определяет, что сейчас пользователь ничего полезного
не делает, без модификации и добавления каких-либо драйверов в ОС. В
дальнейшем этот режим использовался для ещё более изощрённых хаков -
эмуляции PS/2-клавиатуры для работы с USB-клавиатурой в DOS.

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

Оказалось, что APIC находится настолько глубоко в процессорах Intel, что
проверка "не происходит ли обращение к memory-mapped регистрам APIC"
происходит даже в режиме SMM, даже при доступе к SMRAM. Что позволяет
злоумышленнику подвинуть это окошко, чтобы перекрыть важные структуры
данных, лежащие в SMRAM регистрами APIC, таким образом влияя на control
flow. Эта проблема починена начиная с Sandy Bridge возбуждением
исключения, если эти два региона памяти перекрываются.

Из того, с чем можно столкнуться прямо сейчас на практике, в голову
приходят только то, как устроены performance counters и model-specific
registers.

До amd64 когда-то сталкивался с особенностью процессоров Transmeta, в
которых не была реализована на тот момент недокументированная инструкция
CMOVxx, из-за чего i686-бинарники ломались - приходилось патчить ядро,
добавляя в его обработчик исключения #UD (invalid opcode) эмулятор. А
процессоры National Semiconductors Geode не поддерживают инструкцию
endbr32, которую вставляет GCC для защиты кода от Spectre. Процессоры
Intel начиная с Pentium Pro считают это документированным NOP, а Geode
сваливаются с SIGILL.

> приходится жутко страдать и делать CPU detection

Разработчики системного ПО стараются помочь с этим. Например, свежие
версии glibc умеют грузить библиотеки по CPU-зависимому пути, позволяя
положить, например, в /usr/lib64/glibc-hwcaps/x86-64-v4 версии
библиотек, использующие AVX512.

Но всё становится совсем сложно, когда появляются ассиметричные
многоядерные процессоры - у разных ядер могут быть разные instruction
sets. Мне пока неизвестно о наличии в мейнстримных ОС такого
планировщика, который бы умел мигрировать процессы с одного ядра на
другое, учитывая особенности сборки каждой запущенной задачи.

Несколько лет назад компилятор от Intel был замечен в "нечестном"
поведении - в момент запуска программы проверялся CPUID, и если там не
"GenuineIntel", то использовалась не самая оптимальная версия для
некоторых builtins, даже если текущий процессор был способен исполнить
её ожидаемым образом. Что приводило к дополнительным очкам для Intel в
некоторых тестах производительности.

> Или это как-раз то самое: мы работаем на AMD64, но поддерживаем
> чётко-заданный-список-CPU?

Если у разработчика прикладной программы нет цели выжать последние
проценты производительности из CPU, то можно не думать обо всём этом и
использовать то подмножество инструкций, которое работает и на AMD, и на
Intel. Разница уже не столь велика, как раньше на i686 - тогда указание
конкретных микроархитектур в gcc -march= давало куда более заментный
прирост производительности, чем сейчас.

комментарий 1:

From: Sergey Matveev
Date: 2022-05-06 08:20:38Z


Очень любопытно было почитать это! Спасибо.

>До amd64 когда-то сталкивался с особенностью процессоров Transmeta, в
>которых не была реализована на тот момент недокументированная инструкция CMOVxx

Про это помню, помню. Сам на практике не встречался, но читал.

>Но всё становится совсем сложно, когда появляются ассиметричные
>многоядерные процессоры - у разных ядер могут быть разные instruction
>sets.

Ого, не слышал про такое. Точнее я слышал, с выходом Apple M1, о ядрах
разной эффективности, но не о том, что могут быть ещё и разные инструкции.
Задавался ещё и вопросом а современные GNU/Linux, BSD, whatever учитывают
ли в своих планировщиках особенности разноэффектных ядер.

>Несколько лет назад компилятор от Intel был замечен в "нечестном"

Ага, тоже помню :-)

>Если у разработчика прикладной программы нет цели выжать последние
>проценты производительности из CPU, то можно не думать обо всём этом и
>использовать то подмножество инструкций, которое работает и на AMD, и на
>Intel. Разница уже не столь велика, как раньше на i686 - тогда указание
>конкретных микроархитектур в gcc -march= давало куда более заментный
>прирост производительности, чем сейчас.

Ok, ясно, спасибо. Прирост помню был ощутимый для мультимедиа, когда
комплировать MPlayer для K6-2 с 3DNow!.

Сгенерирован: SGBlog 0.34.0