Может ли компилятор C генерировать исполняемый файл 64-битного типа, где указатели являются 32-битными?


Большинство программ хорошо вписывается в адресное пространство

Существуют ли компиляторы / платформы, где я могу использовать регистры x64 и специальные инструкции, но сохранять 32-битные указатели для экономии памяти?

Можно ли сделать это прозрачно на устаревшем коде? Какой переключатель для этого нужен?

Или

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

10 18

10 ответов:

Простой способ обойти это, если бы у вас было только несколько типов для ваших структур, на которые вы указываете. Затем вы можете просто выделить большие массивы для ваших данных и выполнить индексацию с помощью uint32_t.

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

Технически компилятор может сделать это. АФАИК, на практике это не делается. Он был предложен для gcc (даже с патчем здесь: http://gcc.gnu.org/ml/gcc/2007-10/msg00156.html ), но никогда не интегрировались (по крайней мере, это не было задокументировано в последний раз, когда я проверял). Я понимаю, что для работы ему также необходима поддержка ядра и стандартной библиотеки (то есть ядро должно было бы настроить вещи таким образом, который в настоящее время невозможен и использовать существующий 32 или 64-битный ABI связаться с ядром было бы невозможно).

Стоит отметить, что в разработке для linux есть ABI, X32, который позволяет построить двоичный файл x86_64, использующий 32-битные индексы и адреса.

Только относительно новый, но тем не менее интересный.

Http://en.wikipedia.org/wiki/X32_ABI

Какие именно "64-битные функции" вам нужны, разве это не немного расплывчато?

Нашел это, пока искал ответ сам.: http://www.codeproject.com/KB/cpp/smallptr.aspx

Также поднимите обсуждение внизу...

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

На x86, нет. На других процессорах, таких как PowerPC, это довольно распространено - 64-битные регистры и инструкции доступны в 32-битном режиме, тогда как с x86 это имеет тенденцию быть "все или ничего".

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

Насколько мне известно, 32-битные указатели в 64-битном машинном коде иметь невозможно.

Боюсь, что если вы обеспокоены размером указателей, у вас могут возникнуть более серьезные проблемы. Если количество указателей будет исчисляться миллионами или миллиардами, вы, вероятно, столкнетесь с ограничениями в ОС Windows, Прежде чем фактически исчерпаете физическую или виртуальную память.

Марк Русинович написал большую статью, связанную с этим, под названием Раздвигая границы Windows: Виртуальная память.

Это зависит от платформы. В Mac OS X первые 4 ГБ адресного пространства 64-битного процесса зарезервированы и не привязаны, предположительно в качестве функции безопасности, поэтому никакое 32-битное значение никогда не будет ошибочно за указатель. Если вы попытаетесь, может быть, есть способ победить это. Я обошел его однажды, написав класс c++ "указатель", который добавляет 0x100000000 к сохраненному значению. (Это было значительно быстрее, чем индексирование в массив, что также требует нахождения базового адреса массива и умножение перед сложением.)

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

Никаких изменений в программе не требуется, если вы не хотите использовать 64-разрядные и 32-разрядные указатели одновременно. В этом случае вы возвращаетесь к старым плохим временам, когда указатели near и far имели место.

Кроме того, вы наверняка нарушите совместимость ABI с API, которые принимают указатели к указателям.

Я думаю, что это будет похоже на MIPS N32 ABI: 64-разрядные регистры с 32-разрядными указателями.

В N32 ABI все регистры являются 64-разрядными (поэтому требуется процессор MIPS64). Но адреса и указатели являются только 32-разрядными (при хранении в памяти), что уменьшает объем памяти. При загрузке 32-разрядного значения (например, указателя) в регистр оно расширяется по знаку до 64-разрядного. Когда процессор использует указатель/адрес для загрузки или хранения, используются все 64 бита (процессор не знает об этом n32-ess SW). Если ваша ОС поддерживает программы n32 (возможно, ОС также следует модели n32 или это может быть правильная 64-разрядная ОС с добавленной поддержкой n32), она может найти всю память, используемую приложением n32, в подходящей памяти (например, Нижний 2GB и верхний 2GB, виртуальные адреса). Единственная проблема с этой моделью заключается в том, что при сохранении регистров в стеке (вызовы функций и т. д.) используются все 64-разрядные данные, в N32 ABI отсутствует 32-разрядная модель данных.

Вероятно, такой ABI может быть реализовано и для x86-64.

Linux теперь имеет довольно полную поддержку x32 ABI, которая делает именно то, что просит asker, фактически она частично поддерживается в качестве конфигурации под операционной системой Gentoo. Я думаю, что этот вопрос должен быть рассмотрен в свете развития недовольства.