Лучший вариант: попросите автора этой программы с ошибками исправить свой код, чтобы он был 64-битным, или используйте Linux x32 для 64-битных регистров, но 32-битных указателей.
AFAIK, нет простого способа сделать именно то, что вы просите, с помощью обычного glibc malloc . Замена malloc
/ free
на mmap(MAP_32BIT)
, вероятно, будет работать, но будет ужасно для небольших распределений, потому что она может выделяться только в 4k чанках.
mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_32BIT, -1, 0)
/ munmap
. Это не заменяющая вставка, потому что некоторый код, вероятно, нуждается в указателях, которые совместимы с free
.
Или, если вы можете найти пользовательский malloc
, который использует MAP_32BIT
в качестве обходного пути для программного обеспечения с ошибками, которое не является 64-разрядным, вы можете использовать его в качестве замены. Или изменить пользовательскую библиотеку malloc, например tcmalloc
, чтобы добавить MAP_32BIT
, может быть намного проще, чем создать весь пользовательский gcc.
@ Basile Starynkevitch предлагает, возможно, использовать mmap(MAP_FIXED|MAP_NORESERVE)
для отображения огромного диапазона, так что все, что осталось, это младшие 32 бита. (Тогда никогда не трогай это отображение). Диапазон адресов виртуальной памяти в пользовательском пространстве Но это сработает только в том случае, если это будет сделано до загрузки каких-либо библиотек по старшим адресам ( Как ограничить адресное пространство 64-битного процесса менее 4G? предлагает возможный способ предварительной ссылки для загрузки библиотек по низким адресам).
MAP_FIXED
заменит существующие сопоставления в диапазоне, поэтому, возможно, вы захотите пропустить MAP_FIXED и просто дать ненулевой адрес подсказки и проверить, что он сопоставлен с запрошенным вами адресом.
Если у вас есть код, который не является 64-битным чистым для указателей, но вы все еще хотите использовать преимущества 64-битных регистров для эффективного [u]int64_t
, Linux xI ABI может быть именно тем, что вам нужно.
x32 - это ABI ILP32 для длинного режима x86-64, поэтому указатели size_t
и long
являются 32-разрядными типами, но 64-разрядными целочисленными типами, такими как long long
и uint64_t
могут использовать 64-битные регистры . Процессор работает в длинном 64-битном режиме, и ABI использует то же эффективное соглашение о вызовах регистра-аргументов, что и обычный x86-64 System V ABI.
Не не путать x32 с устаревшим 32-битным кодом i386 ABI . Они абсолютно не связаны. x32 - это небольшая модификация обычного x86-64 ABI.
Обычная причина использования x32 - меньший объем кэша с указательными структурами данных, увеличивающими попадания в кэш и экономящими пропускную способность памяти.
У меня нет времени выполнения Intel SVML для x32
Компилятор Intel и библиотеки, включая SVML, поддерживают x32 начиная с версии 16.0, см. Страница поддержки Intel x32 psABI . Если у вас версия старше 16.0, это может быть хорошей причиной для обновления.
(Похоже, на этой странице написано, что OpenMP может не поддерживаться на x32, по крайней мере, в версии 16.0. Это было бы проблемой, если я правильно понял. Текущий 19.01, возможно, он работает сейчас.)
Обратите внимание, что вывод asm для функции, которая добавляет два аргумента uint64_t
, идентичен для icc -O3 -mx32
и icc -O3 -m64
, оба из которых используют add rdi, rsi
/ mov rax,rdi
. (Хотя ICC хорош в автоматическом векторизации и автоматическом распараллеливании, очевидно, что он плохо определяет lea rax, [rdi+rsi]
как оптимизацию глазка, а при использовании mov
не следует собственному совету по оптимизации, сначала скопируйте, а затем уничтожьте копия для более эффективного mov-elission .)
Но в любом случае, текущие версии самого компилятора Intel определенно поддерживают x32; вывод asm из C ++ показывает, что uint64_t
равно unsigned long long
вместо unsigned long
.
Получение GCC для использования SVML:
GCC имеет опцию -mveclibabi=svml
, которая позволяет автоматически векторизовать с использованием функций SVML. Поэтому, если у x32 ICC есть проблема с использованием OpenMP для автоматического распараллеливания, вы можете попробовать GCC.
gcc -fopenmp -O3 -ffast-math -march=native -mveclibabi=svml
должно быть хорошо. (-ffast-math
аналогично тому, что ICC включает по умолчанию.)
Получение обычных 64-битных malloc
для возврата 32-битных указателей
В связи с этим: версия вопроса для OS X: Как выполнить 'malloc' в пределах первых 4 ГБ на x86_64 (там тоже нет простого пути).
Я не думаю, что glibc mallocесть опция для этого.
Можно было бы создать свой собственный glibc с небольшим изменением, если бы вы могли найти вызов mmap
, который malloc
использует для получения новых страниц из ОС, и добавитьфлаг MAP_32BIT
.
Поместите сопоставление в первые 2 гигабайта адресного пространства процесса.Этот флаг поддерживается только на x86-64, для 64-битных программ.Он был добавлен для того, чтобы стеки потоков могли быть выделены где-то в первых 2 ГБ памяти, чтобы улучшить производительность переключения контекста на некоторых ранних 64-битных процессорах
Если вы компилируете не PIEвыполнимый, разрыв должен быть уже ниже 32, поэтому вам не нужно останавливать glibc от использования brk()
для небольших выделений.
https://www.gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html перечисляет вещи, которые вы можете установить с помощьюmallopt
вызов или переменные окружения, например M_MMAP_THRESHOLD
.Если установить 4k, glibc всегда будет использовать mmap для распределений такого размера или больше.Но нет 32-битной опции.