Как работает VirtualAlloc в WinXP 32bit? Выделяет память в сегменте кучи и создает в LDT дескриптор этого сегмента? Или выделяет в сегменте данных? Если в сегменте данных, то тогда записанный в дескрипторе(описывающем сегмент данных) размер сегмента по умолчанию для всех 32-битных процессов должен быть 2Гб, но, насколько я знаю, это не так, т.е. в дескрипторе записан реальный размер сегмента данных. Проясните, плиз, этот момент.
qwe8013, ну в принципе я все это читал уже очень давно. Но как сие проливает свет на мой вопрос? Хотя бы ответьте на 2 вопроса - в виндовозе есть дескриптор кучи? Размер сегмента данных, прописанный в его дескрипторе - это 2Гб или это реальный размер сегмента данных?
Deader Как выделяет не скажу, но думаю если посмотришь http://www.microsoft.com/resources/sharedsource/windowsacademic/researchkernelkit.mspx найдешь ответ.
1) Что вы понимаете под дескриптором кучи? 2) Размер сегмента данных, прописанный в его дескрипторе, на сколько я помню - 4ГБ. А вообще выделение памяти в Windows не имеет отношения к LDT или GDT, я же сказал, прочтите о страничной адресации.
1) Под дескриптором кучи я понимаю стандартный дескриптор, описывающий некий сегмент памяти, называемый(еще со времен DOS) кучей. Дескриптор этот хранится в локальной таблице дескрипторов процесса(LDT) и его селектор можно загрузить в один из сегментных регистров. Лимит, прописанный в этом дескрипторе, хранит размер этого сегмента(а не 4Гб). В этом сегменте размещается динамически выделяемая память по VirtualAlloc, GetMem etc. 2) Если размер сегмента данных равен 4Гб, то где хранится его реальный размер? И каким образом одновременно сосуществуют десятки процессов с сегментами данных по 4Гб у каждого? Получается, что у всех запущенных процессов сегменты данных перекрывают всю физическую память, накладываясь друг на друга?
И еще, можно ли изменить размер сегмента(данных) и как можно(и можно ли) из ринг3 прочитать свой LDT? Или есть отладчик типа ольки или ядерной сиськи, в котором можно посмотреть свой LDT? Я просто не могу понять - если виндовоз тупо везде пишет 4Гб, то зачем вообще нужны биты Limit в дескрипторе. Насколько я понимаю - это аппаратная вещь x86...
По умолчанию LDT у всех процессов отсутствует (ну или пустой, точно не помню). Дескрипторы сегментов памяти, к выделению памяти в Windows не имеют никакого отношения, страничная же адресация. GetThreadSelectorEntry
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 вам уже посоветовал перечитать материалы с сайта, последуйте его совету.
Например, мы имеем 4-х байтный указатель Р на память, выделенную по VirtualAlloc. В контексте нашего процесса в CR3 есть физический адрес каталога страниц нашего процесса. В старших 10 битах(дополненных двумя младшими нулями) переменной Р содержится номер дескриптора PDE, в этом дескрипторе хранится физический адрес подчиненной таблицы страниц PTE. В средних 10битах(21-12), дополненных двумя младшими нулями, переменной Р хранится индекс элемента PTE, а уже в этом элементе хранится физический адрес страницы в памяти. В младших 12 битах переменной Р хранится смещение внутри этой страницы до нашего участка памяти, выделенного по VirtualAlloc. Я правильно понимаю? А где хранится размер выделенного блока памяти? И потом, страницы, в которых расположена память, всегда следуют непрерывно друг за другом в физической памяти или могут располагаться в физической памяти(я не говорю про своп) беспорядочно? Могут ли в одной странице хранится несколько блоков памяти(напр, по 10 байтов), выделенных по VirtualAlloc? PDE выделяется только для каждого процесса или для каждого потока?
Вот как это выглядит в линуксе: http://linux-mm.org/PageTableStructure За размер выделенного блока памяти отвечает менеджер памяти (ядерный), который в свою очередь ведёт учёт всех страниц ОП и выделенных блоков для каждого процесса. PDE, PTE и прочие структуры описывают раскладку памяти процесса. Но важный момент: возможно существование нескольких PTE адресующих один и тот же физический фрейм (для x86 это 1G, 2/4M, 4K) -- в том случае, если используется shared-memory.
Т.е. страничная адресация - это аппаратная вещь, и при этом размер блоков памяти аппартно нигде не хранится(эта роль возложена на системные программы)?
Страничная адресация (paging) это фишка MMU. MMU может быть как программным, так и аппаратным. В случае x86 это конечно аппаратная вещь. Также, в зависимости от режима работы процессора {X86; X86 + PAE, X86_64}, различаются размеры адресуемых через PTE фреймов -- {4M, 4k; 2M, 4k; 1G, 2M, 4k}. Размер же выделенной через VirtualAlloc области адресного пространства хранится где-то во внутренних структурах ядерного менеждера памяти, который и ведёт учёт свободных фреймов. При этом, понятно, что выделенная область может включать в себя более одного физического фрейма.
Deader Шутник, ты когда в последний раз в описание VirtualAlloc заглядывал?! Она выделяет память только страницами - запросишь 10 байт - получишь целую страницу в 4К, запросишь 4096+1 - получишь две страницы Вирт.память принадлежит процессу в целом. А потоки довольствуются лишь "переданными в их владение" индивидуальными стеками Ес-но. При страничной адресации процу нужно лишь транслировать лин.\вирт.адрес страницы в физический и кроме заданного размера страницы и валидных PDE\PTE его ничто другое не волнует.
Если MMU - аппаратная вещь, то как и где он хранит размер блока памяти(или количество страниц)? Фреймы для выделенной области памяти всегда расположены непрерывно друг за другом?
Да, это я маху дал Значит при страничной адресации размер блока памяти(или количество страниц) нигде не хранится? При сегментной адресации все сделано по-человечески - размер сегмента хранится в его дескрипторе, а здесь как-то странно: таблицы дескрипторов страниц - аппаратная вещь и при этом размер памяти отдается на откуп программисту. Как же тогда процессор генерирует исключение при обращении за предел выделенного блока - какой же это тогда защищенный режим?
А вот тут непонятно. В линейном адресе(в моей переменной) хранится индекс PTE, т.е. индекс элемента PTE, указывающего только на одну страницу. Это что? Получается что если я выделяю память, накладывающуюся на несколько страниц, то в PDE добавляются дескрипторы для всех этих страниц, а в PTE - их адреса, и номера этих PDE элементов нигде не хранятся? Или вся таблица PTE описывает только одну область памяти(непохоже, иначе для чего тогда в переменной нужно хранить индекс PTE)?