Как работает VirtualAlloc?

Тема в разделе "WASM.WIN32", создана пользователем Deader, 1 авг 2011.

  1. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    Как работает VirtualAlloc в WinXP 32bit? Выделяет память в сегменте кучи и создает в LDT дескриптор этого сегмента? Или выделяет в сегменте данных? Если в сегменте данных, то тогда записанный в дескрипторе(описывающем сегмент данных) размер сегмента по умолчанию для всех 32-битных процессов должен быть 2Гб, но, насколько я знаю, это не так, т.е. в дескрипторе записан реальный размер сегмента данных. Проясните, плиз, этот момент.
     
  2. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
  3. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    qwe8013, ну в принципе я все это читал уже очень давно. Но как сие проливает свет на мой вопрос? Хотя бы ответьте на 2 вопроса - в виндовозе есть дескриптор кучи? Размер сегмента данных, прописанный в его дескрипторе - это 2Гб или это реальный размер сегмента данных?
     
  4. XshStasX

    XshStasX New Member

    Публикаций:
    0
    Регистрация:
    9 авг 2008
    Сообщения:
    991
  5. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
    1) Что вы понимаете под дескриптором кучи?
    2) Размер сегмента данных, прописанный в его дескрипторе, на сколько я помню - 4ГБ.
    А вообще выделение памяти в Windows не имеет отношения к LDT или GDT, я же сказал, прочтите о страничной адресации.
     
  6. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    1) Под дескриптором кучи я понимаю стандартный дескриптор, описывающий некий сегмент памяти, называемый(еще со времен DOS) кучей. Дескриптор этот хранится в локальной таблице дескрипторов процесса(LDT) и его селектор можно загрузить в один из сегментных регистров. Лимит, прописанный в этом дескрипторе, хранит размер этого сегмента(а не 4Гб). В этом сегменте размещается динамически выделяемая память по VirtualAlloc, GetMem etc.
    2) Если размер сегмента данных равен 4Гб, то где хранится его реальный размер? И каким образом одновременно сосуществуют десятки процессов с сегментами данных по 4Гб у каждого? Получается, что у всех запущенных процессов сегменты данных перекрывают всю физическую память, накладываясь друг на друга?
     
  7. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    И еще, можно ли изменить размер сегмента(данных) и как можно(и можно ли) из ринг3 прочитать свой LDT? Или есть отладчик типа ольки или ядерной сиськи, в котором можно посмотреть свой LDT? Я просто не могу понять - если виндовоз тупо везде пишет 4Гб, то зачем вообще нужны биты Limit в дескрипторе. Насколько я понимаю - это аппаратная вещь x86...
     
  8. qwe8013

    qwe8013 New Member

    Публикаций:
    0
    Регистрация:
    28 май 2009
    Сообщения:
    198
    По умолчанию LDT у всех процессов отсутствует (ну или пустой, точно не помню). Дескрипторы сегментов памяти, к выделению памяти в Windows не имеют никакого отношения, страничная же адресация.

    GetThreadSelectorEntry
     
  9. izl3sa

    izl3sa New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2010
    Сообщения:
    164
    Адрес:
    Spb
    2Deader
    Виндовс использует плоскую модель памяти, что подразумевает практически неиспользование возможностей сегментации x86 архитектуры. Код и данные описываются плоскими 4Гб сегментами, отдельно для r0 и r3. Также специализированные сегменты служат для доступа к TEB и PCR в r3 и r0.

    ;
    ; Gdt Descriptor Offset Definitions
    ;

    KGDT_R3_DATA equ 00020H
    KGDT_R3_CODE equ 00018H
    KGDT_R0_CODE equ 00008H
    KGDT_R0_DATA equ 00010H
    KGDT_R0_PCR equ 00030H
    KGDT_STACK16 equ 000F8H
    KGDT_CODE16 equ 000F0H
    KGDT_TSS equ 00028H
    KGDT_R3_TEB equ 00038H
    KGDT_DF_TSS equ 00050H
    KGDT_NMI_TSS equ 00058H
    KGDT_LDT equ 00048H


    >> Получается, что у всех запущенных процессов сегменты данных перекрывают всю физическую память, накладываясь
    >> друг на друга?

    x86 архитектура предоставляет два уровня защиты - страничный (paging) и сегментация. Разделение памяти между процессами реализовано на уровне страничной адресации. Наборами страниц для каждого процесса управляет ядро, оно же переключает cr0 при смене контекста. qwe8013 вам уже посоветовал перечитать материалы с сайта, последуйте его совету.
     
  10. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    CR3
     
  11. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    Например, мы имеем 4-х байтный указатель Р на память, выделенную по VirtualAlloc. В контексте нашего процесса в CR3 есть физический адрес каталога страниц нашего процесса. В старших 10 битах(дополненных двумя младшими нулями) переменной Р содержится номер дескриптора PDE, в этом дескрипторе хранится физический адрес подчиненной таблицы страниц PTE. В средних 10битах(21-12), дополненных двумя младшими нулями, переменной Р хранится индекс элемента PTE, а уже в этом элементе хранится физический адрес страницы в памяти. В младших 12 битах переменной Р хранится смещение внутри этой страницы до нашего участка памяти, выделенного по VirtualAlloc. Я правильно понимаю? А где хранится размер выделенного блока памяти? И потом, страницы, в которых расположена память, всегда следуют непрерывно друг за другом в физической памяти или могут располагаться в физической памяти(я не говорю про своп) беспорядочно? Могут ли в одной странице хранится несколько блоков памяти(напр, по 10 байтов), выделенных по VirtualAlloc? PDE выделяется только для каждого процесса или для каждого потока?
     
  12. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Вот как это выглядит в линуксе:
    http://linux-mm.org/PageTableStructure

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

    PDE, PTE и прочие структуры описывают раскладку памяти процесса. Но важный момент: возможно существование нескольких PTE адресующих один и тот же физический фрейм (для x86 это 1G, 2/4M, 4K) -- в том случае, если используется shared-memory.
     
  13. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    Т.е. страничная адресация - это аппаратная вещь, и при этом размер блоков памяти аппартно нигде не хранится(эта роль возложена на системные программы)?
     
  14. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Страничная адресация (paging) это фишка MMU. MMU может быть как программным, так и аппаратным. В случае x86 это конечно аппаратная вещь. Также, в зависимости от режима работы процессора {X86; X86 + PAE, X86_64}, различаются размеры адресуемых через PTE фреймов -- {4M, 4k; 2M, 4k; 1G, 2M, 4k}. Размер же выделенной через VirtualAlloc области адресного пространства хранится где-то во внутренних структурах ядерного менеждера памяти, который и ведёт учёт свободных фреймов. При этом, понятно, что выделенная область может включать в себя более одного физического фрейма.
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Deader
    Шутник, ты когда в последний раз в описание VirtualAlloc заглядывал?! Она выделяет память только страницами - запросишь 10 байт - получишь целую страницу в 4К, запросишь 4096+1 - получишь две страницы

    Вирт.память принадлежит процессу в целом. А потоки довольствуются лишь "переданными в их владение" индивидуальными стеками

    Ес-но. При страничной адресации процу нужно лишь транслировать лин.\вирт.адрес страницы в физический и кроме заданного размера страницы и валидных PDE\PTE его ничто другое не волнует.
     
  16. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    Если MMU - аппаратная вещь, то как и где он хранит размер блока памяти(или количество страниц)? Фреймы для выделенной области памяти всегда расположены непрерывно друг за другом?
     
  17. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    Да, это я маху дал :)
    Значит при страничной адресации размер блока памяти(или количество страниц) нигде не хранится? При сегментной адресации все сделано по-человечески - размер сегмента хранится в его дескрипторе, а здесь как-то странно: таблицы дескрипторов страниц - аппаратная вещь и при этом размер памяти отдается на откуп программисту. Как же тогда процессор генерирует исключение при обращении за предел выделенного блока - какой же это тогда защищенный режим?
     
  18. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Если для адреса нет PTE или он !present, будет #PF.
     
  19. Deader

    Deader New Member

    Публикаций:
    0
    Регистрация:
    31 июл 2011
    Сообщения:
    96
    А вот тут непонятно. В линейном адресе(в моей переменной) хранится индекс PTE, т.е. индекс элемента PTE, указывающего только на одну страницу. Это что? Получается что если я выделяю память, накладывающуюся на несколько страниц, то в PDE добавляются дескрипторы для всех этих страниц, а в PTE - их адреса, и номера этих PDE элементов нигде не хранятся? Или вся таблица PTE описывает только одну область памяти(непохоже, иначе для чего тогда в переменной нужно хранить индекс PTE)?
     
  20. gorodon

    gorodon New Member

    Публикаций:
    0
    Регистрация:
    19 окт 2009
    Сообщения:
    301
    Deader, Руссинович,Соломон "Внутреннее устройство Windows", глава 7 "Управление памятью".