Почему нельзя писать по нулю ?
Только не бейте ногами !
Итак:
mov eax, 0
mov [eax], 3
Последняя инструкция эквивалентна mov DS:[eax], 3
Все было бы прекрасно, если бы DS содержал 0 селектор, тогда бы исключение было бы понятным, но DS содержит не нулевой селектор. А в сегменте я могу смещатся на столько на сколько мне позволяет его длинна. Хоть на 0, хоть на 1. Мы же не в реальном режиме, где эти адреса забиты под прерывания.
Итак, почему эксептион ?
Поставим вопрос по другому12.02.02 23:12 Автор: PS <PS> Статус: Elderman Отредактировано 12.02.02 23:22 Количество правок: 2
Я знаю только такие способы,
1 В селекторе индекс равен 0
2 Обращение к ридонли для записи (и наоборот)
3 Обращение не из того кольца
Теперь
char* p = 0;
*p = 3;
Генерится приведеный мной ассемблерный код. DS уже установлена и не подходит не под один из 3х пунктов (индекс !=0, для записи и чтения, в том же кольце).
Вся разница в нормальной и не нормальной программе только в строчке mov eax, XXX (вот тут я правда не уверен)
Так каким образом обеспечивается прирывание ?
PS
А с наездом на реальный я конечно погорячился. может подсознательно вспомнил РК на КР580ВМ80, где сразу безвозврано попадал на вектора прерываний... (или это было в спектруме...)
Поставим вопрос по другому13.02.02 12:52 Автор: ih8u <i hate you> Статус: Member
> Каким макаром обеспечивается прерывание в моем примере, > > mov eax, 0 > > mov [eax], 3 > > Я знаю только такие способы, > 1 В селекторе индекс равен 0 > 2 Обращение к ридонли для записи (и наоборот) > 3 Обращение не из того кольца
4. Защита страницы на уровне процессора. Твой процесс не имеет прав обращаться к нулевой странице памяти. При попытке обращения процессор генерирует исключительную ситуацию, ядро ее обрабатывает и в твоей проге вылезает эксепшн.
Логический адрес, в моем примере преобразуется в КОРРЕКТЫЙ линейный, но на этом не заканчивается и линейный преобразуется в физический, а т.к. винда и возможно линукс скорей всего в дескрипторах ставят нули, то линейный адрес тоже получается 00000000, и он не может преобразоваться в физический.
А что бы остановится на линейном, и оставить его как физический мне надо писать свою "операционку", в которой не будет страниц.
Так ?
Можно сказать, что есть два защищеных режима: с сегментной и со страничной адресацией. Так ?
почитал бы ты доки по процам что-ли13.02.02 12:55 Автор: z0 <z0> Статус: Member Отредактировано 13.02.02 13:05 Количество правок: 1
> Логический адрес, в моем примере преобразуется в КОРРЕКТЫЙ > линейный, но на этом не заканчивается и линейный > преобразуется в физический, а т.к. винда и возможно линукс > скорей всего в дескрипторах ставят нули, то линейный адрес > тоже получается 00000000, и он не может преобразоваться в > физический.
неправильно.
вот правильный ответ:
в режиме защиты адреса (бит 0 = 1 в CR0) логический адрес является КОРРЕКТНЫМ если он не выходит за предел адреса (limit+granularity_bit) установленный в соответствующем сегментному индексу дескрипторе.
перед проверкой логического адреса на КОРРЕКТНОСТЬ процессор выполнит проверку дескриптора - 1) индекс дескриптора (селектор)(сегмент) не может быть равен 0; 2) права доступа на дескриптор должны СООТВЕТСТВОВАТЬ (тут много нюансов) правам кода т.е. правам дескриптора CS; 3) операция с памятью должна допускаться типом данного дескриптора; 4) переходные эффекты (чтение dword по адресу fffffffe etc (не у всех процов))
в случае ошибки генерируется GeneralProtectionFault или (при стековых командах но не всегда) StackFault или Double/TripleFault
к логическому адресу прибавляется база дескриптора и получается линейный адрес - он же физический если бит 1f = 0 в CR0
если установлен режим страничного преобразования адреса (бит 1f = 1 в CR0) то происходит преобразование линейного адреса в физический по двухуровневой таблице страниц. при этом на каждом уровне происходит проверка страницы на доступность (бит юзер/супервизор) и присутствие в памяти (бит present)
по неприсутствию всегда генерится PageFault но надо помнить что у нее приоритет ОЧЕНЬ низкий и до нее часто генерится еще что-нибудь
по недоступности тоже всегда должна генериться PageFault но тут есть процессорозависимые нюансы
> А что бы остановится на линейном, и оставить его как > физический мне надо писать свою "операционку", в которой не > будет страниц. > Так ?
ОС с соответствием физического и линейного адреса - DOS без EMM/QEMM etc, Novel NetWare 2.x 3.x 4.x
причем в досе поскольку RealMode то таблиц страниц и самих страниц естественно нету, а в новеле есть и то и другое но таблицы страниц так построены что преобразуют линейный в физический БЕЗ ИСКАЖЕНИЯ
> > Можно сказать, что есть два защищеных режима: с сегментной > и со страничной адресацией. Так ?
есть режим защиты адреса (ProtectedMode) для которого существует возможность включить режим страничной переадресации (PagingEnabled)
ЗЫ: пропущено много тонкостей естественно
почитал бы ты доки по процам что-ли14.02.02 01:42 Автор: Sandy <Alexander Stepanov> Статус: Elderman
> по неприсутствию всегда генерится PageFault но надо помнить > что у нее приоритет ОЧЕНЬ низкий и до нее часто генерится > еще что-нибудь
Ага, именно эта исключительная ситуация используется менеджером виртуальной памяти для переключения существующих страниц физической памяти и/или подкачки страниц из файла подкачки.
Может еще раз...13.02.02 13:17 Автор: PS <PS> Статус: Elderman
Вообще то я считал, что логический это сегмент:смещение
линейный - преобразованый логический
физический - либо логический, либо преобразованый логический
> вот правильный ответ: > в режиме защиты адреса (бит 0 = 1 в CR0) логический адрес > является КОРРЕКТНЫМ если он не выходит за предел адреса > (limit+granularity_bit) установленный в соответствующем > сегментному индексу дескрипторе. > > перед проверкой логического адреса на КОРРЕКТНОСТЬ > процессор выполнит проверку дескриптора - 1) индекс > дескриптора (селектор)(сегмент) не может быть равен 0;
Селектор в моем примере не 0.
2) права доступа на дескриптор должны СООТВЕТСТВОВАТЬ (тут
> много нюансов) правам кода т.е. правам дескриптора CS;
Соответствуют
3)> операция с памятью должна допускаться типом данного
> дескриптора; Допускается
4) переходные эффекты (чтение dword по адресу
> fffffffe etc (не у всех процов)) > в случае ошибки генерируется GeneralProtectionFault или > (при стековых командах но не всегда) StackFault или > Double/TripleFault > > к логическому адресу прибавляется база дескриптора и > получается линейный адрес - он же физический если бит 1f = > 0 в CR0 > Может к смещению ?
Хорошо, прибавили. Получили... что ? Мы в виндах.
> если установлен режим страничного преобразования адреса > (бит 1f = 1 в CR0) то происходит преобразование линейного > адреса в физический по двухуровневой таблице страниц. при > этом на каждом уровне происходит проверка страницы на > доступность (бит юзер/супервизор) и присутствие в памяти > (бит present) > по неприсутствию всегда генерится PageFault но надо помнить > что у нее приоритет ОЧЕНЬ низкий и до нее часто генерится > еще что-нибудь > по недоступности тоже всегда должна генериться PageFault но > тут есть процессорозависимые нюансы >
Так на каком этапе проц генерит эксептион в примере
mov eax, 0
mov [eax], 1
?????
Может еще раз...14.02.02 01:54 Автор: Sandy <Alexander Stepanov> Статус: Elderman
> Вообще то я считал, что логический это сегмент:смещение > линейный - преобразованый логический > физический - либо логический, либо преобразованый > логический
Здесь надо учитывать, что значение в сегментном регистре в реальном и защищенном режимах сильно отличаются: в реальном там хранится сегмент памяти в пределах 1М памяти, а в защищенном - селектор, т.е. смещение в локальной/глобальной таблице дескрипторов.
> > перед проверкой логического адреса на КОРРЕКТНОСТЬ > > процессор выполнит проверку дескриптора - 1) индекс > > дескриптора (селектор)(сегмент) не может быть равен 0;
Если честно, не вижу причин, почему бы ему не мочь быть равным нулю. Особенно если таблица дескрипторов локальная.
> Так на каком этапе проц генерит эксептион в примере > mov eax, 0 > mov [eax], 1
Именно здесь! Делается попытка записи в память в нулевой странице процесса.
> > ?????
Может еще раз...14.02.02 14:50 Автор: z0 <z0> Статус: Member Отредактировано 14.02.02 15:38 Количество правок: 1
> Здесь надо учитывать, что значение в сегментном регистре в > реальном и защищенном режимах сильно отличаются: в реальном > там хранится сегмент памяти в пределах 1М памяти, а в > защищенном - селектор, т.е. смещение в локальной/глобальной > таблице дескрипторов.
значения-то сами могут и не отличаться а вот смысл их конечно разный
> > > > перед проверкой логического адреса на > КОРРЕКТНОСТЬ > > > процессор выполнит проверку дескриптора - 1) > индекс > > > дескриптора (селектор)(сегмент) не может быть > равен 0; > > Если честно, не вижу причин, почему бы ему не мочь быть > равным нулю. Особенно если таблица дескрипторов локальная.
хорошо поправлю себя: старшие 14 битов сегмента/селектора
ты же наверняка знаешь что равный нулю сегмент/селектор относится именно к GDT
по поводу твоего слова "особенно" - вспоминаются дебаты на каком-то западном форуме - фравии что-ли - по поводу ИСПОЛЬЗОВАНИЯ нулевого индекса в GDT. честно сказать кроме того что это удобное место для хранения 8 байт полезной информации я для себя ничего не использовал - да, есть процессорозависимые глюки но и только
я так понимаю интел сделал селектор 0 по аналогии с сишным нулевым указателем - чтобы было чем загрузить неиспользуемый сегментный регистр
Может еще раз...14.02.02 16:45 Автор: Sandy <Alexander Stepanov> Статус: Elderman
> > Здесь надо учитывать, что значение в сегментном > регистре в > > реальном и защищенном режимах сильно отличаются: в > реальном > > там хранится сегмент памяти в пределах 1М памяти, а в > > защищенном - селектор, т.е. смещение в > локальной/глобальной > > таблице дескрипторов. > > значения-то сами могут и не отличаться а вот смысл их > конечно разный
Ага, именно это я и хотел сказать.
> по поводу твоего слова "особенно" - вспоминаются дебаты на > каком-то западном форуме - фравии что-ли - по поводу > ИСПОЛЬЗОВАНИЯ нулевого индекса в GDT. честно сказать кроме > того что это удобное место для хранения 8 байт полезной > информации я для себя ничего не использовал - да, есть > процессорозависимые глюки но и только > я так понимаю интел сделал селектор 0 по аналогии с сишным > нулевым указателем - чтобы было чем загрузить > неиспользуемый сегментный регистр
Это не совсем очевидно, но мне тоже на ум ничего другого не приходит.
...И еще вопрос.13.02.02 18:54 Автор: Chingachguk <Chingachguk> Статус: Member Отредактировано 13.02.02 18:56 Количество правок: 1
> Так на каком этапе проц генерит эксептион в примере > mov eax, 0 > mov [eax], 1 <<< Тута. > ?????
Вообще-то z0 все уже написал.
Просто хотел дополнить и спросить. Если посмотреть, как выполняется самая простая прога под вин, то вот что видать:
- код начинается ВСЕГДА с смещения 401000h.(возможно, это зависит от компилятора(я имею в виду +1000h));
- если выполнить инструкцию вида:
mov al,ds:[400000h] ; все работает OK
Но вот если выполнить эту:
mov al,ds:[400000h-1] ; То возникает исключение 0Eh - PageFault.
Итак, доступ куда нам дает селектор в ds. Смотрим:
ldt ds ; Выдать описалово на локальный дескриптор(в ds):
Sel ... Base Limit DPL Attr
0167 ... 0000 0000FFFF 3 P RW ED
Я полагаю, используется страничное преобразование линейного адреса.
В данном случае 400000h - это не минимальный физ. адрес, по которому можно читать/писать (это не так, ибо, например Base+Limit меньше+бит гранулярности вроде выставлен).
Пусть используются 4-х килобайтные страницы, тогда физический адрес формируется вроде так:
Биты 12-21 используются как индекс в таблице "базовых" физических адресов, оттуда берем базу, смещение берем(уже в ней) из битов 0-11, биты >=22 - индекс в каталоге страниц.
Я правильно понял ? Ж)
Может еще раз...13.02.02 14:14 Автор: z0 <z0> Статус: Member
> Вообще то я считал, что логический это сегмент:смещение > линейный - преобразованый логический > физический - либо логический, либо преобразованый > логический
ну это конечно вопрос терминологии
давай придерживаться чего-то
например:
ЛОГИЧЕСКИЙ - смещение внутри сегмента
ЛИНЕЙНЫЙ - смещение внутри адресного пространства процессора
ФИЗИЧЕСКИЙ - адрес на шине процессора
> Может к смещению ? > Хорошо, прибавили. Получили... что ? Мы в виндах.
значит прибавили 0
> Так на каком этапе проц генерит эксептион в примере > mov eax, 0 > mov [eax], 1 > > ?????
1) CPU: DS <> 0 CPU: Ok
2) CPU: PL (DS) >= PL (CS) CPU: Ok
3) CPU: DS writable CPU: Ok
4) CPU: eax < segment_size CPU: Ok
5) CPU: segment_size-eax >= operator_size CPU: Ok
eax=eax+0 пропускаем вижу что тебе это понятно
6) CPU: page_table_directory(eax).[bit_present] CPU: Ok
7) CPU: page_table_directory(eax).[bit_user] CPU: Ok
8) CPU: page_table(page_table_directory(eax)).[bit_present] CPU: No
9) CPU: exception(PageFault, Address)
10) OS: check_page_user_rights(Process, Address) OS:NoAccess
11) OS: RaiseException(AccessViolation, Process, Address)
12) OS: Kill(Process)
то что от ОС зависит - это для виндов (смотрел в НТ)
для линуха может ты нам расскажешь
думаю приблизительно так же
в linux точно также13.02.02 16:04 Автор: ukv Статус: Незарегистрированный пользователь
И в виндах, и в линуксе изрядная часть защиты сделана не на уровне сегментов, а на уровне страниц. Сегментация фактически подавляется. Неявно предполагается, что приложение работает в flat-модели, ds и cs адресуют все 4 Гб одного и того же виртуального адресного пространства. На уровне страничной организации в этом пространстве будут в основном лакуны - и в частности нулевая страница. Неприсутствие нулевой страницы в памяти - просто черта операционок - для отлова ошибок обращения по нулевому указателю. Ну а из тех страниц, которые в адресном пространстве есть - некоторые могут быть защищены от записи (и тогда, например, можно отображать одну физическую копию ядра в адесное пространство всех процессов сразу). С точки зрения сегментов все выглядит нормально - сегмент есть (на все 4Гб), и запись в него вроде бы разрешена, а модифицировать ядро не получится - не позволит менеджер страниц.
почему нельзя?12.02.02 21:56 Автор: z0 <z0> Статус: Member
> Мы же не в реальном режиме, где эти адреса забиты под > прерывания. > Итак, почему эксептион ?
во-первых в реальном режиме как раз можно, как ты сам знаешь
во-вторых это зависит от карты распределения памяти для проги, которая в свою очередь зависит от ОС
для чикаги - примерчик
.386
> Почему нельзя писать по нулю ? > Только не бейте ногами ! > Итак: > mov eax, 0 > mov [eax], 3 > > Последняя инструкция эквивалентна mov DS:[eax], 3 > Все было бы прекрасно, если бы DS содержал 0 селектор, > тогда бы исключение было бы понятным, но DS содержит не > нулевой селектор. А в сегменте я могу смещатся на столько > на сколько мне позволяет его длинна. Хоть на 0, хоть на 1. > Мы же не в реальном режиме, где эти адреса забиты под > прерывания. > Итак, почему эксептион ?
Чтобы легче было отлавливать ошибки в программах, связанные с неинициализированными указателями, Винда запрещает обращение к адресам из первой страницы адресного пространства процесса.
Все указатели сегментов указывают на одно и то же адресное пространство. Т.е. CS:0 и DS:0 указывают на одну и ту же ячейку памяти, которая находится по адресу 0.
Из-за этого ЛЮБЫЕ обращения процесса к адресам в первой странице, не важно, что это за обращение: выполнение кода, стек, данные - возникает исключение Access violation.