OSDev http://osdev.su/ |
|
Хранение кода и данных в памяти http://osdev.su/viewtopic.php?f=5&t=370 |
Страница 1 из 2 |
Автор: | qeos [ 12 янв 2011, 14:47 ] |
Заголовок сообщения: | Хранение кода и данных в памяти |
Вобщем назрело.. Видимо пора по немногу делиться идеями, выносить их на обсуждение, т.к. уже силами одного мозга не получается придумать чтото толковое и стоящее. Задача такая: Условие Как известно код и данные жестко зависимы между собой. Т.е. при компиляции исходников мы получаем бинарник с жестко прописанными ссылками на данные. Т.е. например такой код: Код: string1 db 'Test',0 ... mov eax, string1 mov cl, [string1][0] будет скомпилирован в процессорные коды в виде жетких ссылок на эту переменную 'string1' относительно начала этого бинарника (другие варианты смотри ниже). Задача Так вот требуется реализовать некий алгоритм/механизм при котором будет возможность переместить данные и/или код в любое место памяти обеспечив при этом, нормальное выполнение кода. Варианты решения: 1. Использование объектных файлов. Существует некий стандарт как бы "прекомпилированных" файлов, который еще не является кодом готовым к выполнению, но уже и не является исходником. Если утрировать, то это бинарник, со скомпилированным кодом в котором есть секция непосредственно машинных кодов и секция указателей на места в этом коде где используется прямые указатели, ну и секция данных. Т.е. в нашем случае будут указатели на значения в командах mov. В этом варианте есть свои плюсы и минусы. Плюсы: - очень распространенный стандарт. практически любой компилятор может создать такой файл Минусы: - при перемещении нужно изменять данные указатели в этом коде. т.е. менять данные в сегменте кода - данными управляет исполняемый код, т.е. нельзя контролировать ядром тип данных или например, можно ли переместить данные, или данные только для чтения и т.д. 2. Вариант который я пытаюсь реализовать. Весь код компилируется без прямых указателей, т.е. чтобы получить символ в строке, сначала необходимо получить его реальное местоположение в памяти. Структура получается примерно такой:
- Есть указатель на таблицу указателей данных (назовем ее RVA_table). Он хранится в регистре ESI при выполнении этого кода. - Есть таблица указателей на структуры переменных (VAR_record). Очень простая, 4 байта адрес в памяти. - Есть структура (record/struct) описания переменной, которая хранит состояние этой записи, ее тип, размер данных и указатель на сами данные.
- прибавляем местоположение этой таблицы из регистра ESI - получаем местоположение записи VAR_record в памяти из таблицы RVA_table - после этого из записи VAR_record мы можем получить реальное местоположение описанных данных в памяти - исполняемый код неизменяем, т.е. можно отслеживать целостность кода - один и тот же код может работать с разными экземплярами данных - данные располагаются в памяти независимо от кода и могут быть легко перемещены при необходимости Минусы: - как мне кажется этот вариант будет требовать больше процессорного времени на получение ссылок на реальные данные 3. Возможно есть какой либо еще вариант о котором я не знаю. Не исключаю, что существует более эффективный алгоритм. В общем если есть мысли или идеи прошу высказаться. |
Автор: | shm [ 12 янв 2011, 16:28 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
qeos, релокейшины на мой взгляд самое удачное решение проблемы. |
Автор: | Himik [ 12 янв 2011, 17:03 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
qeos, динамические вычисления адресов - это усложнение кода и потеря производительности. В стандартных форматах принято корректировать бинарный образ программы непосредственно в оперативной памяти перед запуском. Это называется настройкой адресов. В результате, на стадии выполнения, все адреса уже настроены на рабочий адрес, "как буд-то так и было". |
Автор: | SII [ 12 янв 2011, 17:12 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
Обычно наиболее критичным является именно время исполнения, поэтому не стоит делать что-то заведомо существенно более медленное. Кроме того, незачем опасаться за целостность кода в памяти, надо лишь обеспечивать, чтобы его не мог модифицировать кто попало. В общем, думаю, целесообразно использовать формат исполняемых модулей, подобный формату объектных: в нём должна сохраняться вся информация о настройке на адрес загрузки, причём не модуля в целом (это обеспечивает и виндузовый ПЕ ЕХЕ, если принудительно не убивать таблицу перемещений, как это обычно делается), а отдельных программных секций (того, что в МАСМе именуется сегментами, но что не является сегментами в смысле архитектуры ИА-32; вроде в ФАСМе они секциями и именуются, но этого я не знаю, поскольку им не пользуюсь). Настройка в любом случае выполняется один раз -- при загрузке модуля в память, и осуществляет это код оси, который имеет полное право модифицировать всю память, в т.ч. и занимаемую кодом задач. Что касается адресации, опираясь на базовый адрес в одном из регистров, то эта идея тоже имеет полное право на существование; более того, существует немало процессорных архитектур, где иное попросту невозможно (например, ИБМовские мэйнфреймы или АРМ). Тут главная проблема в том, что у ИА-32 мало регистров, да к тому же все они имеют специальное назначение. Например, заняв под базу ЕСИ, мы автоматически лишаемся возможности использовать строковые команды. Именно поэтому разработчики Винды сделали финт ушами и используют ФС не как сегментный регистр, а как базовый (фактически, а не формально -- в чисто формальном смысле он, конечно, остался сегментным регистром): для использования в качестве РОНа он всё равно непригоден, а вот для хранения в нём базы чего-нибудь -- очень даже. Собственно, это сохраняется и в 64-разрядном режиме ИА-32, только там ФС и ГС уже официально стали базовыми, поскольку сегментация умерла. |
Автор: | qeos [ 13 янв 2011, 01:05 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
SII писал(а): поэтому разработчики Винды сделали финт ушами Об этом я совершенно не знал. Действительно можно использовать эти сегментные регистры! А я еще думал зачем их так много. |
Автор: | phantom-84 [ 13 янв 2011, 16:56 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
Релокация и позиционно-независимый код (можно и совместить) - это единственно возможные современные решения на IA32/AMD64 - от сегментации уже практически все отказались. У меня раньше дрова на основе сегментации работали. С введением релокации все стало значительно проще. В линуксе есть модули на основе позиционно-независимого кода. DSO вроде. Для их создания нужно просто указать спец. ключ компиляции. В AMD64 вообще все просто, т.к. появилась относительная адресация при обращении к данным (через rip). Объектники по сути используют механиз релокации, только помимо всего прочего содержат много бесполезной инфы. Я сначала хотел для дров использовать Object ELF, но потом это понят и сделал свой формат на основе релокации. |
Автор: | SII [ 13 янв 2011, 17:28 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
А тут речь не о сегментации как таковой, а об использовании сегментных регистров качестве базовых. Сегментация -- это когда память разделена на, вообще говоря, неперекрывающиеся сегменты, доступ к которым осуществляется через сегментные регистры. А здесь, хотя технически используются сегментные регистры, логически применяется обычная адресация относительно базы. Например, сегменты CS, SS, DS и ES отображены на адрес 0, сегмент GS -- на адрес 1000, а сегмент FS -- на адрес 2000. Тогда команда mov eax, gs:0 будет эквивалентна последовательности mov esi, 1000; mov eax, [esi]. Единственный недостаток такой базовой адресации по сравнению с обычной -- это невозможность изменить базу без помощи ОС (поскольку нужно менять соответствующий дескриптор сегмента, а не просто грузить в сегментный регистр нужное значение). |
Автор: | qeos [ 13 янв 2011, 19:44 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
phantom-84 писал(а): Релокация и позиционно-независимый код (можно и совместить) - это единственно возможные современные решения на IA32/AMD64 - от сегментации уже практически все отказались. У меня раньше дрова на основе сегментации работали. С введением релокации все стало значительно проще. В линуксе есть модули на основе позиционно-независимого кода. DSO вроде. Для их создания нужно просто указать спец. ключ компиляции. В AMD64 вообще все просто, т.к. появилась относительная адресация при обращении к данным (через rip). Объектники по сути используют механиз релокации, только помимо всего прочего содержат много бесполезной инфы. Я сначала хотел для дров использовать Object ELF, но потом это понят и сделал свой формат на основе релокации. вот, вот.. что-то похожее на то, что мне требуется.. использование %rip не совсем то что мне нужно. как описано в http://www.x86-64.org/documentation/assembly.html: Код: movl $0x1, 0x10(%rip) will store the value 0x1 10 bytes after the end of the instruction. т.е. задача наполовину решена: 1 код + 1 вариант данных = 1 объект. У меня идея реализовать выполнение кода (по сути код объекта) для разных данных. Т.е. несколько одинаковых объектов будут иметь разные пространства данных (1 код + много вариантов данных = много объектов). В связи с этим можно строить массивы объектов без ущерба ресурсам. Кстати, интересно узнать что за формат на основе релокации. Что изменил? что добавил? в чем преимущество? |
Автор: | phantom-84 [ 14 янв 2011, 11:46 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
Цитата: Единственный недостаток такой базовой адресации по сравнению с обычной -- это невозможность изменить базу без помощи ОС (поскольку нужно менять соответствующий дескриптор сегмента, а не просто грузить в сегментный регистр нужное значение). А каждый раз менять базу при помощи ОС нормально? Поэтому нужно этим пользоваться редко, а лучше вообще один раз для обеспечения сегментации при обращении к данному модулю извне (если этого не делает само ядро), а еще лучше вообще не пользоваться.Цитата: использование %rip не совсем то что мне нужно. Компилятор тебе нормальный нужен. Им должен поддерживаться спец. ключ компиляции, уточняющая директива для группы команд/отдельной команды или просто соглашение об адресации. Например, когда я на fasm'е в длинном режиме пишу mov byte [var],1, я знаю, что будет использоваться относительная адресация (относительно rip). А если мне нужно использовать абсолютную адресацию, то я должен написать mov byte [dword var],1.Цитата: Кстати, интересно узнать что за формат на основе релокации. Что изменил? что добавил? в чем преимущество? Формат предельно прост. Для драйверов я сохраняю одну единственную секцию с кодом и данными (вообще формат позволяет сохранять в файле две секции) плюс таблицу релокации.Модули ядра в формате DEF v4/a Модули ядра в формате DEF v3 |
Автор: | KIV [ 14 янв 2011, 17:02 ] |
Заголовок сообщения: | Re: Хранение кода и данных в памяти |
На мой взгляд самое лучше - пи код. Поскольку релоки могут занимать много места и требуют усложнения загрузчика. Но делать таблицу переменных считаю не рациональным - достаточно одного базового адреса, а смещения в этом блоке уже жёстко заданы в программе, хотя это не мешает разместить данные в любом месте памяти указав другую базу. Единственное ограничение в 32-битном режиме придётся забрать один регистр общего назначения (кстати, лучше не ESI, а EBX, чтобы не лишать программиста строковых команд). А вот в long mode пи код делать благодаря адресации относительно RIP можно очень легко. И самое главное практически без потери производительности и отнимания регистров у программиста (RIP не получится всё равно использовать как регистр общего назначения). В ассемблере fasm например единственное, что придётся сделать - загружать адрес в регистр не с помощью mov rax, label, а с помощью lea rax, [label]. Таким образом загрузчик исполняемых файлов может быть предельно простым, но потерь производительности как в случае использования таблицы адресов переменных не будет. Да и все более менее нормальные компиляторы умеют генерировать пи код. Как 32-битный, так и 64-битный. |
Страница 1 из 2 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |