Позиционно-независимый код

Позиционно-независимый код или 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):

r_scattered

1— истина

r_pcrel

0— ложь

r_length

2— указание 4 байтов

r_type

PPC_RELOC_HA16_SECTDIFF

r_address

0x10— адрес addis инструкция

r_value

0x20— адрес символа _bar

Значения второй записи перемещения:

r_scattered

1— истина

r_pcrel

0— ложь

r_length

2— указание 4 байтов

r_type

PPC_RELOC_PAIR

r_address

0x18— низкие 16 битов выражения (_bar - L1$pb)

r_value

0x8— адрес символа L1$pb

Первая запись перемещения для la инструкция (в адресе 0x14 в примере):

r_scattered

1— истина

r_pcrel

0— ложь

r_length

2— указание 4 байтов

r_type

PPC_RELOC_LO16_SECTDIFF

r_address

0x14— адрес addi инструкция

r_value

0x20— адрес символа _bar

Значения второй записи перемещения:

r_scattered

1— истина

r_pcrel

0— ложь

r_length

2— указание 4 байтов

r_type

PPC_RELOC_PAIR

r_address

0x0— высокие 16 битов выражения (_bar - L1$pb)

r_value

0x8— адрес символа L1$pb

Перемещения в x86-64 Среде

Перемещения в OS X x86-64 среда отличаются, чем перемещения в других средах OS X и System V x86-64 (http://www .x86-64.org/documentation). Основные отличия are:.

В этом разделе описывается перемещения реализованы в 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