Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

В вычислении , позиционно-независимый код [1] ( ПИК [1] ) или позиционно-независимый исполняемый ( PIE ) [2] является органом машинного кода , который, будучи помещен где - то в первичной памяти , выполняет должным образом , независимо от его абсолютного адреса . PIC обычно используется для разделяемых библиотек , так что один и тот же код библиотеки может быть загружен в место в каждом адресном пространстве программы, где он не перекрывается с другой используемой памятью (например, другими разделяемыми библиотеками). PIC также использовался в старых компьютерных системах, в которых не было MMU , [3]так что операционная система может держать приложения подальше друг от друга даже в пределах единого адресного пространства системы без MMU.

Позиционно-независимый код может выполняться по любому адресу памяти без изменений. Это отличается от абсолютного кода , [1] , который должен быть загружен в определенном месте функционировать правильно, [1] и время загрузки передвижного (LTL) кода, [1] , в которой линкер или загрузчик программы модифицирует программа , прежде чем выполнение так его можно запустить только из определенного места в памяти. [1] Генерация позиционно-независимого кода часто является поведением по умолчанию для компиляторов , но они могут накладывать ограничения на использование некоторых языковых функций, таких как запрет на использование абсолютных адресов (позиционно-независимый код должен использоватьотносительная адресация ). Команды, которые относятся непосредственно к конкретным адресам памяти, иногда выполняются быстрее, и замена их эквивалентными инструкциями относительной адресации может привести к немного более медленному выполнению, хотя современные процессоры делают разницу практически незначительной. [4]

История [ править ]

В ранних компьютерах, таких как IBM 701 [5] (29 апреля 1952 г.) или UNIVAC I (31 марта 1951 г.), код был позиционно-зависимым: каждая программа была построена для загрузки и запуска с определенного адреса. На этих ранних компьютерах не было операционной системы и многозадачности. Программы загружались в основное хранилище (или даже сохранялись на магнитном барабане для выполнения непосредственно оттуда) и запускались по одной за раз. В таком оперативном контексте не было необходимости в позиционно-независимом коде.

