Добавлен: 29.10.2018
Просмотров: 48028
Скачиваний: 190
11.2. Программирование в Windows
951
Таблица 11.6. Разделы реестра в Windows. HKLM — это сокращение
для HKEY_LOCAL_MACHINE
Файл
раздела
Имя после
монтирования
Применение
STEM
HKLM \SYSTEM
Информация о конфигурации операционной систе-
мы (используется ядром)
HARDWARE
HKLM \HARDWARE
Раздел в памяти, в котором записано обнаруженное
оборудование
BCD
HKLM \BCD*
База данных конфигурации загрузки
SAM
HKLM\SAM
Информация об учетных записях локальных пользо-
вателей
SECURITY
HKLM\SECURITY
Информация службы lsass об учетных записях
и прочая информация безопасности
DEFAULT
HKEY_USERS\DEFAULT
Раздел по умолчанию для новых пользователей
NTUSER.DAT
HKEY_USERS<user id>
Раздел для пользователей, хранится в домашнем
каталоге
SOFTWARE
HKLM \SOFTTWARE
Зарегистрированные в СОМ классы приложений
COMPONENTS
HKLM \COMPONENTS
Манифесты и зависимости для компонентов системы
До введения реестра конфигурационная информация в Windows хранилась в сотнях
инициализационных файлов
.ini
, разбросанных по всему диску. Реестр собрал эти фай-
лы в центральное хранилище, которое доступно на ранней стадии процесса загрузки
системы. Это важно для реализации функции Plug-and-Play. Однако по мере развития
Windows реестр стал очень неорганизованным. Плохо определены соглашения о том,
как должна быть организована информация по конфигурации, многие приложения
демонстрируют непродуманный подход. Большинство пользователей и приложений,
а также все драйверы работают с полными привилегиями и часто напрямую модифици-
руют в реестре системные параметры, при этом они иногда конфликтуют друг с другом
и дестабилизируют систему.
Реестр — это странная помесь файловой системы и базы данных (причем он отличается
и от той и от другой). Для описания реестра написаны целые книги (Born, 1998; Hipson,
2002; Ivens, 1998), возникло даже множество компаний, которые продают специальное
программное обеспечение для того, чтобы справиться со сложностью реестра.
Для изучения реестра в Windows есть программа с графическим интерфейсом под
названием regedit, которая позволяет вам открывать и изучать каталоги (называе-
мые ключами) и элементы данных (называемые значениями). Новый язык сценариев
PowerShell
компании Microsoft также может быть полезным для просмотра ключей
и значений реестра (в виде каталогов и файлов). Более интересным инструментом
является procmon, который имеется на веб-сайте компании Microsoft по адресу:
www.
microsoft.com/technet/sysinternals
.
Procmon наблюдает за всеми происходящими в системе обращениями к реестру, что
чрезвычайно познавательно. Вы увидите, что некоторые программы обращаются к од-
ним и тем же ключам десятки тысяч раз.
В полном соответствии со своим названием программа regedit позволяет пользователям
редактировать реестр. Однако будьте при этом очень осторожны: очень легко сделать
952
Глава 11. Изучение конкретных примеров: Windows 8
так, что ваша система перестанет загружаться, либо повредить установленные прило-
жения настолько, что для их восстановления потребуется много шаманства. Компания
Microsoft пообещала в следующих версиях почистить реестр, но на данный момент это
просто большая свалка — гораздо более сложная, чем конфигурационная информация
систем UNIX. Сложность и хрупкость реестра привела разработчиков новых операци-
онных систем, в частности iOS и Android, к уклонению от чего-либо подобного.
Реестр доступен программисту Win32. Имеются вызовы для создания и удаления клю-
чей, поиска значений в ключах и т. д. Некоторые из наиболее полезных перечислены
в табл. 11.7.
Таблица 11.7. Некоторые вызовы Win32 API для использования
при работе с реестром
Функция Win32 API
Описание
RegCreateKeyEx
Создать новый ключ реестра
RegDeleteKey
Удалить ключ реестра
RegOpenKeyEx
Открыть ключ, чтобы получить его описатель
RegEnumKeyEx
Перечислить подключи того ключа, описатель которого задан
RegQueryValueEx
Поиск значения в ключе
Когда система выключается, большая часть информации реестра сохраняется на диске
в разделах. Поскольку их целостность критична для правильного функционирования
системы, автоматически выполняется резервное копирование и сделанные в мета-
данных записи сбрасываются на диск (во избежание повреждения в случае отказа
системы). Потеря реестра приводит к необходимости повторной установки всего про-
граммного обеспечения системы.
11.3. Структура системы
В предыдущих разделах мы изучали Windows Vista с точки зрения программиста, кото-
рый пишет код для пользовательского режима. Теперь мы собираемся заглянуть «под
капот», чтобы увидеть внутреннюю организацию системы, понять, что делают разные
ее компоненты, как они взаимодействуют друг с другом и с программами пользователя.
Это та часть системы, с которой работают программисты, пишущие код низкого уровня
для пользовательского режима (такой, как подсистемы и собственные службы), а также
программисты, которые пишут драйверы устройств.
Несмотря на то что есть много книг о том, как использовать Windows, гораздо меньше
таких книг, которые описывают, как она устроена. Одно из самых лучших мест, где мож-
но найти дополнительную информацию по этой теме, — это книга «Microsoft Windows
Internals», 6-е издание, части 1 и 2 (Russinovich and Solomon, 2012).
11.3.1. Структура операционной системы
Как описывалось ранее, операционная система Windows Vista состоит из множества
уровней (см. рис. 11.2). В последующих разделах мы погрузимся в самые нижние уровни
операционной системы — те, которые работают в режиме ядра. Центральный уровень —
11.3. Структура системы
953
это само ядро NTOS, которое загружается из файла
ntoskrnl.exe
(при загрузке Windows).
NTOS имеет два уровня: исполнительный (executive), в котором содержится большая
часть служб, и меньший по размеру уровень, который называется ядром (kernel) и реа-
лизует планирование потоков и абстракции синхронизации (ядро внутри ядра?), а также
реализует обработчики ловушек, прерывания и прочие аспекты управления процессором.
Деление NTOS на ядро и исполнительную систему отражает общность NT с системой
VAX/VMS. Операционная система VMS, которая также была разработана Катлером,
имела четыре аппаратно обеспечиваемых уровня: пользовательский, супервизора,
исполнительный и уровень ядра (в соответствии с четырьмя режимами защиты, обе-
спечивавшимися архитектурой процессора VAX). Процессор Intel также поддерживает
четыре кольца защиты, однако в некоторых процессорах (для которых первоначально
разрабатывалась NT) этого не было, поэтому уровни ядра и исполнительный представ-
ляют собой программную абстракцию и такие функции, которые VMS предоставляет
в режиме супервизора (например, очередь печати), в NT реализованы как службы
пользовательского режима.
Уровни режима ядра системы NT показаны на рис. 11.4. Уровень ядра NTOS показан
над исполнительным уровнем, поскольку он реализует механизмы ловушек и прерыва-
ний, которые используются для перехода из пользовательского режима в режим ядра.
Верхний уровень — это системная библиотека
ntdll.dll
, которая фактически работает
в пользовательском режиме. Эта системная библиотека содержит некоторые вспомога-
тельные функции для библиотек компилятора (времени исполнения и низкого уровня)
аналогично библиотеке
libc
системы UNIX.
Ntdll.dll
содержит также специальные точки
входа, используемые ядром для инициализации потоков, а также диспетчеризации ис-
ключений и вызовов APC (Asynchronous Procedure Calls — асинхронные вызовы про-
цедур) пользовательского режима. Поскольку системная библиотека так тесно интегри-
рована в работу ядра, то каждый созданный NTOS процесс пользовательского режима
имеет отображение на
ntdll
по одному и тому же фиксированному адресу. Когда NTOS
инициализирует систему, он создает объект-сегмент, который будет использоваться для
отображения
ntdll
, а также записывает адреса точек входа
ntdll
, используемых ядром.
Ниже уровня ядра и исполнительного уровня NTOS находится программное обеспе-
чение под названием HAL (Hardware Abstraction Layer — уровень абстрагирования
оборудования), который абстрагирует низкоуровневые детали оборудования (вроде
доступа к регистрам устройств и работы в режиме DMA), а также то, как прошивка
материнской платы представляет конфигурационную информацию и работает с раз-
личными чипсетами (например, с контроллерами прерываний).
Самым нижним уровнем программного обеспечения является гипервизор, который
в Windows называется Hyper-V. Гипервизор является дополнительным средством
(на рис. 11.4 не показано). Он доступен на многих версиях Windows, включая про-
фессиональные клиентские версии для настольных систем. Гипервизор перехватывает
многие привилегированные операции, выполняемые ядром, и эмулирует их таким
образом, чтобы позволить на одной и той же машине одновременно работать несколь-
ким операционным системам. Каждая операционная система работает на собственной
виртуальной машине, которая в Windows называется разделом (partition). Гипервизор
использует возможности в архитектуре оборудования для защиты физической памяти
и обеспечения изолированности разделов друг от друга. Операционная система, запу-
скаемая поверх гипервизора, выполняет потоки и обрабатывает прерывания абстрак-
ций физических процессоров, называемых виртуальными процессорами. Гипервизор
планирует работу виртуальных процессоров на физических процессорах.
954
Глава 11. Изучение конкретных примеров: Windows 8
Рис. 11.4. Организация режима ядра Windows
Основная (или корневая — root) операционная система запускается в корневом раз-
деле. Она предоставляет множество служб другим (гостевым) разделам. Некоторые
наиболее важные службы обеспечивают интеграцию гостевых разделов с совместно
используемыми устройствами, например с сетевыми устройствами и устройствами
графического пользовательского интерфейса. Хотя при запуске Hyper-V корневой
операционной системой должна быть Windows, в гостевых разделах могут запускать-
ся и другие операционные системы, например Linux. Гостевая операционная система
может работать весьма посредственно, пока не будет модифицирована (то есть пара-
виртуализирована) для работы с гипервизором.
Например, если ядро гостевой операционной системы, чтобы синхронизировать два
виртуальных процесса, использует спин-блокировку и гипервизор перепланирует вир-
туальный процессор, удерживающий спин-блокировку, время удержания блокировки
может увеличиться на несколько порядков, оставляя другие виртуальные процессоры,
запущенные в разделе, работать вхолостую очень длительный период времени. Для ре-
шения этой проблемы гостевая операционная система информируется, чтобы работать
вхолостую лишь короткий период времени перед тем, как вызвать гипервизор, чтобы
тот уступил ее физический процессор для запуска другого виртуального процессора.
BIOS поставляет несколько компаний, он интегрируется в энергонезависимую память
EEPROM (которая находится на системной плате компьютера).
Другой важный компонент режима ядра — это драйверы устройств. Windows исполь-
зует драйверы устройств для всех тех компонентов режима ядра, которые не являются
частью NTOS или HAL. Сюда входят файловые системы и стеки сетевых протоколов,
а также расширения ядра, такие как антивирусы и программное обеспечение DRM
(Digital Rights Management — управление цифровыми правами), а также драйверы для
управления физическими устройствами, для интерфейсов с системными шинами и т. д.
11.3. Структура системы
955
Компоненты ввода-вывода и виртуальной памяти совместно загружают (и выгружают)
драйверы устройств в память ядра и связывают их с уровнями NTOS и HAL. Диспетчер
ввода-вывода обеспечивает интерфейсы, которые позволяют обнаруживать устройства,
организовывать их и работать с ними, в том числе загружать соответствующий драйвер
устройства. Большая часть конфигурационной информации для управления устрой-
ствами и драйверами находится в разделе SYSTEM реестра. Компонент Plug-and-Play
диспетчера ввода-вывода поддерживает информацию по обнаруженному оборудованию
в разделе HARDWARE, который поддерживается в памяти, а не на диске, поскольку
он полностью создается заново при каждой загрузке системы.
Теперь мы изучим различные компоненты операционной системы несколько под-
робнее.
Уровень HAL (уровень абстрагирования оборудования)
Одной из целей Windows было сделать операционную систему способной к переносу
на другие аппаратные платформы. В идеале для того, чтобы «поднять» операционную
систему на компьютерной системе нового типа, должно быть достаточно просто пере-
компилировать операционную систему при помощи компилятора для этой новой плат-
формы. К сожалению, все не так просто. Хотя многие компоненты некоторых уровней
операционной системы вполне могут быть переносимыми (поскольку они в основном
имеют дело с внутренними структурами данных и абстракциями, поддерживающими
модель программирования), прочие уровни должны работать с регистрами устройств,
прерываниями, прямым доступом к памяти и прочими аппаратными функциями (ко-
торые на разных компьютерах существенно различаются).
Большая часть исходного кода для ядра NTOS написана на языке С, а не на ассемблере
(на ассемблере написано примерно 2 % кода для процессоров х86 и меньше 1 % для
процессоров х64). Однако нельзя просто взять этот код на языке С из системы х86,
плюхнуть в систему ARM, перекомпилировать и перезагрузиться, поскольку суще-
ствует множество аппаратных различий в архитектурах процессоров (которые даже не
связаны с разными наборами команд и не могут быть скрыты компилятором). Языки
типа С затрудняют абстрагирование (без существенного падения производительности)
некоторых структур данных и параметров оборудования, таких как формат элементов
таблицы страниц, размер физических страниц памяти и размер слова. Все это (а также
массу специфичных для оборудования оптимизаций) необходимо переносить вручную
(несмотря на то, что они написаны не на ассемблере).
Аппаратные подробности организации памяти на больших серверах (или наличие
аппаратных примитивов синхронизации) могут повлиять также на более высокие
уровни системы. Например, диспетчер виртуальной памяти NT и уровень ядра знают
об аппаратных подробностях кэширования и локальности памяти. NT везде исполь-
зует примитивы синхронизации compare&swap, и ее будет очень трудно перенести на
систему, в которой их нет. И наконец, в системе есть много зависимостей от порядка
байтов в словах. На всех системах, куда была портирована NT, оборудование имеет
прямой порядок байтов.
Кроме этих серьезных проблем переносимости имеется также значительное количество
более мелких проблем (даже между системными платами разных производителей).
Разница в процессорах влияет на реализацию примитивов синхронизации (таких, как
спин-блокировка). Есть несколько семейств чипсетов, которые имеют разные приори-