ELF64 / x86_64 и начальный адрес сегмента отображения памяти (для общих объектов) - PullRequest
5 голосов
/ 11 октября 2011

Я написал несколько программ и обнаружил, что при компиляции в 64-битной сегмент отображения памяти (где хранятся, например, общие объекты и общая память) всегда находится где-то около 7f9aca84a000-7fff88400000, но никогда не бывает одинаковым.

Я хотел бы знать, существует ли фиксированный начальный адрес для этого сегмента памяти в архитектуре x86_64 (ELF64) или каков максимальный и минимальный диапазон для этого сегмента?

Вот почему я задаю этот вопрос. Мы переносим систему с Tru64 UNIX на Linux. Эта система использовала сложное сопоставление фиксированной памяти разделяемой памяти IPC Sys V, и она использует цепочечный список для перехода от структуры к другой в этом сегменте. Учитывая размер и сложность этого фрагмента кода, а также ограниченное время, которое у нас есть, мы пытаемся найти надежный способ исправить начало разделяемой памяти (эффективно используя shmat с указанным адресом для присоединения сегмента). ). С 64-битным виртуальное адресное пространство настолько велико (48-битные возможные адреса), что выбрать «безопасный» фиксированный адрес гораздо проще и менее рискованно, чем на 32-битном.

Ответы [ 3 ]

4 голосов
/ 11 октября 2011

Есть ли фиксированный начальный адрес для mmaped сегментов?

Нет. Linux поддерживает ASLR (рандомизация расположения адресного пространства), что означает, что адреса в программах имеют некоторый элемент случайности. Это должно сделать некоторые эксплойты менее успешными. Кроме того, вероятно, некоторые патчи ядра реализуют различные стратегии ASLR (они делают для обычных x86), подумайте о PaX, exec-shield, ...

Итак, если вы хотите использовать фиксированный адрес, вам может не понравиться MAP_FIXED, как рекомендовано @Ethereal.

4 голосов
/ 12 октября 2011

Схема отображения памяти x86-64 определена в arch/x86/mm/mmap.c.Как видите, используются две стратегии: сверху вниз и снизу вверх.

По умолчанию используется распределение сверху вниз.Он начинается на 128 МБ ниже максимального экстента стека (как определено ограничением стека), настраивается случайным смещением, а затем распределяет последующие отображения вниз в памяти оттуда.

Распределение снизу вверх - это запасной вариант,Он используется, если:

  • Ограничение стека не ограничено;
  • Процесс имеет индивидуальную настройку ADDR_COMPAT_LAYOUT;или
  • sysctl vm.legacy_va_layout не равен нулю.

При распределении снизу-вверх сопоставленные области распределяются постепенно по более высоким адресам, начиная с TASK_SIZE / 3, и настраиваются случайным образом.смещение.TASK_SIZE на x86-64 равно 0x800000000000, поэтому распределение снизу вверх начнется примерно с 0x2AAAAAAAAAAA.

Я бы предложил подходящее отверстие для ваших фиксированных отображений, которое должно быть в порядке при любой стратегии распределения:около 2 * TASK_SIZE / 3 - я бы использовал 0x500000000000.

3 голосов
/ 11 октября 2011

У меня нет прямого ответа для вас (пока!), Но я могу сказать, что у меня было успешное отображение памяти далеко за пределы более высоких диапазонов памяти. Например:

#include <stdio.h>
#include <sys/mman.h>
#include <stdint.h>

#define ADDRESS 0x700000000

int main(int argc, char *argv[]) {
    uint64_t *map = mmap((void *)ADDRESS, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);

    map[0] = 64;

    printf("Value: %lu\n", map[0]);

    munmap(map, 4096);

    return 0;
}

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

...