Как ограничить адресное пространство 64-битного процесса менее 4G? - PullRequest
3 голосов
/ 22 марта 2011

Когда я выполняю 64-битный процесс и смотрю на /proc/[pid]/maps, компоновка показывает, что разделяемые библиотеки и секция стека находятся по большему адресу;например, следующее:

7ffff7ffc000-7ffff7ffd000 r--p 0001d000 08:03 16643      /lib/ld-2.11.2.so
7ffff7ffd000-7ffff7ffe000 rw-p 0001e000 08:03 16643      /lib/ld-2.11.2.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
7ffffffea000-7ffffffff000 rw-p 00000000 00:00 0         [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

Можно ли ограничить эти разделы меньшим пространством 4 ГБ, и это все равно должен быть 64-разрядный процесс, а не компилировать его в 32-разрядный процесс?

Ответы [ 5 ]

3 голосов
/ 22 марта 2011

Несмотря на то, что инструмент и концепция prelink(8) широко презираются (и, вероятно, не поставляются в вашем дистрибутиве), вы можете использовать его для связывания библиотек в двоичном коде с нехваткой памяти:

-r --reloc-only=ADDRESS
    Instead of prelinking, just relink given shared libraries
    to the specified base address.

Поскольку адрес, по которому библиотеки будут отображаться в процессе, определяется ld(1), вы можете изменить Makefile для вызова ld с другими значениями --section-start:

--section-start SECTION=ADDRESS
                           Set address of named section
-Tbss ADDRESS               Set address of .bss section
-Tdata ADDRESS              Set address of .data section
-Ttext ADDRESS              Set address of .text section
-Ttext-segment ADDRESS      Set address of text segment

Я переместил сегменты текста и bss вниз по младшим адресам:

$ gcc -Wl,-Ttext-segment=0x200000 -Wl,-Tbss=0x400000 -o broken broken.c
$ readelf -a broken
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x200450
...

Если вы можете переместить все разделы, предоставленные в исполняемом файле, с помощью --section-start и переместить библиотеки вниз с помощью prelink(8), вы сможете загрузить весь код размером менее 4 гигабайт.

0 голосов
/ 23 марта 2011

Основано на вашем комментарии:

Я использую llvm jit и заставляю его генерировать код x86 в 64-битном процесс. Когда я генерирую код для инструкция "printf" вызовет функция в libc; но размер регистрация стала 32-битной, я не могу добраться до адреса (адрес libc в 7fffxxxxxxxx.)

... простого ограничения библиотек 32-битными адресами совершенно недостаточно. С одной стороны, соглашение о вызовах отличается в 64-битном режиме - 64-битный printf() ожидает свой первый параметр в %rdi, но 32-битный код вместо этого поместит его в стек.

Вам потребуется, чтобы сгенерированный код вызывал оболочку printf(), которая правильно устанавливает параметры для вызова реального printf(). Вы можете поместить эту оболочку в область MAP_32BIT.

0 голосов
/ 22 марта 2011

Я не знаю какого-либо общего ответа на этот вопрос, но если вы пропатчили libc и ядро, вы можете изменить их так, чтобы они никогда не создавали адреса выше 4G. Тогда ваш код режима пользователя не должен был бы изменяться вообще, любой сгенерированный адрес, например, через malloc (), никогда не был бы выше 4G.

Это также может быть наиболее удобно, если на компьютере, на котором вы запускали ядро, не более 4 ГБ объединенной подкачки и физической памяти.

Одна вещь, которую нужно попробовать, это отключить overcommit. Согласно этой странице , если вы установите для overcommit значение 2 (выкл) и используете, скажем, 512 мегабайт физической памяти ( включая swap), то ваше адресное пространство никогда не должно выходить за пределы что может содержать 32-битный адрес. Может быть также быть какое-то смещение, добавленное к 64-битным адресам, но в этом случае вы сможете найти его и удалить.

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

0 голосов
/ 22 марта 2011

Может быть, это то, что вы ищете:

man setrlimit
0 голосов
/ 22 марта 2011

Видя, что за меня проголосовали, я пошел и исправил ответ.

Для Microsoft Visual Studio C ++, если компилятор является 32-разрядным компилятором, флаг / LARGEADDRESSAWARE устанавливает виртуальное адресное пространство от 2 до 3 ГБ, это только при работе в 32-разрядной ОС.

При запуске той же 32-битной программы на 64-битной ОС приложению будет предоставлен доступ ко всем 4 ГБ виртуального адресного пространства. Для 64-битных компиляторов флаг / LARGEADDRESSAWARE включен по умолчанию.

Видение этого вопроса для GCC Я думаю, это не важно для вашей проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...