Большая часть набора команд x86 является общей для всех процессоров - вполне разумно предположить, что у обоих процессоров одинаковый набор команд, за исключением, возможно, SIMD-инструкций, которые, вероятно, не будут очень полезны при реализации простого компилятор (эти инструкции обычно используются для ускорения работы мультимедийных приложений и т. п.). Набор инструкций приведен в Руководства Intel - в частности, 2A и 2B содержат полный список инструкций и их поведение, хотя на другие тома стоит обратить внимание.
При создании кода пользовательского пространства выбор операционной системы имеет значение, когда дело доходит до системных вызовов. Например, если вы хотите, чтобы программа выводила что-то на терминал в 64-битной Linux, вам нужно сделать системный вызов:
- загрузка значения 1 в регистр
rax
, чтобы указать, что это системный вызов write
.
- загрузка значения 1 в регистр
rdi
для указания того, что следует использовать стандартный вывод (1 - дескриптор файла для стандартного вывода)
- загрузка начального адреса того, что вы хотите напечатать в регистр
rsi
- загрузка длины того, что вы хотите напечатать в регистр
rdx
- выполнение инструкции
syscall
после настройки регистров (и памяти).
Возвращаемое значение из write
сохраняется в rax
.
Другая операционная система может иметь другой номер системного вызова для write
, может иметь другой способ передачи аргументов (системные вызовы Linux x86-64 всегда используют rdi
, rsi
, rdx
, r10
, r8
и r9
в таком порядке для параметров с номером системного вызова в rax
), и могут иметь разные системные вызовы в целом.
Соглашение для обычных вызовов функций в Linux аналогично - порядок регистров rdi
, rsi
, rdx
, rcx
, r8
и r9
(так что все то же самое, за исключением использования rcx
вместо r10
), с дополнительными аргументами в стеке и возвращаемым значением в rax
. Согласно этой странице регистры rbp
, rbx
и r12
до r15
должны сохраняться при вызовах функций. Вы, конечно, можете создавать свои собственные соглашения (если только не делаете системный вызов), но это усложняет вызов, вызываемый из кода, сгенерированного или написанного другими.