IBM System / 360 (7 апреля 1964) был разработан с усеченным адресации аналогично в UNIVAC III , [6] с кодом позиции независимости в виду. При усеченной адресации адреса памяти вычисляются из базового регистра и смещения. В начале программы программист должен установить адресуемость , загрузив базовый регистр; обычно программист также сообщает ассемблеру псевдооперацию USING . Программист может загрузить базовый регистр из регистра, который, как известно, содержит адрес точки входа, обычно R15, или может использовать BALR (Branch And Link, Register form).инструкция (со значением 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 (язык управления заданиями).

Таким образом, в системах S / 360 без виртуальной памяти программа могла быть загружена в любое место хранения, но для этого требовалась непрерывная область памяти, достаточно большая для хранения этой программы. Иногда фрагментация памяти может происходить из-за загрузки и выгрузки модулей разного размера. Виртуальное хранилище - по замыслу - не имеет этого ограничения.

Хотя DOS / 360 и OS / 360 не поддерживали PIC, временные процедуры SVC в OS / 360 не могли содержать перемещаемые адресные константы и могли работать в любой из временных областей без перемещения.

Виртуальная память была впервые представлена ​​в IBM System / 360 model 67 в (1965 г.) для поддержки первой многозадачной операционной системы и операционной системы с разделением времени TSS / 360. Более поздние версии DOS / 360 (DOS / VS и т. Д.) И более поздние операционные системы IBM использовали виртуальную память. Усеченная адресация осталась частью базовой архитектуры и по-прежнему имеет преимущество, когда несколько модулей должны быть загружены в одно и то же виртуальное адресное пространство.

Другие ранние сегментированные системы, такие как Burroughs MCP на Burroughs B5000 (1961) и Multics (1964), системы подкачки, такие как IBM TSS / 360 (1967) [a] или системы с основанием и границами [b] , такие как GECOS на GE 625 и EXEC на UNIVAC 1107 , код также изначально не зависел от позиции, поскольку адреса в программе были относительны к текущему сегменту, а не абсолютны.

Изобретение динамической трансляции адресов (функция, предоставляемая MMU ) первоначально уменьшило потребность в позиционно-независимом коде, поскольку каждый процесс мог иметь собственное независимое адресное пространство (диапазон адресов). Однако выполнение нескольких одновременных заданий с использованием одного и того же кода приводит к неэффективной трате физической памяти. Если два задания запускают полностью идентичные программы, динамическое преобразование адресов обеспечивает решение, позволяя системе просто отображать адрес 32 КБ двух разных заданий в одни и те же байты реальной памяти, содержащие единственную копию программы.

Различные программы могут иметь общий код. Например, программа расчета заработной платы и программа расчета с клиентами могут содержать идентичную подпрограмму сортировки. Общий модуль (общая библиотека - это форма общего модуля) загружается один раз и отображается в два адресных пространства.

Технические детали [ править ]

Вызов процедур внутри разделяемой библиотеки обычно выполняется через небольшие заглушки таблицы связывания процедур , которые затем вызывают окончательную функцию. Это, в частности, позволяет разделяемой библиотеке наследовать определенные вызовы функций из ранее загруженных библиотек, а не использовать свои собственные версии.

Ссылки на данные из позиционно-независимого кода обычно делаются косвенно, через глобальные таблицы смещения (GOT), в которых хранятся адреса всех доступных глобальных переменных . На каждую единицу компиляции или объектный модуль приходится один GOT, и он расположен с фиксированным смещением от кода (хотя это смещение неизвестно до тех пор, пока библиотека не будет связана ). Когда компоновщик связывает модули для создания общей библиотеки, он объединяет GOT и устанавливает окончательные смещения в коде. При последующей загрузке общей библиотеки нет необходимости настраивать смещения.

Независимые от позиции функции, обращающиеся к глобальным данным, начинают с определения абсолютного адреса GOT по их собственному текущему значению программного счетчика. Это часто принимает форму поддельного вызова функции для получения возвращаемого значения в стеке ( x86 ) или в специальном регистре ( PowerPC , SPARC , MIPS , возможно, по крайней мере, некоторые другие процессоры RISC [ ласковые слова ] , ESA / 390 ). , который затем может быть сохранен в заранее определенном стандартном регистре. Некоторые архитектуры процессоров, такие как Motorola 68000 , Motorola 6809 , WDC 65C816 , MMIX Кнута , ARM и x86-64 позволяют ссылаться на данные по смещению от счетчика программ . Это специально нацелено на то, чтобы сделать независимый от позиции код меньшим, менее требовательным к регистрам и, следовательно, более эффективным.

DLL Windows [ править ]

Библиотеки динамической компоновки (DLL) в Microsoft Windows используют вариант E8 инструкции CALL (вызов рядом, относительный, смещение относительно следующей инструкции). Эти инструкции не нужно исправлять при загрузке DLL.

Ожидается, что некоторые глобальные переменные (например, массивы строковых литералов, таблицы виртуальных функций) будут содержать адрес объекта в разделе данных, соответственно, в разделе кода динамической библиотеки; следовательно, сохраненный адрес в глобальной переменной должен быть обновлен, чтобы отразить адрес, по которому была загружена DLL. Динамический загрузчик вычисляет адрес, на который указывает глобальная переменная, и сохраняет значение в такой глобальной переменной; это вызывает копирование при записи страницы памяти, содержащей такую ​​глобальную переменную. Страницы с кодом и страницы с глобальными переменными, не содержащие указателей на код или глобальные данные, остаются совместно используемыми между процессами. Эта операция должна выполняться в любой ОС, которая может загружать динамическую библиотеку по произвольному адресу.

В Windows Vista и более поздних версиях Windows перемещение библиотек DLL и исполняемых файлов выполняется диспетчером памяти ядра, который разделяет перемещенные двоичные файлы между несколькими процессами. Изображения всегда перемещаются с их предпочтительных базовых адресов, обеспечивая рандомизацию разметки адресного пространства (ASLR). [7]

Версии Windows до Vista требуют, чтобы системные библиотеки DLL были предварительно связаны по неконфликтным фиксированным адресам во время связывания, чтобы избежать перемещения изображений во время выполнения. Перемещение среды выполнения в этих более старых версиях Windows выполняется загрузчиком DLL в контексте каждого процесса, и результирующие перемещенные части каждого образа больше не могут использоваться совместно между процессами.

Работа с библиотеками DLL в Windows отличается от более ранней процедуры OS / 2 , от которой она является производным. OS / 2 представляет третью альтернативу и пытается загрузить библиотеки DLL, которые не зависят от позиции, в выделенную «общую арену» в памяти и отображает их после загрузки. Все пользователи DLL могут использовать одну и ту же копию в памяти.

Мультики [ править ]

В Multics каждая процедура концептуально [c] имеет сегмент кода и сегмент связи. Сегмент кода содержит только код, а раздел связывания служит шаблоном для нового сегмента связывания. Регистр указателя 4 (PR4) указывает на сегмент связи процедуры. Вызов процедуры сохраняет PR4 в стеке перед загрузкой его с указателем на сегмент связи вызываемого объекта. Вызов процедуры использует пару косвенных указателей [8] с флагом, чтобы вызвать прерывание при первом вызове, чтобы механизм динамического связывания мог добавить новую процедуру и ее сегмент связывания в таблицу известных сегментов (KST), построить новую связь сегмент, поместите их номера сегментов в раздел связывания вызывающего абонента и сбросьте флаг в паре косвенных указателей.

TSS [ править ]

В системе разделения времени IBM S / 360 (TSS / 360 и TSS / 370) каждая процедура может иметь общедоступную CSECT только для чтения и частную секцию прототипа с возможностью записи (PSECT). Вызывающий загружает V-константу для подпрограммы в общий регистр 15 (GR15) и копирует R-константу для PSECT подпрограммы в 19-е слово области сохранения, обозначенной как GR13. [9]

Динамический загрузчик [10] не загружает страницы программы и не разрешает адресные константы до отказа первой страницы.

Независимые от позиции исполняемые файлы [ править ]

Позиционно-независимые исполняемые файлы (PIE) - это исполняемые двоичные файлы, полностью состоящие из позиционно-независимого кода. Хотя в некоторых системах выполняются только исполняемые файлы PIC, есть и другие причины, по которым они используются. Двоичные файлы PIE используются в некоторых дистрибутивах Linux, ориентированных на безопасность, чтобы позволить PaX или Exec Shield использовать рандомизацию разметки адресного пространства, чтобы злоумышленники не знали, где находится существующий исполняемый код во время атаки безопасности, используя эксплойты, которые полагаются на знание смещения исполняемого кода в двоичный файл, например, атаки с возвратом к libc .

MacOS и iOS от Apple полностью поддерживают исполняемые файлы PIE, начиная с версий 10.7 и 4.3 соответственно; выдается предупреждение, когда исполняемые файлы iOS, отличные от PIE, отправляются на утверждение в Apple App Store, но жестких требований пока нет [ когда? ] и заявки, не относящиеся к PIE, не отклоняются. [11] [12]

OpenBSD с включенным PIE по умолчанию на большинстве архитектур , так как OpenBSD 5.3, выпущенный 1 мая 2013 года [13] Поддержка PIE в статически связанных исполняемых файлов, таких как исполняемые файлы в /binи /sbinкаталогах, была добавлена в конце 2014 года [14] OpenSUSE добавлен PIE по умолчанию в 2015-02. Начиная с Fedora  23, сопровождающие Fedora решили создавать пакеты с включенным PIE по умолчанию. [15] В Ubuntu 17.10 PIE включен по умолчанию на всех архитектурах. [16] Новые профили Gentoo теперь по умолчанию поддерживают PIE. [17]

Android включил поддержку PIE в Jelly Bean [18] и удалил поддержку компоновщика без PIE в Lollipop . [19]

См. Также [ править ]

  • Динамический компоновщик
  • Файл объекта
  • Сегмент кода

Заметки [ править ]

  1. ^ Хотя TSS / 360 поддерживал общий PIC, это не относилось ко всем системам подкачки
  2. ^ Но для каждого задания загружалась отдельная копия кода.
  3. ^ Существуют некоторые технические отклонения по причинам производительности, которые выходят за рамки этой статьи.

Ссылки [ править ]

  1. ^ a b c d e f "Типы объектного кода". Справочное руководство загрузчика приложений iRMX 86 (PDF) . Intel . С. 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. […]
  2. ^ Позиционно-независимые исполняемые файлы (PIE)
  3. ^ Левин, Джон Р. (2000) [октябрь 1999]. «Глава 8: Загрузка и наложения» . Линкеры и загрузчики . Серия Морган Кауфманн в программной инженерии и программировании (1-е изд.). Сан-Франциско, США: Морган Кауфманн . С. 170–171. ISBN 1-55860-496-0. OCLC  42413382 . ISBN 978-1-55860-496-4 . Архивировано 05 декабря 2012 года . Проверено 12 января 2020 . Код: [1] [2] Ошибки: [3]
  4. ^ Габерт, Александр (январь 2004 г.). «Внутреннее устройство независимого от позиции кода» . Закаленный Gentoo . Проверено 3 декабря 2009 . […] Прямая адресация без поддержки PIC всегда дешевле (читай: быстрее), чем адресация PIC. […]
  5. ^ "701 объявлено" , IBM , 1952-04-29
  6. ^ Справочное руководство UNIVAC III Data Processing System (PDF) . Sperry Rand Corporation. 1962. УТ-2488.
  7. ^ «Достижения в управлении памятью для Windows» . View.officeapps.live.com . Проверено 23 июня 2017 .
  8. ^ «Раздел 6 Формирование виртуального адреса», DPS / LEVEL 68 & DPS 8M MULTICS PROCESSOR MANUAL (PDF) (Rev. 1 ed.), Honeywell Information Systems Inc. , 1982, стр. 6–21, AL39
  9. ^ «Раздел 3: TSS для: Svslcm Programmer». Концепции и средства системы разделения времени IBM (PDF) (седьмое изд.). Апрель 1978 г. с. 61. GC28-2003-6.
  10. ^ IBM System / 360 Time Sharing System Dynamic Loader (PDF) (Четвертое изд.). Сентябрь 1971 г. GY28-2031-3.
  11. ^ «iphone - Двоичный файл без PIE -« Имя проекта »исполняемого файла не является независимым от позиции исполняемым файлом. - Переполнение стека» . stackoverflow.com .
  12. ^ «Библиотека разработчика iOS» . apple.com .
  13. ^ "OpenBSD 5.3 Release" . 2013-05-01 . Проверено 9 мая 2020 .
  14. ^ «Внимание: обновления снимков для статического пирога» . 2014-12-24 . Проверено 24 декабря 2014 .
  15. ^ «Изменения / Усиление всех пакетов - FedoraProject» . fedoraproject.org .
  16. ^ «Команда основателей Ubuntu - Еженедельный бюллетень, 2017-06-15» . 2017-06-15 . Проверено 17 июня 2017 .
  17. ^ "Новые профили 17.0 в репозитории Gentoo" . 2017-11-30 . Проверено 10 декабря 2017 .
  18. ^ «Улучшения безопасности в Android 1.5–4.1 - Android Open Source Project» . Проект с открытым исходным кодом Android .
  19. ^ «Улучшения безопасности в Android 5.0 - Android Open Source Project» . Проект с открытым исходным кодом Android .

Внешние ссылки [ править ]

  • Введение в позиционно-независимый кодекс
  • Внутреннее устройство независимого от позиции кода
  • Программирование на языке ассемблера с помощью PIC
  • Любопытный случай позиционно-независимых исполняемых файлов