Модель Кода x86-64
Эта статья описывает различия в OS X x86-64 модель кода пространства пользователя от модели кода, описанной в Двоичном интерфейсе приложений System V Дополнение Процессора Архитектуры AMD64, в http://www .x86-64.org/documentation.
x86-64 среда в OS X имеет только одну модель кода для кода пространства пользователя. Это является самым подобным маленькой модели PIC, определенной x86-64 System V ABI. Под Мужественным все статическое инициализированное хранение (и код и данные) должно соответствовать в Мужественном файле на 4 ГБ. Неинициализированный (заполняют нулями) данные, может быть любой размер, несмотря на то, что существует практический предел, наложенный OS X.
Ко всем локальным и маленьким данным получают доступ непосредственно с помощью обращения, это относительно указателя команд (относительная адресация RIP). Ко всем большим или возможно нелокальные данные получают доступ косвенно посредством записи глобальной таблицы смещения (GOT). К записи GOT получают доступ непосредственно с помощью относительной адресации RIP.
Перечисление 1 показывает, что выборка C код и соответствующий собирает код.
Код перечисления 1 C и соответствующий ассемблерный код
extern int src[]; |
extern int dst[]; |
extern int* ptr; |
static int lsrc[500]; |
static int ldst[500]; |
static int bsrc[500000]; |
static int bdst[500000]; |
static int* lptr; |
dst[0] = src[0]; movq _src@GOTPCREL(%rip), %rax |
movl (%rax), %edx |
movq _dst@GOTPCREL(%rip), %rax |
movl %edx, (%rax) |
ptr = dst; movq _dst@GOTPCREL(%rip), %rdx |
movq _ptr@GOTPCREL(%rip), %rax |
movq %rdx, (%rax) |
ret |
*ptr = src[0]; movq _ptr@GOTPCREL(%rip), %rax |
movq (%rax), %rdx |
movq _src@GOTPCREL(%rip), %rax |
movl (%rax), %eax |
movl %eax, (%rdx) |
ret |
ldst[0] = lsrc[0]; movl _lsrc(%rip), %eax |
movl %eax, _ldst(%rip) |
lptr = ldst; lea _ldst(%rip), %rax |
movq %rax, _lptr(%rip) |
*lptr = lsrc[0]; movl _lsrc(%rip), %edx |
movq _lptr(%rip), %rax |
movl %edx, (%rax) |
bdst[0] = bsrc[0]; movq _bsrc@GOTPCREL(%rip), %rax |
movl (%rax), %edx |
movq _bdst@GOTPCREL(%rip), %rax |
movl %edx, (%rax) |
lptr = bdst; movq _bdst@GOTPCREL(%rip), %rax |
movq %rax, _lptr(%rip) |
*lptr = bsrc[0]; movq _bsrc@GOTPCREL(%rip), %rdx |
movq _lptr(%rip), %rax |
movl (%rdx), %edx |
OS X x86-64 доступы модели генерации кода большие локальные данные через GOT, отличающийся от пути маленькая модель PIC, работает в System V x86-64 среда. Косвенность через GOT устраняет потребность в средней модели кода. Это поведение происходит от факта, что, когда компоновщик размечает данные, оно помещает данные, к которым получают доступ непосредственно (маленькие локальные данные и GOT сами) в 2 ГБ кода. Другие данные могут быть помещены дальше, потому что к этим данным получают доступ только через GOT. Это поведение позволяет большой (больше, чем 4 ГБ) и маленькие исполнимые программы быть созданным с помощью той же модели кода.
Модель кода для вызовов функции очень проста, как показано в Перечислении 2.
Перечисление 2 модель кода для вызовов функции
extern int foo(); |
static int bar(); |
foo(); call _foo |
bar(); call _bar |
Все прямые вызовы функции сделаны с помощью CALL rel32
инструкция.
Компоновщик ответственен за создание записей GOT (также известный как неленивые указатели), а также интерфейсные функции и ленивые указатели (также известный как записи таблицы загрузки программы или записи PLT) для вызовов к другому модулю связи. Так как компоновщик должен создать эти записи, это может также принять решение не создать их, когда это видит возможность. У компоновщика есть сложный ряд правил, которые диктуют, к каким символам нужно получить доступ косвенно (в зависимости от плоского по сравнению с двухуровневым пространством имен, слабым по сравнению с неслабыми определениями, видимостью символа, расстоянием от кода, и т.д.). Но в конечном счете существует много символов, к которым можно получить доступ непосредственно (не через GOT или записи PLT). Для этих символов компоновщик делает следующую оптимизацию:
A
CALL
илиJMP
инструкция выполняет прямое, относительное PC ответвление к цели.Инструкция загрузки, выполняемая на записи GOT (например,
movq _foo@GOTPCREL(%rip), %rxx
) преобразовывается в aLEA
вычисление (например,leaq _foo(%rip), %rxx
). Эта трансформация удаляет одну запись GOT и сохраняет одну загрузку в память.
В обоих случаях специальные перемещения используются, которые позволяют компоновщику выполнять эту оптимизацию.