Генерация сборки для процессора x86 - PullRequest
7 голосов
/ 02 марта 2010

В настоящее время я работаю над внедрением современного компилятора Эндрю Аппеля в Java, и я почти дошел до того момента, когда строю промежуточное представление низкого уровня.

Первоначально я решил нацелиться на JVM и игнорировать все низкоуровневые машинные вещи, но в интересах изучения вещей, о которых я мало знаю, у меня изменилось мнение. Это меняет мой IR, потому что нацеливание на JVM позволяет мне (более или менее) махать руками при вызове метода или создании объекта.

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

Вещи, которые я сейчас знаю, и которые мне нужно знать:

  • Какой набор команд использовать. У меня есть два ноутбука, на которых я мог бы развиваться; оба имеют процессоры Core 2 Duo. Насколько я понимаю, процессоры x86 в основном используют один и тот же набор команд, но не все они одинаковы.

  • Влияет ли операционная система на этап генерации кода или полностью зависит от процессора. Например, я знаю, что в генерации кода, работающего на 32-битной и 64-битной платформах, есть кое-что другое.

  • Как организованы стековые фреймы и тому подобное. Когда использовать регистры, а не помещать параметры в стек, caller-save или callee-save, и все такое. Я бы подумал, что это будет описано вместе с набором инструкций, но пока я нигде не видел этой конкретной информации. Может я тут что-то недопонимаю?

Ссылки на ресурсы вместо ответов приветствуются.

Ответы [ 3 ]

5 голосов
/ 02 марта 2010

Большая часть набора команд x86 является общей для всех процессоров - вполне разумно предположить, что у обоих процессоров одинаковый набор команд, за исключением, возможно, SIMD-инструкций, которые, вероятно, не будут очень полезны при реализации простого компилятор (эти инструкции обычно используются для ускорения работы мультимедийных приложений и т. п.). Набор инструкций приведен в Руководства Intel - в частности, 2A и 2B содержат полный список инструкций и их поведение, хотя на другие тома стоит обратить внимание.

При создании кода пользовательского пространства выбор операционной системы имеет значение, когда дело доходит до системных вызовов. Например, если вы хотите, чтобы программа выводила что-то на терминал в 64-битной Linux, вам нужно сделать системный вызов:

  • загрузка значения 1 в регистр rax, чтобы указать, что это системный вызов write.
  • загрузка значения 1 в регистр rdi для указания того, что следует использовать стандартный вывод (1 - дескриптор файла для стандартного вывода)
  • загрузка начального адреса того, что вы хотите напечатать в регистр rsi
  • загрузка длины того, что вы хотите напечатать в регистр rdx
  • выполнение инструкции syscall после настройки регистров (и памяти).

Возвращаемое значение из write сохраняется в rax.

Другая операционная система может иметь другой номер системного вызова для write, может иметь другой способ передачи аргументов (системные вызовы Linux x86-64 всегда используют rdi, rsi, rdx, r10, r8 и r9 в таком порядке для параметров с номером системного вызова в rax), и могут иметь разные системные вызовы в целом.

Соглашение для обычных вызовов функций в Linux аналогично - порядок регистров rdi, rsi, rdx, rcx, r8 и r9 (так что все то же самое, за исключением использования rcx вместо r10), с дополнительными аргументами в стеке и возвращаемым значением в rax. Согласно этой странице регистры rbp, rbx и r12 до r15 должны сохраняться при вызовах функций. Вы, конечно, можете создавать свои собственные соглашения (если только не делаете системный вызов), но это усложняет вызов, вызываемый из кода, сгенерированного или написанного другими.

3 голосов
/ 02 марта 2010

Как складываются кадры и тому подобное организовано. Когда использовать регистры и положить параметры в стек, вызывающий-сохранить против вызываемого-сохранить, все тот. Я бы подумал, что это будет быть описаны вместе с набор инструкций, но пока у меня нет видел эту конкретную информацию в любом месте. Может быть, я что-то неправильно понимаю здесь

В общем, нет правильных ответов на эти вопросы. Вы можете использовать любые соглашения о вызовах, которые вы хотите ... если вы не хотите взаимодействовать с кодом других людей. Для обеспечения совместимости компиляторы стандартизируют двоичные интерфейсы приложений. Насколько я понимаю, Itanium C ++ ABI стал популярным стандартом в последние годы. Попробуйте начать там.

1 голос
/ 02 марта 2010

Я не могу ответить на все ваши вопросы; но

  • Базовый набор команд x86 совместим с семейством x86 процессоры. Вы не планируете реализовать любые конкретные расширения, ты?
  • Я не думаю, что ваша ОС или архитектура имеет большое значение для кода поколение
  • Ответ по умолчанию для что-нибудь связанное с компилятором Книга Дракона . Вы смотрели на это еще?
...