Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
Я помню когда-то давно читал код самого-самого ядра линукса, и там тоже не было всех этих функций типа memcpy/strcpy, по нужде вручную переписывали. "Библиотеки си" во многом зависят от самого ядра, т.е. циклическая зависимость получается, плюс занимают лишнюю память ядра, возможно.
цикл хорошая конечно идея. но по чему ты собрался циклится то?
это в прикладухе у тебя и сегмент данных всегда под рукой, и стек на пример почти безразмерный. потому что их ОС для тебя загрузила и проинициализировала.
а кто их по твоему для ОС загрузит и/или проинициализирует?
нет. кернела грузятся бутстрапом как правило в одну большую страницу. виртуальной памяти на ранней фазе инициализации еще нету.
> Так что большинство подсистем уже запущено...
не знаю - системщина под виндами это не моя область. ну да ни в одном из моих комментарием я и не отрицал что код может быть говном.
народ спрашивал для чего такое может быть. то сверху - есть один из способов зашить в код строковый литерал, для того что бы он в сегменте данных не появился. и в системщене есть на самом деле места где это нужно.
но как правило, сегменты в ехе-шнике маппятся прямо в память, как отдельные сегменты. и по типу сегмента в ехе-шнике, сегменту в памяти выдаются соответствующие аттрибуты: исполняемый/рид-онли, рид-онли, рид-врайт. в виндах в оссобенности это используется для шаред сегментов.
для простых ехе-шников, сегменты буквально мапятся. и загружаются при первом доступе, как если бы из свапа. (для ускорения запуска, предзагрузка может заранее что-то подгрузить.)
в случае кернела, сегменты скорее всего будут замержены и как один в память залиты (кернел в одну (большую) страницу слегка повышает производительность). в случае драйвера, как правило кернел уже загружает посегментно, но загружает сразу все полностью, потому что драйверам виртуальная память в общем случае недоступна.
в виндах оно может быть и не так, но и сильно отличатся не будет.
>но как правило, сегменты в ехе-шнике маппятся прямо в память, как отдельные сегменты
Некоторые отдельные секции могут попадать в один сегмент. Собственно в системах с линейной памятью, например 32х винда в обычном режиме, адресное пространство - это в основном отдельный общий большой сегмент.
Вроде вот такая конфигурация сегментов была в винде:
cs - сегмент кода на все доступное пространство, RX
ds, es, gs - сегмент данных на все доступное пространство, RW
fs - сегмент с инфой о процессе, RW
Т.е. сегментные регистры настроены на отъебись, а все разруливается уже на уровне страниц.
> Собственно в системах с линейной памятью, например 32х винда в обычном режиме, адресное пространство - это в основном отдельный общий большой сегмент.
ты немножко путаешься.
flat memory это как бы стандартная фича. виртуально адресное пространстно это самый верхний уровень подразделения виртуальной памяти.
дальше идут сегменты, которые в нынешнее время не имеют отношения к старым 64К сегментам 8086. сегмент это просто кусок непрерывной виртуальной памяти, который часто описывается одним дескриптором в таблице виртуальной памяти процессора. (вот сюда как раз и мапятся сегменты ехе-шника).
самый нижный уроветь - это непосредственно страницы виртуальной памяти.
это конечно не совсем уровни: сегменты виртуальной памяти и страницы виртуальной памяти ортогональны. сегменты говорят процу какая часть виртуальной памяти может аддресоватся (все что не описано - адресоваться программой не может). страницы нужны для сваппинга или динамической загрузки данных осью.
> Некоторые отдельные секции могут попадать в один сегмент.
Да. Сегменты с аналогичными свойствами как правило сливаются вместе. Потому что количество сегментов влияет на скорость переключения процессов: больше сегментов/дескрипторов, дольше длится переключение процессора на виртуальную память нового процесса. (Хотя вроде на последних Интелах есть какие-то хаки что бы этого избежать.)
> ты немножко путаешься.
Нет. Рассмотрим этапы трансляции адреса на 32 битной архитектуре intel:
1) Адрес, указанный в команде складывается с адресом начала сегмента, прописанным в дескрипторе, на который ссылается сегментный регистр указанный (или подразумевающийся) в команде. Здесь же проверяется выход адреса за границу сегмента. В итоге мы получаем виртуальный адрес.
2) Виртуальный адрес транслируется в физический по дереву таблиц трансляции. Проверяются права на доступ к странице.
Т.е. мы имеем такой порядок - сегмент:адрес -> виртуальный адрес -> физический адрес.
Так вот. Во flat модели дескрипторы сегментов настраиваются так, что адреса транслируются в виртуальные без изменений. (Ну за исключением сегмента, на который ссылается регистр fs в windows, который для удобства ссылается на структуру с инфой о процессе). Сегменты применяются только для ограничения доступной пользовательской программе области (например в 32хбитных осях это младшие 2-3 гигабайта).
Секции экзешников никакого отношения к сегментам не имеют. Ось размещает секции в памяти, следуя советам компилятора, и расставляет на страницы, в которые попали эти секции, соответствующие атрибуты (RW для данных и стека, RX для кода, RWS для шаренных секций и т.п.). Секции с аналогичными атрибутами компилятор объединяет прежде всего для экономии памяти (не сегментных дескрипторов которых от силы штук 5!).
Мысль которую я пытался донести до вас - 32х битные операционки на intel архитектуре с flat моделью памяти (linux, freebsd, windows, да пофиг какие) не связывают сегменты\секции в исполняемом файле с сегментными регистрами и дескрипторами сегментов.
Сегментные дескрипторы и регистры используются ими только для создания плоского адресного пространства.
Все атрибуты секций\сегментов, которые линкер указал в экзешнике применяются на уровне страниц и только страниц.
но я как бы здесь пытался в абстрактных понятиях (не вдаваясь в нерелевантные тех подробности) объяснить разницу между тем как видит память процесс и как ее видит система на фазе бутстрапа. смотри оригинальный топик.
> не связывают сегменты\секции в исполняемом файле с сегментными регистрами и дескрипторами сегментов.
сегодня - нет. ранние винды и линухи до 2.4 - связывали. потому что именно как бы для этой цели Интел и ввел эти дескрипторы. то что в конце от них пришлось отзаться (в линухе начиная с 2.5), это другая песня.
то что я подразумевал под "сегментом" или "дескриптором" в линухе называется VMA (Virtual Memory Area; они в старые времена на i386, как и рекомендовалось в прошлом Интелом, мапились на дескрипторы). и это то что ты видишь под линохом в /proc/$$/maps или под виндой в VMMap ( http://technet.microsoft.com/en-us/sysinternals/dd535533.aspx )
> Все атрибуты секций\сегментов, которые линкер указал в экзешнике применяются на уровне страниц и только страниц.
За исключением конечно атрибута "шаред" который и живет как раз только на уровне OC в VMA. 🙂
>сегодня - нет. ранние винды и линухи до 2.4 - связывал
что?
Сегментные регистры в 32хитный ОС почти всегда указывают на нули. Смысл сегмента только в отделении колец защиты, а сегментация осталась в шестнадцатибитных ос
Дескрипторы ненулевые, они нужны для функционирования защиты, а вот записи в GDT/LDT, куда они указывают, в современных ОС с нулевой базой и с бесконечным лимитом.
P.S. В 32-битной Винде у FS ненулевая база, а в 64-битной ненулевая база у GS (чтобы нескучно было), и они указывают на thread information block.
Это единственное, что я вспомнил из исключений. CS, DS, ES, SS обычно с нулевой базой (хотя значения дескрипторов могут быть разными).
В длинном режиме 64-битного процессора у инструкций нельзя использовать префиксы CS:, DS:, ES:, SS:, потому что всегда используется дефолтный префикс, а вот FS: и GS: использовать можно (этим и пользуется Винда, пихая туда указатель на TIB).
> для функционирования защиты
Не только. При помощи флагов «DB» и «L» дескриптора сегмента происходит переключение «на лету» между 16-битным, 32-битным и длинным 64-битным режимами; так функционирует выполнение 32-битного кода в 64-битных ОС, например.
В long mode не только нету v86, там ещё 16-битные сегменты защищённого режима кастрированные: инструкция LLDT не работает. Из-за этого в 64-битную Винду не стали включать подсистему Win16, а авторам winevdm пришлось костылить мумулятор хуй86.
Насколько помню, в ядре винды (и в драйверах) есть еще разделение на pageable и non pageable секции, и программист определяет какие код и данные можно своповать, а какие нет.
В общем случае, код не работающий на высоких IRQL вполне свопуется (т.к. несвопуемая память дорогой ресурс).
Чем это может обусливливаться?
я ядрах осей, в коде который относится к инициализации и бутстрапу, можно всякого интересного найти.
Обычно часть стандартной библиотеки си и обычно линкуется статически. Так что скорее всего это исключено.
это в прикладухе у тебя и сегмент данных всегда под рукой, и стек на пример почти безразмерный. потому что их ОС для тебя загрузила и проинициализировала.
а кто их по твоему для ОС загрузит и/или проинициализирует?
Вот разве что не загружена страница, в которой лежал бы литерал L"SystemPartition"... но это же обычно сегмент кода?
нет. литералы лежат в BSS.
> Вот разве что не загружена страница
нет. кернела грузятся бутстрапом как правило в одну большую страницу. виртуальной памяти на ранней фазе инициализации еще нету.
> Так что большинство подсистем уже запущено...
не знаю - системщина под виндами это не моя область. ну да ни в одном из моих комментарием я и не отрицал что код может быть говном.
народ спрашивал для чего такое может быть. то сверху - есть один из способов зашить в код строковый литерал, для того что бы он в сегменте данных не появился. и в системщене есть на самом деле места где это нужно.
Не путать сегмент в оперативке и секцию в exe-файле.
но как правило, сегменты в ехе-шнике маппятся прямо в память, как отдельные сегменты. и по типу сегмента в ехе-шнике, сегменту в памяти выдаются соответствующие аттрибуты: исполняемый/рид-онли, рид-онли, рид-врайт. в виндах в оссобенности это используется для шаред сегментов.
для простых ехе-шников, сегменты буквально мапятся. и загружаются при первом доступе, как если бы из свапа. (для ускорения запуска, предзагрузка может заранее что-то подгрузить.)
в случае кернела, сегменты скорее всего будут замержены и как один в память залиты (кернел в одну (большую) страницу слегка повышает производительность). в случае драйвера, как правило кернел уже загружает посегментно, но загружает сразу все полностью, потому что драйверам виртуальная память в общем случае недоступна.
в виндах оно может быть и не так, но и сильно отличатся не будет.
Некоторые отдельные секции могут попадать в один сегмент. Собственно в системах с линейной памятью, например 32х винда в обычном режиме, адресное пространство - это в основном отдельный общий большой сегмент.
cs - сегмент кода на все доступное пространство, RX
ds, es, gs - сегмент данных на все доступное пространство, RW
fs - сегмент с инфой о процессе, RW
Т.е. сегментные регистры настроены на отъебись, а все разруливается уже на уровне страниц.
Именно.
ты немножко путаешься.
flat memory это как бы стандартная фича. виртуально адресное пространстно это самый верхний уровень подразделения виртуальной памяти.
дальше идут сегменты, которые в нынешнее время не имеют отношения к старым 64К сегментам 8086. сегмент это просто кусок непрерывной виртуальной памяти, который часто описывается одним дескриптором в таблице виртуальной памяти процессора. (вот сюда как раз и мапятся сегменты ехе-шника).
самый нижный уроветь - это непосредственно страницы виртуальной памяти.
это конечно не совсем уровни: сегменты виртуальной памяти и страницы виртуальной памяти ортогональны. сегменты говорят процу какая часть виртуальной памяти может аддресоватся (все что не описано - адресоваться программой не может). страницы нужны для сваппинга или динамической загрузки данных осью.
> Некоторые отдельные секции могут попадать в один сегмент.
Да. Сегменты с аналогичными свойствами как правило сливаются вместе. Потому что количество сегментов влияет на скорость переключения процессов: больше сегментов/дескрипторов, дольше длится переключение процессора на виртуальную память нового процесса. (Хотя вроде на последних Интелах есть какие-то хаки что бы этого избежать.)
Нет. Рассмотрим этапы трансляции адреса на 32 битной архитектуре intel:
1) Адрес, указанный в команде складывается с адресом начала сегмента, прописанным в дескрипторе, на который ссылается сегментный регистр указанный (или подразумевающийся) в команде. Здесь же проверяется выход адреса за границу сегмента. В итоге мы получаем виртуальный адрес.
2) Виртуальный адрес транслируется в физический по дереву таблиц трансляции. Проверяются права на доступ к странице.
Т.е. мы имеем такой порядок - сегмент:адрес -> виртуальный адрес -> физический адрес.
Так вот. Во flat модели дескрипторы сегментов настраиваются так, что адреса транслируются в виртуальные без изменений. (Ну за исключением сегмента, на который ссылается регистр fs в windows, который для удобства ссылается на структуру с инфой о процессе). Сегменты применяются только для ограничения доступной пользовательской программе области (например в 32хбитных осях это младшие 2-3 гигабайта).
Секции экзешников никакого отношения к сегментам не имеют. Ось размещает секции в памяти, следуя советам компилятора, и расставляет на страницы, в которые попали эти секции, соответствующие атрибуты (RW для данных и стека, RX для кода, RWS для шаренных секций и т.п.). Секции с аналогичными атрибутами компилятор объединяет прежде всего для экономии памяти (не сегментных дескрипторов которых от силы штук 5!).
LOL. транслируются из чего?? :))))
> Ось размещает секции в памяти, следуя советам компилятора
Сегменты в ехе-шнике и есть не что иное как "советы компилятора." Или более точнее - советы линкера.
N.B. Ты похоже недооцениваешь роль линкера во всем этом. Выше ты вполне вероятно имел ввиду не "транлируются" а "релоцируются."
Спорить не буду. Похоже что терминология на виндах отличается. Хотя как бы сильно ты мне и не противоречишь.
> LOL. транслируются из чего?? :))))
Из адреса который указан в команде.
> Выше ты вполне вероятно имел ввиду не "транлируются" а "релоцируются."
Нет, именно транслируются процом.
Релокации может и не быть, если операционке удалось замапить все секции по предложенным линкером адресам.
Сегментные дескрипторы и регистры используются ими только для создания плоского адресного пространства.
Все атрибуты секций\сегментов, которые линкер указал в экзешнике применяются на уровне страниц и только страниц.
Чтобы не быть голословным приведу пару ссылок - http://www.ibm.com/developerworks/ru/library/l-memmod/ ну и допустим вот http://itechspace.wordpress.com/2008/08/19/windows-memory-model/.
но я как бы здесь пытался в абстрактных понятиях (не вдаваясь в нерелевантные тех подробности) объяснить разницу между тем как видит память процесс и как ее видит система на фазе бутстрапа. смотри оригинальный топик.
> не связывают сегменты\секции в исполняемом файле с сегментными регистрами и дескрипторами сегментов.
сегодня - нет. ранние винды и линухи до 2.4 - связывали. потому что именно как бы для этой цели Интел и ввел эти дескрипторы. то что в конце от них пришлось отзаться (в линухе начиная с 2.5), это другая песня.
то что я подразумевал под "сегментом" или "дескриптором" в линухе называется VMA (Virtual Memory Area; они в старые времена на i386, как и рекомендовалось в прошлом Интелом, мапились на дескрипторы). и это то что ты видишь под линохом в /proc/$$/maps или под виндой в VMMap ( http://technet.microsoft.com/en-us/sysinternals/dd535533.aspx )
> Все атрибуты секций\сегментов, которые линкер указал в экзешнике применяются на уровне страниц и только страниц.
За исключением конечно атрибута "шаред" который и живет как раз только на уровне OC в VMA. 🙂
Ну да, согласен, я просто рассуждал о более-менее современных системах с flat memory model.
> то что я подразумевал под "сегментом" или "дескриптором" в линухе называется VMA
Ок, теперь все встало на свои места 🙂
что?
Сегментные регистры в 32хитный ОС почти всегда указывают на нули. Смысл сегмента только в отделении колец защиты, а сегментация осталась в шестнадцатибитных ос
Это единственное, что я вспомнил из исключений. CS, DS, ES, SS обычно с нулевой базой (хотя значения дескрипторов могут быть разными).
В длинном режиме 64-битного процессора у инструкций нельзя использовать префиксы CS:, DS:, ES:, SS:, потому что всегда используется дефолтный префикс, а вот FS: и GS: использовать можно (этим и пользуется Винда, пихая туда указатель на TIB).
Не только. При помощи флагов «DB» и «L» дескриптора сегмента происходит переключение «на лету» между 16-битным, 32-битным и длинным 64-битным режимами; так функционирует выполнение 32-битного кода в 64-битных ОС, например.
https://govnokod.ru/25776#comment497735
давай про пхп
Да, давай про пхп. Дмитрий Стогов протащил в PHP 7 очереди, стеки, деки, множества и другие структуры данных:
https://www.php.net/manual/ru/book.ds.php
(только непправильные ответы)
>деки
а функцию бесселя?
зы: посмотрел ссылку и понял, что бандерлоги обезьянничают вечно ненавидимую ими джаву, потому что для плюсов у них интеллект не дотягивает.
ПХПшники часто садились кружками, чесались, отыскивали блох и притворялись программистами
https://github.com/otya128/winevdm
Переключение из long mode в «короткий» слишком дорогое, чтобы его использовать в многозадачной среде.
А разве в нём что-то менялось?
Я помню, что в 2.5 перевернули набор дефолтных драйверов, кучу говна зашили прямо в ядро, и его теперь не нужно инсталлировать через insmod.
В общем случае, код не работающий на высоких IRQL вполне свопуется (т.к. несвопуемая память дорогой ресурс).
Там же где и винду.