Если единственное различие между 32-битными и 64-битными процессорами - это их размер регистра, то почему 32-битные программы должны быть перезаписаны для 64-битной платформы?

Какова фактическая разница в исходном коде при написании 64-битной программы? Например, только сборка отличается? Это не похоже на 64-битную версию С++. Если это так просто, как опция в компиляторе, чем то, как больше программ не изначально 64 бит? Если единственная разница в 32-битном и 64-битном процессорах - это размер регистра, я не вижу, как это влияет на программу (кроме возможности иметь больше памяти).

Ответ 1

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

Некоторые программы, возможно, придется перекомпилировать, оставив исходный код без изменений. Некоторые среды программирования, которые используют промежуточное представление и компиляцию "точно в срок", позволяют одинаковым двоичным файлам работать без изменений в 32- или 64-разрядной ОС.

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

Ответ 2

Типичными ошибками для 32-битного/64-битного портирования являются:

  • Неявное предположение программиста, что sizeof(void*) == 4 * sizeof(char).
    Если вы делаете это предположение и, например, распределите массивы таким образом ( "Мне нужно 20 указателей, поэтому я выделяю 80 байтов" ), ваш код разбивается на 64-битный, поскольку это вызовет переполнение буфера.

  • "Котенок-убийца" (re @SK-logic), int x = (int)&something; (и наоборот, void* ptr = (void*)some_int). Опять же предположение о sizeof(int) == sizeof(void*). Это не вызывает переполнения, но теряет данные - более высокий 32-разрядный указатель, а именно:

    Обе эти проблемы относятся к классу, называемому псевдонимом типов (предполагая идентичность/взаимозаменяемость/эквивалентность на уровне двоичного представления между двумя типами), и такие предположения являются общими; например, на UN * X, если time_t, size_t, off_t int, или в Windows, HANDLE, void* и long являются взаимозаменяемыми и т.д.

    /li >
  • Предположения о структуре данных/использовании пространства стека (см. также ниже). В коде C/С++ локальные переменные выделяются в стеке, а используемое там пространство различается между 32-битным и 64-битным режимами из-за указанной ниже точки и из-за разных правил для передачи аргументов (32 бит x86, как правило, в стеке, 64 бит x86 частично в регистрах). Код, который просто уходит со стеком на 32 бит по умолчанию, может привести к сбою на 64-разрядной версии.
    Это относительно легко определить как причину сбоя, но в зависимости от конфигурации приложения, возможно, трудно исправить.

  • Сроки разницы между 32-битным и 64-битным кодом (из-за разных размеров кода/следов кеша или различных характеристик/шаблонов доступа к памяти или различных соглашений о вызовах) могут нарушить "калибровку". Скажем, for (int i = 0; i < 1000000; ++i) sleep(0);, вероятно, будет иметь разные тайминги для 32-битных и 64-битных...

  • Наконец, ABI (Application Binary Interface). Там обычно большие различия между 64-битной и 32-битной средами, чем размер указателей...
    В настоящее время существуют две основные "ветки" из 64-битных сред, IL32P64 (то, что использует Win64 - int и long int32_t, только uintptr_t/void* - uint64_t, говорящий в терминах целых чисел размера от <stdint.h>) и LP64 (то, что использует UN * X - int - это int32_t, long is int64_t и uintptr_t/void* is uint64_t), но там есть "подразделения" другие правила выравнивания - в некоторых средах предполагается, что long, float или double выровнены по их соответствующим размерам, в то время как другие предполагают, что они выровняются по кратным четырем байтам. В 32-битном Linux они выравнивают все по четыре байта, в то время как в 64-битной Linux float выравнивается в четыре, long и double в восьмибайтовых кратных.
    Следствием этих правил является то, что во многих случаях bith sizeof(struct { ...}) и смещение членов структуры/класса различаются между 32-битными и 64-битными средами, даже если объявление типа данных полностью идентично.
    Помимо влияния на распределение массивов/векторов эти проблемы также влияют на данные в/выходе, например. через файлы - если 32-разрядное приложение записывает, например. struct { char a; int b; char c, long d; double e } к файлу, в котором выполняется повторное компиляция того же приложения для 64 бит, результат не будет полным, на что надеялся.
    Только что приведенные примеры относятся только к примитивам языка (char, int, long и т.д.), Но, конечно, влияют на все типы типов данных библиотеки, зависящих от платформы/времени выполнения, независимо от того, size_t, off_t, time_t, HANDLE, по существу, любой нетривиальный struct/union/class... - поэтому пространство для ошибки здесь велико,

И тогда есть различия на нижнем уровне, которые вступают в игру, например. для ручного оптимизированного монтажа (SSE/SSE2/...); 32 бит и 64 бит имеют разные (числа) регистров, разные правила передачи аргументов; все это сильно влияет на то, как такие оптимизации выполняются, и весьма вероятно, что, например, Код SSE2, который дает лучшую производительность в 32-битном режиме, должен быть переписан/нуждается в улучшении, чтобы обеспечить максимальную производительность 64-битного режима.

Также существуют ограничения на дизайн кода, которые очень различны для 32-битных и 64-битных, особенно для распределения/управления памятью; приложение, которое было тщательно закодировано, чтобы "максимизировать ад из памяти, которую он может получить в 32 бит", будет иметь сложную логику о том, как/когда выделять/освобождать память, использование файлов с памятью, внутреннее кэширование и т.д. - большая часть из них будет быть вредным в 64 бит, где вы могли бы "просто" воспользоваться огромным доступным адресным пространством. Такое приложение может перекомпилировать для 64-битной просто отлично, но хуже, чем какая-то "старинная простая устаревшая версия", в которой не было оптимизаций макси-32-битных головок.

Итак, в конечном итоге, это также касается улучшений/выигрышей и того, что там, где больше работы, частично в программировании, отчасти зависит от дизайна/требований. Даже если ваше приложение чисто перекомпилирует как в 32-битной, так и в 64-битной среде и проверяется на обоих, это действительно выигрывает от 64-битного? Существуют ли какие-либо изменения, которые могут/должны быть выполнены для логики кода, чтобы сделать его более быстрым или быстрее работать на 64-битном уровне? Можете ли вы сделать эти изменения, не нарушая совместимость с 32-разрядной обратной связью? Без отрицательных воздействий на 32-битную цель? Где будут улучшения и сколько вы можете получить?
Для большого коммерческого проекта ответы на эти вопросы часто являются важными маркерами на дорожной карте, потому что отправной точкой является какой-то существующий "создатель денег"...

Ответ 3

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

Ответ 4

Для правильно написанной программы на скомпилированном языке все, что нужно сделать, это перекомпиляция. Единственные программы, которые должны быть "перезаписаны" (или даже изменены), - это те, которые были плохо написаны для начала и которые делают множество фальшивых предположений и, вероятно, вызывают поведение undefined, такое как wild.

Для языков, которые не скомпилированы в машинный код, но интерпретируются или выполняются в некоторой полуинтерпретированной/байт-кодовой/JIT-форме, на самом деле довольно сложно сделать программу, которая разбивается при переносе с 32-разрядной машины на 64- бит один. Вероятно, наиболее вероятный способ "разбить" - это просто использовать больше памяти и, возможно, иссякнуть.

Ответ 5

Указатели обычно 64-разрядные в 64-разрядных системах.