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

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

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

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


person Huygens    schedule 11.10.2011    source источник


Ответы (3)


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

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

Распределение снизу вверх является запасным вариантом. Он используется, если:

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

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

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

person caf    schedule 12.10.2011
comment
Спасибо за такое понимание. Я собираюсь просмотреть всю информацию, которую вы мне указали. - person Huygens; 12.10.2011
comment
так может не дать наш собственный начальный адрес? - person Kumar Sukhani; 07.10.2014

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

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

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

person ninjalj    schedule 11.10.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;
}

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

person Ethereal    schedule 11.10.2011
comment
Спасибо за информацию, аналогичный прием используется в коде с System V IPC, мы задаем специальный адрес при вызове shmat. См. выдержку из справочной страницы: Если shmaddr не равен NULL и SHM_RND указан в shmflg, присоединение происходит по адресу, равному shmaddr, округленному в меньшую сторону до ближайшего кратного SHMLBA. В противном случае shmaddr должен быть выровненным по странице адресом, по которому происходит присоединение. - person Huygens; 12.10.2011
comment
Трудность заключается в том, чтобы определить правильный адрес, например тот, который вы предлагаете: 0x700000000. И хотелось бы иметь возможность четко обосновать свой выбор. - person Huygens; 12.10.2011