Независимый от позиции код
Эта статья нуждается в дополнительных цитатах для проверки . ( январь 2007 г. ) |
В вычислениях позиционно -независимый код [ 1 ] ( ПИК [ 1 ] ) или независимый от позиции исполняемый файл ( PIE ) [ 2 ] представляет собой тело машинного кода , который выполняется правильно независимо от его адреса в памяти . [ а ] PIC обычно используется для разделяемых библиотек , чтобы один и тот же библиотечный код мог быть загружен в такое место адресного пространства каждой программы, где он не перекрывается с другой памятью, используемой, например, другими разделяемыми библиотеками. PIC также использовался в старых компьютерных системах, в которых не было MMU . [ 3 ] так что операционная система могла держать приложения отдельно друг от друга даже в пределах единого адресного пространства системы без MMU.
Независимый от позиции код может быть выполнен по любому адресу памяти без изменений. Это отличается от абсолютного кода, [ 1 ] который должен быть загружен в определенном месте для правильной работы, [ 1 ] и код , обнаруживаемый во время загрузки (LTL), [ 1 ] при котором компоновщик или загрузчик программ изменяет программу перед выполнением, поэтому ее можно запускать только из определенного участка памяти. [ 1 ] Генерация позиционно-независимого кода часто является поведением компиляторов по умолчанию , но они могут накладывать ограничения на использование некоторых функций языка, например, запрещать использование абсолютных адресов (позиционно-независимый код должен использовать относительную адресацию ). Инструкции, которые обращаются непосредственно к определенным адресам памяти, иногда выполняются быстрее, и замена их эквивалентными инструкциями относительной адресации может привести к немного более медленному выполнению, хотя современные процессоры делают разницу практически незначительной. [ 4 ]
История
[ редактировать ]В ранних компьютерах, таких как IBM 701 [ 5 ] (29 апреля 1952 г.) или код UNIVAC I (31 марта 1951 г.) не был независимым от позиции: каждая программа была создана для загрузки и запуска с определенного адреса. На этих ранних компьютерах не было операционной системы и они не были способны к многозадачности. Программы загружались в основную память (или даже сохранялись на магнитном барабане для выполнения непосредственно оттуда) и запускались по одной. В таком оперативном контексте позиционно-независимый код не был необходим.
Даже на базе и границах [ б ] В таких системах, как CDC 6600 , GE 625 и UNIVAC 1107 , как только ОС загружала код в хранилище заданий, он мог запускаться только с относительного адреса, по которому он был загружен.
Берроуз представил сегментированную систему B5000 (1961), в которой программы обращались к сегментам косвенно через управляющие слова в стеке или в справочной таблице программы (PRT); общий сегмент может быть адресован через разные местоположения PRT в разных процессах. Аналогично, в более позднем B6500 все ссылки на сегменты осуществлялись через позиции в кадре стека .
IBM System/360 (7 апреля 1964 г.) была разработана с усеченной адресацией, аналогичной UNIVAC III . [ 6 ] с учетом независимости позиции кода. При усеченной адресации адреса памяти вычисляются на основе базового регистра и смещения. В начале программы программист должен установить адресацию , загрузив базовый регистр; обычно программист также информирует ассемблер псевдооперацией . USING Программист может загрузить базовый регистр из регистра, который, как известно, содержит адрес точки входа, обычно R15, или может использовать команду BALR (форма ветвления и связи, регистра) (со значением R2, равным 0) для сохранения адреса следующей последовательной инструкции. в базовый регистр, который затем явно или неявно кодировался в каждой инструкции, которая ссылалась на место хранения в программе. Можно использовать несколько базовых регистров для кода или данных. Такие инструкции требуют меньше памяти, поскольку им не обязательно хранить полный 24-, 31-, 32- или 64-битный адрес (4 или 8 байтов), а вместо этого нужно хранить номер базового регистра (закодированный в 4 бита) и 12-битное смещение адреса. (закодированный в 12 битах), требующий всего два байта.
Этот метод программирования является стандартным для систем типа IBM S/360. Он использовался вплоть до сегодняшнего IBM System/z. При кодировании на языке ассемблера программист должен установить адресацию программы, как описано выше, а также использовать другие базовые регистры для динамически выделяемой памяти. Компиляторы автоматически заботятся об этом виде адресации.
Ранняя операционная система IBM DOS/360 (1966) не использовала виртуальное хранилище (поскольку ранние модели System S/360 не поддерживали его), но имела возможность размещать программы в произвольном (или автоматически выбранном) месте хранения. во время загрузки через имя PHASE*, оператор JCL (Job Control Language).
Таким образом, в системах S/360 без виртуальной памяти программа могла быть загружена в любое место хранения, но для этого требовалась непрерывная область памяти, достаточно большая для хранения этой программы. Иногда фрагментация памяти происходила из-за загрузки и выгрузки модулей разного размера. Виртуальное хранилище по замыслу не имеет такого ограничения.
Хотя DOS/360 и OS/360 не поддерживали PIC, временные процедуры SVC в OS/360 не могли содержать перемещаемые адресные константы и могли выполняться в любой из временных областей без перемещения .
IBM впервые представила виртуальное хранилище на IBM System/360 модели 67 в (1965 году) для поддержки первой многозадачной операционной системы IBM с разделением времени TSS/360. Все более поздние версии DOS/360 (DOS/VS и т. д.) и более поздние операционные системы IBM использовали виртуальное хранилище. Усеченная адресация осталась частью базовой архитектуры и по-прежнему полезна, когда несколько модулей необходимо загрузить в одно и то же виртуальное адресное пространство.
Для сравнения: в ранних сегментированных системах, таких как Burroughs MCP на Burroughs B5000 (1961) и Multics (1964), а также в системах подкачки, таких как IBM TSS/360 (1967). [ с ] Код также был по своей сути независимым от позиции, поскольку виртуальные адреса подпрограмм в программе располагались в частных данных, внешних по отношению к коду, например, в справочной таблице программы, сегменте связи, разделе прототипа.
Изобретение динамической трансляции адресов (функция, предоставляемая MMU ) первоначально уменьшило потребность в независимом от позиции коде, поскольку каждый процесс мог иметь свое собственное независимое адресное пространство (диапазон адресов). Однако несколько одновременных заданий, использующих один и тот же код, привели к пустой трате физической памяти. Если два задания выполняют полностью идентичные программы, динамическая трансляция адресов обеспечивает решение, позволяя системе просто сопоставить адрес 32 КБ двух разных заданий с одними и теми же байтами реальной памяти, содержащими одну копию программы.
Разные программы могут иметь общий код. Например, программа расчета заработной платы и программа расчета дебиторской задолженности могут содержать идентичную подпрограмму сортировки. Общий модуль (общая библиотека — это разновидность общего модуля) загружается один раз и отображается в два адресных пространства.
SunOS 4.x и ELF
[ редактировать ]Вызовы процедур внутри общей библиотеки обычно выполняются через небольшие заглушки таблицы связей процедур (PLT) , которые затем вызывают определенную функцию. Это, в частности, позволяет общей библиотеке наследовать определенные вызовы функций из ранее загруженных библиотек, а не использовать свои собственные версии. [ 7 ]
Ссылки на данные из независимого от позиции кода обычно выполняются косвенно, через таблицы глобальных смещений (GOT), в которых хранятся адреса всех доступных глобальных переменных . На каждую единицу компиляции или объектный модуль приходится один GOT, и он расположен с фиксированным смещением от кода (хотя это смещение неизвестно до тех пор, пока библиотека не будет скомпонована ). Когда компоновщик связывает модули для создания общей библиотеки, он объединяет GOT и устанавливает окончательные смещения в коде. Нет необходимости корректировать смещения при последующей загрузке общей библиотеки. [ 7 ]
Независимые от позиции функции, обращающиеся к глобальным данным, начинают с определения абсолютного адреса GOT с учетом собственного текущего значения счетчика программы. Это часто принимает форму поддельного вызова функции, чтобы получить возвращаемое значение в стеке ( x86 ), в определенном стандартном регистре ( SPARC , MIPS ) или специальном регистре ( POWER / PowerPC / Power ISA ), который затем может быть перемещен в предопределенный стандартный регистр или получить его в этот стандартный регистр ( PA-RISC , Alpha , ESA/390 и z/Architecture ). Некоторые архитектуры процессоров, такие как Motorola 68000 , ARM , x86-64 , более новые версии z/Architecture, Motorola 6809 , WDC 65C816 и Кнута MMIX , позволяют ссылаться на данные по смещению от счетчика программ . Это специально направлено на то, чтобы сделать позиционно-независимый код меньше, менее требовательным к регистрам и, следовательно, более эффективным.
Библиотеки DLL Windows
[ редактировать ]Этот раздел нуждается в дополнительных цитатах для проверки . ( Апрель 2018 г. ) |
Библиотеки динамической компоновки (DLL) в Microsoft Windows используют вариант E8 инструкции CALL (вызов рядом, относительно, смещение относительно следующей инструкции). Эти инструкции не требуют изменения при загрузке DLL.
Ожидается, что некоторые глобальные переменные (например, массивы строковых литералов, таблицы виртуальных функций) будут содержать адрес объекта в разделе данных или в разделе кода динамической библиотеки; поэтому сохраненный адрес в глобальной переменной должен быть обновлен, чтобы отразить адрес, по которому была загружена DLL. Динамический загрузчик вычисляет адрес, на который ссылается глобальная переменная, и сохраняет значение в такой глобальной переменной; это запускает копирование при записи страницы памяти, содержащей такую глобальную переменную. Страницы с кодом и страницы с глобальными переменными, не содержащими указателей на код или глобальные данные, остаются общими для процессов. Эту операцию необходимо проделать в любой ОС, которая может загружать динамическую библиотеку по произвольному адресу.
В Windows Vista и более поздних версиях Windows перемещение DLL и исполняемых файлов выполняется диспетчером памяти ядра, который распределяет перемещенные двоичные файлы по нескольким процессам. Изображения всегда перемещаются со своих предпочтительных базовых адресов, обеспечивая рандомизацию расположения адресного пространства (ASLR). [ 8 ]
Версии Windows до Vista требуют, чтобы системные библиотеки DLL были предварительно связаны по неконфликтным фиксированным адресам во время компоновки, чтобы избежать перемещения образов во время выполнения. Перемещение во время выполнения в этих старых версиях Windows выполняется загрузчиком DLL в контексте каждого процесса, и полученные в результате перемещенные части каждого образа больше не могут использоваться совместно между процессами.
Обработка DLL в Windows отличается от более ранней процедуры OS/2 , от которой она произошла. OS/2 представляет третью альтернативу и пытается загружать библиотеки DLL, которые не являются независимыми от позиции, в выделенную «общую арену» в памяти и отображает их после загрузки. Все пользователи DLL могут использовать одну и ту же копию в памяти.
Мультикс
[ редактировать ]В Multics каждая процедура концептуально [ д ] имеет сегмент кода и сегмент связи. [ 9 ] [ 10 ] Сегмент кода содержит только код, а раздел связи служит шаблоном для нового сегмента связи. Регистр указателя 4 (PR4) указывает на сегмент связи процедуры. Вызов процедуры сохраняет PR4 в стеке перед загрузкой его указателем на сегмент связи вызываемой стороны. При вызове процедуры используется пара косвенных указателей. [ 11 ] с флагом, вызывающим ловушку при первом вызове, чтобы механизм динамической связи мог добавить новую процедуру и ее сегмент связи в таблицу известных сегментов (KST), построить новый сегмент связи, поместить номера их сегментов в раздел связи вызывающей стороны. и сбросьте флаг в паре косвенных указателей.
ТСС
[ редактировать ]В системе разделения времени IBM S/360 (TSS/360 и TSS/370) каждая процедура может иметь открытый CSECT, доступный только для чтения, и доступную для записи частную секцию прототипа (PSECT). Вызывающий загружает V-константу для подпрограммы в общий регистр 15 (GR15) и копирует R-константу для PSECT подпрограммы в 19-е слово области сохранения, обозначенное как GR13. [ 12 ]
Динамический загрузчик [ 13 ] не загружает страницы программы и не разрешает адресные константы до тех пор, пока не произойдет ошибка первой страницы.
Независимые от позиции исполняемые файлы
[ редактировать ]Позиционно-независимые исполняемые файлы (PIE) — это исполняемые двоичные файлы, полностью созданные из позиционно-независимого кода. Хотя некоторые системы запускают только исполняемые файлы PIC, существуют и другие причины их использования. Двоичные файлы PIE используются в некоторых ориентированных на безопасность Linux, дистрибутивах , чтобы позволить PaX или Exec Shield использовать рандомизацию макета адресного пространства (ASLR), чтобы злоумышленники не знали, где находится существующий исполняемый код во время атаки на безопасность, используя эксплойты , которые полагаются на знание смещения исполняемый код в двоичном формате, например атаки с возвратом в libc . (Официальное ядро Linux, начиная с версии 2.6.12 2005 года, имеет более слабый ASLR, который также работает с PIE. Он слабый в том смысле, что случайность применяется ко всем файловым единицам ELF.) [ 14 ]
от Apple MacOS и iOS полностью поддерживают исполняемые файлы PIE версий 10.7 и 4.3 соответственно; предупреждение выдается, когда исполняемые файлы iOS, не относящиеся к PIE, отправляются на утверждение в Apple App Store, но жестких требований пока нет [ когда? ] и заявки, не относящиеся к PIE, не отклоняются. [ 15 ] [ 16 ]
В OpenBSD PIE включен по умолчанию на большинстве архитектур, начиная с OpenBSD 5.3, выпущенного 1 мая 2013 года. [ 17 ] Поддержка PIE в статически связанных двоичных файлах, таких как исполняемые файлы в /bin
и /sbin
каталоги, был добавлен ближе к концу 2014 года. [ 18 ] openSUSE добавил PIE по умолчанию в версии 2015-02. Начиная с Fedora 23, сопровождающие Fedora решили создавать пакеты с включенным PIE по умолчанию. [ 19 ] В Ubuntu 17.10 PIE включен по умолчанию во всех архитектурах. [ 20 ] . Новые профили Gentoo теперь поддерживают PIE по умолчанию [ 21 ] Примерно в июле 2017 года Debian включил PIE по умолчанию. [ 22 ]
Android включил поддержку PIE в Jelly Bean [ 23 ] и удалена поддержка компоновщика, отличного от PIE, в Lollipop . [ 24 ]
См. также
[ редактировать ]Примечания
[ редактировать ]- ^ Это позволяет каждому процессу, использующему общую копию, видеть ее по другому виртуальному адресу.
- ^ Но для каждого задания загружалась отдельная копия кода.
- ^ Хотя TSS/360 поддерживал общий PIC, это было верно не для всех систем подкачки.
- ^ Имеются некоторые технические отклонения по причинам производительности, которые выходят за рамки этой статьи.
Ссылки
[ редактировать ]- ^ Перейти обратно: а б с д и ж «Типы объектного кода». Справочное руководство по загрузчику приложений iRMX 86 (PDF) . Интел . стр. 1-2, 1-3 . Проверено 21 августа 2017 г.
[…] Абсолютный код и абсолютный объектный модуль — это код, который был обработан LOC86 для запуска только в определенном месте памяти. Загрузчик . загружает абсолютный объектный модуль только в определенное место, которое модуль должен занимать Независимый от позиции код (обычно называемый PIC) отличается от абсолютного кода тем, что PIC можно загрузить в любую ячейку памяти. Преимущество PIC перед абсолютным кодом заключается в том, что PIC не требует резервирования определенного блока памяти. Когда загрузчик загружает PIC, он получает сегменты памяти iRMX 86 из пула задания вызывающей задачи и загружает PIC в эти сегменты. Ограничение, касающееся PIC, заключается в том, что, как и в модели сегментации PL/M-86 COMPACT […], он может иметь только один сегмент кода и один сегмент данных, вместо того, чтобы позволять базовым адресам этих сегментов и, следовательно, самим сегментам , динамически изменяются. Это означает, что программы PIC обязательно имеют длину менее 64 КБ. Код PIC может быть создан с помощью элемента управления BIND LINK86. Код, размещаемый во время загрузки (обычно называемый LTL-кодом), является третьей формой объектного кода. Код LTL аналогичен PIC тем, что код LTL можно загрузить в любом месте памяти. Однако при загрузке LTL-кода загрузчик изменяет базовую часть указателей так, чтобы указатели не зависели от исходного содержимого регистров микропроцессора. Благодаря этому исправлению (корректировке базовых адресов) код LTL может использоваться задачами, имеющими более одного сегмента кода или более одного сегмента данных. Это означает, что программы LTL могут иметь длину более 64 КБ. FORTRAN 86 и Pascal 86 автоматически создают код LTL даже для коротких программ. Код LTL может быть создан с помощью элемента управления BIND LINK86. […]
- ^ «Позиционно-независимые исполняемые файлы (PIE)» .
- ^ Левин, Джон Р. (2000) [октябрь 1999 г.]. «Глава 8: Загрузка и наложения» . Линкеры и загрузчики . Серия Моргана Кауфмана по разработке программного обеспечения и программированию (1-е изд.). Сан-Франциско, США: Морган Кауфманн . стр. 170–171. ISBN 1-55860-496-0 . OCLC 42413382 . ISBN 978-1-55860-496-4 . Архивировано из оригинала 5 декабря 2012 г. Проверено 12 января 2020 г. Код: [1] [2] Ошибки: [3]
- ^ Габерт, Александр (январь 2004 г.). «Внутренние положения независимого от позиции кода» . Укрепленный Gentoo . Проверено 3 декабря 2009 г.
[…] прямая адресация без поддержки PIC всегда дешевле (читай: быстрее), чем адресация PIC. […]
- ^ «Объявлено 701» , IBM , 29 апреля 1952 г.
- ^ Справочное руководство Система обработки данных UNIVAC III (PDF) . Корпорация Сперри Рэнд . 1962. УТ-2488.
- ^ Перейти обратно: а б Гингелл, Роберт А.; Ли, Мэн; Данг, Сюонг Т.; Уикс, Мэри С. Общие библиотеки в SunOS (PDF) . 1987 Летняя техническая конференция и выставка USENIX. стр. 131–146.
- ^ «Достижения в области управления памятью для Windows» . Посмотреть.officeapps.live.com . Проверено 23 июня 2017 г.
- ^ Органик, Эллиот Ирвинг (1972). Система Мультикс; исследование его структуры . МТИ Пресс . ISBN 9780262150125 . LCCN 78157477 .
- ^ Дейли, Роберт С.; Деннис, Джек Б. (май 1968 г.). «Виртуальная память, процессы и совместное использование в Multics» . Коммуникации АКМ . 11 (5). Ассоциация вычислительной техники : 306–312 . Проверено 21 июля 2024 г.
- ^ «Раздел 6 Формирование виртуального адреса», РУКОВОДСТВО ПО МУЛЬТИЧЕСКОМУ ПРОЦЕССОРУ DPS/LEVEL 68 и DPS 8M (PDF) (ред. 1-е изд.), Honeywell Information Systems Inc. , 1982, стр. 6–21, AL39 , получено 03.03.2023 г. 25
- ^ «Раздел 3: TSS для программиста Svslcm». Концепции и возможности системы разделения времени IBM (PDF) (Седьмое изд.). Апрель 1978 г. с. 61. GC28-2003-6.
- ^ Динамический загрузчик системы разделения времени IBM System / 360 (PDF) (Четвертое изд.). Сентябрь 1971 г. GY28-2031-3.
- ^ Леттьери, Г. «Рандомизация макета адресного пространства» (PDF) .
- ^ «iphone — двоичный файл, не относящийся к PIE — исполняемый файл «имя проекта» не является независимым от позиции исполняемым файлом. — Переполнение стека» . stackoverflow.com .
- ^ «Библиотека разработчиков iOS» . apple.com .
- ^ «Выпуск OpenBSD 5.3» . 01.05.2013 . Проверено 9 мая 2020 г.
- ^ «Внимание: обновления моментальных снимков для Static PIE» . 24 декабря 2014 г. Проверено 24 декабря 2014 г.
- ^ «Изменения/укрепление всех пакетов — FedoraProject» . Fedoraproject.org .
- ^ «Команда Ubuntu Foundations — еженедельный информационный бюллетень, 15 июня 2017 г.» . 15 июня 2017 г. Проверено 17 июня 2017 г.
- ^ «Новые профили версии 17.0 в репозитории Gentoo» . 30 ноября 2017 г. Проверено 10 декабря 2017 г.
- ^ Лян, Мудонг (08 августа 2017 г.). «Когда Debian решил включить PIE по умолчанию?» . debian.org . Проверено 6 июля 2021 г.
- ^ «Усовершенствования безопасности в Android 1.5–4.1 — проект Android с открытым исходным кодом» . Проект Android с открытым исходным кодом .
- ^ «Усовершенствования безопасности в Android 5.0 — проект Android с открытым исходным кодом» . Проект Android с открытым исходным кодом .