Создание кода, 64-разрядного чистый
Прежде чем Вы начнете обновлять свой код, необходимо ознакомить себя с документом Технологический Обзор Mac. После чтения того документа первая вещь, которую необходимо сделать, скомпилировать код с -Wall
флаг компилятора и фиксирует любые происходящие предупреждения. В частности удостоверьтесь, что все прототипы функции находятся в объеме, потому что прототипы из объема могут скрыть много тонких проблем мобильности.
На высоком уровне, для создания кода 64-разрядным чистый необходимо сделать следующее:
Избегите присваиваться 64-разрядный
long
целые числа к 32-разрядным целым числам.Избегите присваивать 64-разрядные указатели на 32-разрядные целые числа.
Устраните проблемы выравнивания, вызванные изменениями в размерах типа данных.
Избегите указателя и
long
целочисленное усечение во время арифметических операций.
Общие подсказки по программированию
Этот раздел содержит некоторые общие советы для того, чтобы сделать Ваш код 64-разрядным чистый.
Обновите архитектурно-зависимый код. Если Ваше программное обеспечение содержит какой-либо архитектурно-зависимый код, необходимо или добавить дополнительный код для каждой дополнительной архитектуры или изменить директивы препроцессору так, чтобы тот же код был включен для многократной поддерживаемой архитектуры.
Если Вы не включаете код языка встроенного ассемблерного кода, необходимо обычно тестировать на присутствие нейтральных архитектурой макросов такой как __LITTLE_ENDIAN__
или __LP64__
вместо того, чтобы тестировать на определенную архитектуру процессора.
Макрос __LP64__
может использоваться для тестирования на компиляцию LP64 архитектурно-независимым способом. Например:
#ifdef __LP64__ |
// 64-bit code |
#else |
// 32-bit code |
#endif |
Для кода, который является действительно архитектурно-зависимым (такие как код ассемблера), необходимо продолжать использовать архитектурно-зависимые тесты. Знайте, однако, что при компиляции для 64-разрядной архитектуры, код, обернутый в тест для 32-разрядной архитектуры, не компилируется в исполнимую программу.
Например, код перенесся с #ifdef __i386__
директива не будет включена при компиляции для x86_64
архитектура. Следующее перечисление (Перечисление 3-1) дает примеры как к тестам записи на различную архитектуру.
Изменения определения Архитектуры перечисления 3-1
#ifdef __ppc__ |
// 32-bit PowerPC code |
#else |
#ifdef __ppc64__ |
// 64-bit PowerPC code |
#else |
#if defined(__i386__) || defined(__x86_64__) |
// 32-bit or 64-bit Intel code |
#else |
#error UNKNOWN ARCHITECTURE |
#endif |
#endif |
#endif |
Код, ищущий только __ppc__
или __i386__
если Вы скомпилируете для связанной 64-разрядной архитектуры, определение повредится.
Для кода, определенного для (немежплатформенного) OS X, TargetConditionals.h
заголовок также предоставляет макро-поддержку для архитектурно-зависимого кода. Например:
#include <TargetConditionals.h> |
#if TARGET_RT_LITTLE_ENDIAN |
... |
#elif TARGET_RT_BIG_ENDIAN |
... |
#else |
#error Something is very wrong here. |
#endif |
Избегите бросать указатели на не указатели. Необходимо обычно избегать бросать указатель на неуказательный тип по любой причине (особенно при выполнении адресной арифметики). Альтернативы описаны в Предотвращении Преобразования Указателя на целое число.
Обновите ассемблерный код. Любой ассемблерный код должен быть переписан, потому что 64-разрядный ассемблер Intel существенно отличается от своего 32-разрядного дубликата. Для получения дополнительной информации посмотрите Код Ассемблера Портирования.
Любой ассемблерный код, непосредственно имеющий дело со структурой штабеля (в противоположность простому использованию указателей на переменные на штабеле) должен быть изменен для работы в 64-разрядной среде. Для получения дополнительной информации посмотрите OS X ABI Мужественная Ссылка Формата файла.
Фиксируйте строки формата. Печать функционирует такой как printf
может быть хитрым при записи кода для поддержки 32-разрядных и 64-разрядных платформ из-за изменения в размерах указателей. Решить эту проблему для целых чисел размера указателя (uintptr_t
) и другие стандартные типы, различные макросы существуют в inttypes.h
заголовочный файл.
Строки формата для различных типов данных описаны в Таблице 3-1. Эти дополнительные типы, перечисленные в inttypes.h
заголовочный файл, описаны в Таблице 3-2.
Ввести | Строка формата |
---|---|
|
|
|
|
|
|
|
|
|
|
любой указатель |
|
Ввести | Строка формата |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Например, для печати intptr_t
переменная (целое число размера указателя) и указатель, Вы пишете код, подобный этому в Перечислении 3-2.
Перечисление 3-2 Архитектурно-независимая печать
#include <inttypes.h> |
void *foo; |
intptr_t k = (intptr_t) foo; |
void *ptr = &k; |
printf("The value of k is %" PRIdPTR "\n", k); |
printf("The value of ptr is %p\n", ptr); |
Тип данных и подсказки по выравниванию
Вот несколько подсказок, чтобы помочь Вам избежать проблем, происходящих от изменений до размера типа данных и выравнивания.
Будьте осторожны при смешивании целых чисел и длинных целых. Размер и выравнивание long
целые числа и указатели изменились от 32-разрядного до 64-разрядного.
По большей части, если Вы всегда используете sizeof
функционируйте при выделении структур данных и избегите присваивать указатели на неуказательные типы, размер и выравнивание указателей не должны влиять код, потому что структуры, содержащие элементы указателя, обычно не пишутся в диск или отправляются через сети между 32-разрядными и 64-разрядными приложениями. Это - что-то для рассмотрения при записи расширений ядра, читающих, структуры передали в из приложений, как бы то ни было.
Если Вы часто перемещаете данные между переменными типа int
и long
, изменение в размере long
может вызвать проблемы. Вы будете видеть различные связанные проблемы всюду по этому разделу.
Обязательно управляйте выравниванием совместно используемых данных. Выравнивание long long
(64-разрядные) целые числа изменились от 32-разрядного до 64-разрядного. Это изменение выравнивания может изложить проблему при обмене данными между 32-разрядным и 64-разрядным кодом.
В Перечислении 3-3 изменяется выравнивание даже при том, что типы данных являются тем же размером.
Выравнивание перечисления 3-3 long long
целые числа в структурах
struct bar { |
int foo0; |
int foo1; |
int foo2; |
long long bar; |
}; |
Когда этот код компилируется с 32-разрядным компилятором, переменной bar
начинает 12 байтов с запуска структуры. Когда тот же код компилируется с 64-разрядным компилятором, переменной bar
начинает 16 байтов с запуска структуры, и 4-байтовая клавиатура добавляется после foo2
.
Если необходимо поддержать совместимость структуры данных, чтобы позволить единственной структуре данных быть совместно использованной, можно использовать прагму для принуждения упакованного режима выравнивания для каждой структуры по мере необходимости. Тогда добавьте надлежащие байты клавиатуры (если необходимый) для получения желаемого выравнивания. Пример показан в Перечислении 3-4.
Если назад совместимость с существующими структурами не важна, необходимо переупорядочить структуру данных так, чтобы самые большие поля были в начале структуры. Тем путем 8-байтовые поля начинаются при смещении 0
и таким образом выровненные на 8-байтовых границах без потребности добавить прагму выравнивания.
Перечисление 3-4 Используя прагмы для управления выравниванием
#pragma pack(4) |
struct bar { |
int foo0; |
int foo1; |
int foo2; |
long long bar; |
}; |
#pragma options align=reset |
Необходимо использовать эту опцию только при необходимости, потому что существует потеря производительности для неправильно выровненных доступов.
Используйте sizeof с malloc. Так как указатели и длинные целые больше не 4 байта длиной, никогда не вызывайте malloc
с явным размером (например, malloc(4)
) выделять площадь для них. Всегда используйте sizeof
получить корректный размер.
Никогда не предполагайте знание размера любой структуры (содержащий указатель или иначе); всегда используйте sizeof
узнать наверняка. Для предотвращения будущих проблем мобильности ищите код любой экземпляр malloc
это не сопровождается sizeof
. grep
команда и регулярные выражения являются Вашим другом, хотя использование Находит в меню Xcode Edit, может выполнить работу.
64-разрядный sizeof возвращает size_t. Обратите внимание на то, что sizeof
возвращает целое число типа size_t
. Поскольку размер size_t
изменился на 64 бита, не передавайте значение функции в параметре размера int
(если Вы не уверены, что размер не может быть настолько большим). Если Вы сделаете, то усечение произойдет.
Используйте явный (фиксированная ширина) типы C99. Необходимо использовать явные типы, если это возможно. Например, типы с именами как int32_t
и uint32_t
всегда будет 32-разрядное количество, независимо от будущих изменений в архитектуре.
32-разрядный тип | Предложенный тип C99 |
---|---|
|
|
|
|
|
|
|
|
|
|
Наблюдайте за ошибками преобразования. Преобразование более коротких типов к 64-разрядному longs может привести к неожиданным результатам в определенных случаях. Обязательно считайте Правила Расширения знака для C и Языков C-derived, если Вы видите неожиданные значения от смешивающейся математики int
и long
переменные.
Используйте 64-разрядные типы для результатов адресной арифметики с указателями. Поскольку размер указателей является 64-разрядным значением, результатом адресной арифметики с указателями является также 64-разрядное значение. Необходимо всегда хранить эти значения в переменной типа ptrdiff_t
гарантировать, что переменная измерена соответственно.
Избегите усекать позиции файла и смещения. Несмотря на то, что операции файла всегда использовали 64-разрядные позиции и смещения, необходимо все еще проверить на ошибки в их использовании. Ошибки станут более важными, когда растут размеры общего файла. Использовать fpos_t
для позиции файла и off_t
для файлового смещения.
Будьте осторожны со списками аргумента переменной. Списки аргумента переменной (varargs
) не предоставляйте информацию типа для параметров, и параметры не продвинуты на большие типы автоматически. Если необходимо различить различные входные типы данных, Вы, как ожидают, будете использовать строку формата или другой подобный механизм для предоставления той информации varargs
функция. Если функция вызова правильно не предоставляет ту информацию (или если varargs
функция не интерпретирует его правильно), Вы получите неправильные результаты.
В частности если Ваш varargs
функция ожидает a long
введите и Вы передаете в 32-разрядном значении, varargs
функция будет содержать 32 бита данных и 32 бита мусора от следующего параметра (который Вы потеряете в результате). Аналогично, если Ваш varargs
функция ожидает int
введите и Вы передаете в a long
, Вы получите только половину данных, и остальные неправильно появятся в следующем параметре.
Например, если Вы используете неправильный printf
строки формата, Вы получите неправильное поведение. Некоторые примеры этих ошибок строки формата показаны в общих Подсказках по Программированию.
Предотвращение преобразования указателя на целое число
Необходимо обычно избегать бросать указатель на неуказательный тип по любой причине. Если возможно, переписывают любой код, использующий эти броски, или путем изменения типов данных или путем замены адресной арифметики адресной арифметикой с указателями. Например, следующий код:
int *c = something passed in as an argument.... |
int *d = (int *)((int)c + 4); // This code is WRONG! |
результаты в усечении указателя. Поскольку получающееся значение было бы корректно для достаточно небольших указателей, эти ошибки может быть трудно найти. Вместо этого этот код может быть заменен:
int *c = something passed in as an argument.... |
int *d = c + 1; |
(Конечно, этот пример несколько изобретен, и такое использование указателей является относительно редким.)
Больше типичной проблемы хранит указатель временно в переменной типа int
. В большинстве случаев компилятор предупредит Вас, что указатель присваивается целому числу различного размера. Однако в нескольких случаях, код, содержащий такое присвоение, скомпилирует без предупреждения. Например, если код хранит значения в переменной типа long
и затем более поздние копии это к целому числу, сам указатель не является непосредственно усеченным, таким образом, компилятор может не генерировать предупреждение. Эти проблемы особенно трудно определить.
Наконец, типичной проблемой является потребность сместить указатель определенным числом байтов. Вместо того, чтобы бросить к целому числу и использовать целочисленную математику, необходимо бросить указатель на тип указателя ширины байта такой как char *
или uint8_t *
. После того, как Вы сделаете это, указатель будет вести себя как целое число в арифметических целях. Например:
int *myptr = getPointerFromSomewhere(); |
int *shiftbytwobytes = (int *)(((int)myptr) + 2); |
может быть переписан как:
int *myptr = getPointerFromSomewhere(); |
int *shiftbytwobytes = (int *)(((char *)myptr) + 2); |
Путем предотвращения присвоения указателей на любой неуказательный тип Вы избегаете почти всех связанных с указателем проблем, потому что указатели редко сохранены или обмениваются между 32-разрядными и 64-разрядными процессами. В нескольких ситуациях, однако, не может быть никакого простого способа избежать преобразований адреса к целому числу. uintptr_t
тип существует для этих граничных случаев.
Работа с битами и битовыми масками
При работе с битами и масках с 64-разрядными значениями, необходимо стараться избежать получать 32-разрядные значения непреднамеренно. Вот некоторые подсказки для помощи Вам:
Сместитесь тщательно. Если Вы смещаетесь через биты, сохраненные в переменной типа long
, не предполагайте, что переменная имеет определенную длину. Вместо этого используйте значение LONG_BIT
определить число битов в a long
. Результат сдвига, превышающего длину переменной, является архитектурно-зависимым.
Используйте инвертированные маски в случае необходимости. Будьте осторожны при использовании битовых масок с переменными типа long
, потому что ширина отличается между 32-разрядной и 64-разрядной архитектурой. Существует два способа создать маску, в зависимости от того, хотите ли Вы, чтобы маска была расширена до нуля, или однорасширенные:
Если Вы захотите, чтобы значение маски содержало нули в верхних 32 битах на 64-разрядной архитектуре, то обычная маска фиксированной ширины будет работать как ожидалось, потому что это будет расширено способом без знака на 64-разрядное количество.
Если Вы хотите, чтобы значение маски содержало в верхних битах, однако, необходимо записать маску как поразрядную инверсию ее инверсии, как показано в Перечислении 3-5.
Перечисление 3-5 Используя инвертированную маску для расширения знака
function_name(long value) |
{ |
long mask = ~0x3; // 0xfffffffc or 0xfffffffffffffffc |
return (value & mask); |
} |
В коде обратите внимание на то, что верхние биты в маске заполнены в 64-разрядном случае.
Подсказки по инструментам
Вот некоторые подсказки, чтобы помочь Вам использовать компилятор эффективнее в переходе Вашего кода к 64-разрядному:
Если данные являются непреднамеренно усеченными, чтобы помочь Вам найти источник, попытайтесь включить дополнительные предупреждения компилятора.
В способных версиях на 64 бита GCC (4.0 и позже), размер a
long double
будут 128 битов вместо 64 битов. Это изменение не ограничивается кодом, скомпилированным как 64-разрядная исполнимая программа, но это - изменение набора инструментальных средств, о котором необходимо знать.
Можно найти подробные подсказки и информацию о 64-разрядных изменениях инструментов в Компиляции 64-разрядного Кода.
Прагмы выравнивания
Иногда, разработчики используют прагмы выравнивания для изменения способа, которым структуры данных размечаются в памяти. Они обычно делают это для обратной совместимости. Во многих случаях Apple добавил прагмы для поддержания совместимости структуры данных между основанным на 68K и основанным на PowerPC кодом, работающим на той же машине под Mac OS 9 и ранее. OS X сохранил эти переопределения выравнивания для поддержания совместимости на уровне двоичных кодов с существующими структурами данных Углерода между Mac OS 9 и OS X.
Существует стоимость производительности, связанная с прагмами, однако; доступы памяти к невыровненным полям данных приводят к потере производительности. Поскольку нет никакого существующего 64-разрядного OS X приложений GUI, с которыми быть совместим, не необходимо сохранить совместимость на уровне двоичных кодов для этих структур данных в 64-разрядных приложениях. Таким образом, для улучшения общей производительности, при компиляции 64-разрядных исполнимых программ, версия OS X GCC игнорирует запросы на mac68k
выравнивание.
При использовании этой прагмы только для доступа к структурам данных Apple, Вы не должны должны быть вносить любые изменения кода в свой код. При компиляции 64-разрядного кода компилятор игнорирует прагмы, и код работает правильно. Если, однако, Вы в настоящее время используете mac68k
прагма выравнивания в Ваших собственных структурах данных, которые будут совместно использованы 32-разрядными и 64-разрядными версиями Вашего приложения (или если Вы используете mac68k
прагма для структуры данных, соответствующей расположению регистра физического устройства), необходимо переписать структуру данных, чтобы использовать упакованное выравнивание и дополнить структуру соответственно.
За исключением типов данных Altivec, следующий код эквивалентен mac68k
выравнивание:
#pragma pack(2) |
...structure declaration goes here... |
#pragma options align=reset |
Точно так же за исключением некоторых векторных типов данных, следующий код эквивалентен стандартному 32-разрядному выравниванию:
#pragma pack(4) |
...structure declaration goes here... |
#pragma options align=reset |
Правила расширения знака для C и языков C-derived
C и подобные языки используют ряд правил расширения знака определить, обработать ли главный бит в целом числе как знаковый бит, когда значение присваивается переменной большей ширины. Правила расширения знака следующие:
Сумма значения со знаком и значения без знака того же размера является значением без знака.
Любое продвижение всегда приводит к типу со знаком, если тип со знаком не может содержать все значения исходного типа (т.е. если получающийся тип не является тем же размером как исходный тип).
Значения без знака являются расширенным нулем (не, подписываются расширенный), когда продвинуто на больший тип.
Даже если получающийся тип без знака, значения со знаком всегда являются знаком, расширенным, когда продвинуто на больший тип.
Константы (если не изменено суффиксом, такой как
0x8L
) обрабатываются как самый маленький размер, который будет содержать значение. Числа, записанные в шестнадцатеричном, могут быть обработаны компилятором какsigned
иunsigned
int
,long
, иlong long
типы. Десятичные числа будут всегда обрабатываться какsigned
типы.
Перечисление 3-6 показывает пример неожиданного поведения, следующего из этих правил вместе с сопроводительным объяснением.
Пример Расширения знака перечисления 3-6 1
int a=-2; |
unsigned int b=1; |
long c = a + b; |
long long d=c; // to get a consistent size for printing. |
printf("%lld\n", d); |
Проблема: Когда этот код выполняется на 32-разрядной архитектуре, результат -1
(0xffffffff
). Когда код выполняется на 64-разрядной архитектуре, результат 4294967295
(0x00000000ffffffff
), который является, вероятно, не, что Вы ожидали.
Причина: Почему это происходит? Во-первых, эти два числа добавляются. Значение со знаком плюс значение без знака приводит к значению без знака (правило 1). Затем, то значение продвинуто на больший тип. Это продвижение не вызывает расширение знака (правило 2).
Решение: Для решения этой проблемы совместимым способом на 32 бита бросить b
к long
. Этот бросок вызывает не, подписывают расширенное продвижение b
к 64-разрядному типу до дополнения, таким образом вынуждая целое число со знаком быть продвинутым (способом со знаком) для соответствия. С тем изменением результатом является ожидаемый -1
.
Перечисление 3-7 показывает связанный пример с сопроводительным объяснением.
Пример Расширения знака перечисления 3-7 2
unsigned short a=1; |
unsigned long b = (a << 31); |
unsigned long long c=b; |
printf("%llx\n", c); |
Проблема: ожидаемый результат (и результат 32-разрядной исполнимой программы) 0x80000000
. Результат, сгенерированный 64-разрядной исполнимой программой, однако, 0xffffffff80000000
.
Причина: Почему расширяется этот знак? Во-первых, когда оператор сдвига вызывается, переменная a
продвинут на переменную типа int
. Поскольку все значения a short
может вписаться в со знаком int
, результат этого продвижения подписывается (правило 3).
Второй, когда сдвиг завершился, результат был сохранен в a long
. Таким образом, 32-разрядное значение со знаком, представленное (a << 31)
был знак, расширенный (правило 4), когда это было продвинуто на 64-разрядное значение (даже при том, что получающийся тип без знака).
Решение: Для решения этой проблемы необходимо бросить начальное значение к a long
до сдвига. Таким образом короткое будет продвинуто только один раз — на сей раз к 64-разрядному типу (по крайней мере, когда скомпилировано как 64-разрядная исполнимая программа).
Скоростной механизм и подсказки по выравниванию SSE
Несмотря на то, что SSE и Скоростной Механизм C и интерфейсы ассемблера не изменились для 64-разрядного при использовании этих технологий необходимо рассмотреть любой код, пытающийся выровнять указатели на 16-байтовые адреса для обработки.
Например, следующий код содержит две ошибки:
TYPE *aligned = (TYPE *) ((int) misalignedPtr & 0xFFFFFFF0); // BAD! |
Во-первых, указатель брошен к int
значение, приводящее к усечению. Даже после того, как эта проблема решена, однако, указатель все еще будет усеченным потому что постоянное значение 0xFFFFFFF0
не 64-разрядное значение.
Вместо этого этот код должен быть записан как:
#include <stdint.h> |
TYPE *aligned = (TYPE *) ((intptr_t) misalignedPtr & ~(intptr_t)0xF); |
Портирование кода ассемблера
В этом разделе описываются некоторые проблемы, вовлеченные в портирование кода ассемблера к 64-разрядному приложению. На архитектуре Intel, в дополнение к проблемам, описанным в этом разделе, необходимо значительно изменить любой код ассемблера, имеющий дело со штабелем непосредственно, потому что 64-разрядный ABI отличается значительно от 32-разрядного ABI. Предмет стековых фреймов выходит за рамки этого раздела. Для получения дополнительной информации посмотрите OS X ABI Мужественная Ссылка Формата файла.
На основанных на Intel компьютерах Macintosh 64-разрядный код использует Intel 64 (раньше EM64T) расширения ассемблера Intel ISA. Этот раздел суммирует различия между кодом Intel 64 и кодом IA32 с точки зрения их влияния на регистры и системы команд.
Изменения регистра
64-разрядные регистры на Intel имеют различные имена, чем их 32-разрядные дубликаты. Кроме того, существует больше из них. Эти имена регистра перечислены в Таблице 3-3.
IA32 32-разрядный регистр | Архитектура Intel 64 64-разрядный вариант | Описание |
---|---|---|
|
| Указатель команд |
|
| Регистр общего назначения A |
|
| Регистр общего назначения B |
|
| Регистр общего назначения C |
|
| Регистр общего назначения D |
|
| Указатель вершины стека |
|
| Указатель кадра |
|
| Исходный индексный регистр |
|
| Целевой индексный регистр |
---- |
| Зарегистрируйтесь 8 (новый) |
---- |
| Зарегистрируйтесь 9 (новый) |
---- |
| Зарегистрируйтесь 10 (новый) |
---- |
| Зарегистрируйтесь 11 (новый) |
---- |
| Зарегистрируйтесь 12 (новый) |
---- |
| Зарегистрируйтесь 13 (новый) |
---- |
| Зарегистрируйтесь 14 (новый) |
---- |
| Зарегистрируйтесь 15 (новый) |
Все новые регистры (R8
через R15
) добавленный в системе команд архитектуры Intel 64 может также быть получен доступ как 32-разрядные, 16-разрядные, и 8-разрядные регистры. Например, регистр R8
может адресоваться следующими способами:
Имя регистра | Описание |
---|---|
| 64-разрядный регистр. |
| 32-разрядный регистр, содержащий нижнюю половину |
| 16-разрядный регистр, содержащий нижнюю половину |
| 8-разрядный регистр, содержащий нижнюю половину |
В дополнение к добавлению регистров общего назначения система команд Архитектуры Intel 64 имеет восемь дополнительных векторных регистров. В системе команд IA32 пронумерованы векторные регистры XMM0
через XMM7
. Система команд Архитектуры Intel 64 расширяет это путем добавления XMM8
через XMM15
.
Изменения инструкции
Большинство инструкций IA32 может взять 64-разрядные параметры. Все расширения системы команд IA32 через SSE3 включены как часть Архитектуры Intel 64. Кроме того, много новых инструкций были добавлены.
Полный список этих изменений выходит за рамки этого документа. Для получения информации об этих изменениях посмотрите ссылки в Для получения дополнительной информации.
Для получения дополнительной информации
Для получения дополнительной информации о портировании и оптимизации ассемблера Intel кодируют для 64-разрядного, необходимо также читать:
OS X ABI Мужественная Ссылка Формата файла — документация ABI для OS X.
http://developer.intel.com/technology/intel64/index.htm — технологическая страница Архитектуры Intel 64 (Intel).
http://software .intel.com/en-us/parallel/— сайт документации многоядерного программирования Intel (Intel).
http://software .intel.com/en-us/articles/porting-to-64-bit-intel-architecture/— Портирующий на 64-разрядную архитектуру Intel (Intel).
http://software .intel.com/en-us/articles/porting-code-to-intel-em64t-based-platforms/— информация о 64-разрядной оптимизации. Обратите внимание на то, что информацией о ABI в этом расположении является ориентированный Windows, таким образом, не применяются те части.
http://www .x86-64.org/documentation/assembly.html — Общая информация о 64-разрядном блоке Intel (x86-64.org).