Позиционно-независимый код
Позиционно-независимый код или PIC, является именем метода генерации кода, используемого в средах PowerPC, который позволяет динамическому компоновщику загружать область кода в нефиксированном адресе виртуальной памяти. Без некоторой формы позиционно-независимой генерации кода операционная система должна была бы поместить весь код, Вы хотели быть совместно использованными в фиксированных адресах в виртуальной памяти, которая сделает обслуживание операционной системы удивительно трудным. Например, было бы почти невозможно поддерживать совместно использованные библиотеки и платформы, потому что каждый должен будет быть предписан адрес, который никогда не мог изменяться.
Мужественный позиционно-независимый проект кода основывается на наблюдении что __DATA
сегмент всегда располагается при постоянном смещении от __TEXT
сегмент. Т.е. динамический загрузчик, при загрузке любого Мужественного файла, никогда не перемещает файл __TEXT
сегмент относительно __DATA
сегмент. Поэтому функция может использовать свой собственный текущий адрес плюс фиксированное смещение для определения расположения данных, к которым это хочет получить доступ. Все сегменты Мужественного файла, не только __TEXT
и __DATA
сегменты, при фиксированных смещениях относительно других сегментов.
Устранение позиционно-независимых ссылок кода
Позиционно-независимый код обычно требуется для совместно используемых библиотек и пакетов позволить динамическому загрузчику перемещать их к различным адресам во время загрузки. Однако это не требуется для приложений, обычно находящихся в том же адресе в виртуальной памяти. GCC 3.1 представляет новую опцию, вызванную -mdynamic-no-pic
. Эта опция и сокращает размер кода исполнимых программ приложения и улучшает их производительность путем устранения позиционно-независимых ссылок кода при сохранении непрямых вызовов совместно используемых библиотек и косвенности к неопределенным символам. При использовании XCode для создавания приложения, эта опция включена по умолчанию. Для примера динамического кода, сгенерированного без PIC, см. Перечисление 2.
Перечисление 2 показывает пример позиционно-независимого кода, сгенерированного для кода C в Перечислении 1.
Пример исходного кода перечисления 1 C для позиционно-независимого кода
struct s { int member1; int member2; }; |
struct s bar = {1,2}; |
int foo(void) |
{ |
return bar.member2; |
} |
Перечисление 2 Позиционно-независимый код, сгенерированный от примера C (с адресами в левом столбце)
.text |
; The function foo |
.align 2 |
.globl _foo |
0x0 _foo: mflr r0 ; save the link register (LR) |
0x4 bcl 20,31,L1$pb ; Use the branch always instruction |
; that does not affect the link |
; register stack to get the address |
; of L1$pb into the LR. |
0x8 L1$pb: mflr r10 ; then move LR to r10 |
0xc mtlr r0 ; restore the previous LR |
; bar is located at L1$pc + distance |
0x10 addis r9,r10,ha16(_bar-L1$pb); L1$pb plus high 16 bits of distance |
0x14 la r9,lo16(_bar-L1$pb)(r9) ; plus low 16 of distance |
; => r9 now contains address of bar |
0x18 lwz r3,4(r9) ; return bar.member2 |
0x1c blr |
.data |
; The initialized structure bar |
.align 2 |
.globl _bar |
0x20 _bar: .long 1 ; member1’s initialized value |
0x24 .long 2 ; member2’s initialized value |
Вычислить адрес _bar
, сгенерированный код добавляет адрес L1$pb
символ (0x8
) к расстоянию до bar
. Расстояние до bar
от адреса L1$pb
значение выражения _bar - L1$pb
, который является 0x18
(0x20 - 0x8
).
Перемещение позиционно-независимого кода
Поддерживать перемещение кода в промежуточных объектных файлах, Мужественные поддержки формат записи перемещения различия в разделе. Записи перемещения описаны в OS X ABI Мужественная Ссылка Формата файла.
Каждое добавление - непосредственные инструкции представлено двумя записями перемещения. Для addis
инструкция (в адресе 0x10
в примере), следующие таблицы приводят две записи перемещения. Поля первой записи перемещения (типа scattered_relocation_info
):
|
|
|
|
|
|
|
|
|
|
|
|
Значения второй записи перемещения:
|
|
|
|
|
|
|
|
|
|
|
|
Первая запись перемещения для la
инструкция (в адресе 0x14
в примере):
|
|
|
|
|
|
|
|
|
|
|
|
Значения второй записи перемещения:
|
|
|
|
|
|
|
|
|
|
|
|
Перемещения в x86-64 Среде
Перемещения в OS X x86-64 среда отличаются, чем перемещения в других средах OS X и System V x86-64 (http://www .x86-64.org/documentation). Основные отличия are:.
Рассеянные перемещения не используются
Сгенерированный компилятором код использует главным образом внешние перемещения
(Мужественный) Объект Маха, не Исполнимый и Связываемый Формат (ELF), используется в качестве формата исполняемого файла
В этом разделе описывается перемещения реализованы в OS X x86-64 среда.
Когда ассемблер генерирует перемещения, если целевая метка является локальной меткой (это начинается L
), предыдущая нелокальная метка в том же разделе используется в качестве цели внешнего перемещения. Слагаемое (т.е. 4
в _foo + 4
) используется с расстоянием от той нелокальной метки до целевой метки. Ассемблер использует внутреннее перемещение только, когда нет никакой предыдущей нелокальной метки в разделе.
Слагаемое кодируется в инструкции (Мужественный, не имеет RELA
перемещения). Для относительных PC перемещений слагаемое сохранено в инструкции. Эта практика отличается, чем в других средах OS X, кодирующих слагаемое минус текущее смещение раздела. x86-64 типы перемещения описаны в OS X ABI Мужественная Ссылка Формата файла.
Перечисление 3 показывает инструкции по сборке и перемещение и содержание раздела, что они генерируют.
Инструкции по сборке перечисления 3 В качестве примера и их соответствующие перемещения
call _foo |
r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
E8 00 00 00 00 |
call _foo+4 |
r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
E8 04 00 00 00 |
movq _foo@GOTPCREL(%rip), %rax |
r_type=X86_64_RELOC_GOT_LOAD, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
48 8B 05 00 00 00 00 |
pushq _foo@GOTPCREL(%rip) |
r_type=X86_64_RELOC_GOT, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
FF 35 00 00 00 00 |
movl _foo(%rip), %eax |
r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
8B 05 00 00 00 00 |
movl _foo+4(%rip), %eax |
r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
8B 05 04 00 00 00 |
movb $0x12, _foo(%rip) |
r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
C6 05 FF FF FF FF 12 |
movl $0x12345678, _foo(%rip) |
r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo |
C7 05 FC FF FF FF 78 56 34 12 |
.quad _foo |
r_type=X86_64_RELOC_UNSIGNED,r_length=3, r_extern=1,r_pcrel=0, r_symbolnum=_foo |
00 00 00 00 00 00 00 00 |
.quad _foo+4 |
r_type=X86_64_RELOC_UNSIGNED,r_length=3,r_extern=1,r_pcrel=0,r_symbolnum=_foo |
04 00 00 00 00 00 00 00 |
.quad _foo - _bar |
r_type=X86_64_RELOC_SUBTRACTOR,r_length=3,r_extern=1, r_pcrel=0,r_symbolnum=_bar |
r_type=X86_64_RELOC_UNSIGNED,r_length=3,r_extern=1, r_pcrel=0,r_symbolnum=_foo |
00 00 00 00 00 00 00 00 |
.quad _foo - _bar + 4 |
r_type=X86_64_RELOC_SUBTRACTOR,r_length=3, r_extern=1,r_pcrel=0,r_symbolnum=_bar |
r_type=X86_64_RELOC_UNSIGNED,r_length=3, r_extern=1,r_pcrel=0,r_symbolnum=_foo |
04 00 00 00 00 00 00 00 |
.long _foo - _bar |
r_type=X86_64_RELOC_SUBTRACTOR,r_length=2,r_extern=1,r_pcrel=0,r_symbolnum=_bar |
r_type=X86_64_RELOC_UNSIGNED,r_length=2,r_extern=1,r_pcrel=0,r_symbolnum=_foo |
00 00 00 00 |
lea L1(%rip), %rax |
r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_prev |
48 8d 05 12 00 00 00 |
// Assumes that _prev is the first nonlocal label 0x12 bytes before L1. |
lea L0(%rip), %rax |
r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3 |
48 8d 05 56 00 00 00 |
// Assumes that L0 is in third section, and has an address of 0x00000056 |
// in .o file, and no previous nonlocal label. |
.quad L1 |
r_type=X86_64_RELOC_UNSIGNED,r_length=3,r_extern=1,r_pcrel=0, r_symbolnum= _prev |
12 00 00 00 00 00 00 00 |
// Assumes that _prev is the first nonlocal label 0x12 bytes before L1. |
.quad L0 |
r_type=X86_64_RELOC_UNSIGNED,r_length=3, r_extern=0, r_pcrel=0, r_symbolnum= 3 |
56 00 00 00 00 00 00 00 |
// Assumes that L0 is in third section, and has address of 0x00000056 |
// in .o file, and no previous nonlocal label. |
.quad _foo - . |
r_type=X86_64_RELOC_SUBTRACTOR,r_length=3,r_extern=1,r_pcrel=0,r_symbolnum=_prev |
r_type=X86_64_RELOC_UNSIGNED,r_length=3,r_extern=1,r_pcrel=0,r_symbolnum=_foo |
EE FF FF FF FF FF FF FF |
// Assumes that _prev is the first nonlocal label 0x12 bytes |
// before this .quad |
.quad _foo - L1 |
r_type=X86_64_RELOC_SUBTRACTOR,r_length=3,r_extern=1,r_pcrel=0,r_symbolnum=_prev |
r_type=X86_64_RELOC_UNSIGNED,r_length=3,r_extern=1,r_pcrel=0,r_symbolnum=_foo |
EE FF FF FF FF FF FF FF |
// Assumes that _prev is the first nonlocal label 0x12 bytes before L1. |
.quad L1 - _prev |
// No relocations. This is an assembly time constant. |
12 00 00 00 00 00 00 00 |
// Assumes that _prev is the first nonlocal label 0x12 bytes before L |