Как работает самозагрузка для gcc? - PullRequest
10 голосов
/ 21 июня 2011

Я искал проект pypy (Python в Python) и начал размышлять над вопросом, что запускает внешний слой python?Конечно, я предположил, что это не может быть, как гласит старая поговорка «черепахи все время вниз»!В конце концов, python не является верной сборкой x86!

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

Это все хорошо, но все еще остается вопрос, как компьютер получает этот файл сборки?!

Скажем, я покупаю новый процессор без него.Во время первой операции я хочу установить ОС, на которой работает C. Что запускает компилятор C?Есть ли в BIOS миниатюрный компилятор C?

Может кто-нибудь объяснить мне это?

Ответы [ 3 ]

12 голосов
/ 21 июня 2011

Скажем, я покупаю новый процессор без него.Во время первой операции я хочу установить ОС, на которой работает C. Что запускает компилятор C?Есть ли в BIOS миниатюрный компилятор C?

Я понимаю, о чем вы спрашиваете ... что произойдет, если у нас не будет компилятора C и мы начнем все с нуля?

Ответ: вам нужно начатьот сборки или оборудования.То есть вы можете создать компилятор как программно, так и аппаратно.Если бы во всем мире не было компиляторов, в эти дни вы, вероятно, могли бы делать это быстрее при сборке;тем не менее, в те времена, я полагаю, компиляторы на самом деле были выделенными аппаратными средствами.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Вопрос: "Что происходит сегодня?Ну, эти авторы компиляторов годами занимались написанием переносимого C, поэтому компилятор должен иметь возможность компилировать себя.Стоит обсудить на очень высоком уровне, что такое компиляция.По сути, вы берете набор утверждений и производите из них сборку.Вот и все.Ну, на самом деле все сложнее - вы можете делать все что угодно с помощью лексеров и парсеров, и я понимаю только небольшое его подмножество, но, по сути, вы хотите сопоставить C со сборкой.

ПодПри нормальной работе компилятор создает ассемблерный код, соответствующий вашей платформе, но это не обязательно.Он может создавать ассемблерный код для любой платформы, которая вам нравится, при условии, что она знает, как это сделать.Итак, первый шаг к тому, чтобы заставить C работать на вашей платформе, - создать цель в существующем компиляторе, начать добавлять инструкции и заставить работать базовый код.

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

Затем вы можете приступить к компиляции компилятора для этой платформы (как только вы получите работающий пользовательский мир и все остальное).вам нужно запустить процесс сборки).Если это удастся, у вас есть базовые утилиты, работающее ядро, пользовательское пространство и система компиляторов.Теперь вы уже в пути.

Обратите внимание, что в процессе переноса компилятора вам, вероятно, нужно было написать ассемблер и компоновщик для этой платформы.Чтобы описание было простым, я их опускал.

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

Python фактически не собирается для сборки.Для начала, работающая программа на Python отслеживает количество ссылок на объекты, что процессор не сделает для вас.Тем не менее, концепция кода на основе инструкций также лежит в основе Python.Поиграйте с этим:

>>> def hello(x, y, z, q):
...     print "Hello, world"
...     q()
...     return x+y+z
... 
>>> import dis
dis.dis(hello)


  2           0 LOAD_CONST               1 ('Hello, world')
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       

  3           5 LOAD_FAST                3 (q)
              8 CALL_FUNCTION            0
             11 POP_TOP             

  4          12 LOAD_FAST                0 (x)
             15 LOAD_FAST                1 (y)
             18 BINARY_ADD          
             19 LOAD_FAST                2 (z)
             22 BINARY_ADD          
             23 RETURN_VALUE

Там вы можете увидеть, как Python думает о коде, который вы ввели.Это байт-код python, т.е. язык ассемблера python.Он эффективно имеет свой собственный «набор инструкций», если вам нравится реализация языка.Это концепция виртуальной машины.

Java имеет точно такую ​​же идею.Я взял функцию класса и набрал javap -c class, чтобы получить это:

invalid.site.ningefingers.main:();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return
public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iconst_0
   3:   istore_1
   4:   iload_1
   5:   aload_0
   6:   arraylength
   7:   if_icmpge   57
   10:  getstatic   #2; 
   13:  new #3; 
   16:  dup
   17:  invokespecial   #4; 
   20:  ldc #5; 
   22:  invokevirtual   #6; 
   25:  iload_1
   26:  invokevirtual   #7; 
   //.......
}

Я так понимаю, вы поняли идею.Это языки ассемблера миров python и java, то есть то, что думают интерпретатор python и компилятор java соответственно.

Еще кое-что, о чем стоило бы прочитать, это JonesForth .Это как работающий переводчик, так и учебник, и я не могу рекомендовать его достаточно для размышлений о том, «как все выполняется» и как вы пишете простой и легкий язык.

6 голосов
/ 21 июня 2011

В интересах производительности, я уверен, что компиляторы C просто собраны из сборки.

Компиляторы C в настоящее время (почти?) Полностью написаны на C (или языках более высокого уровня - например, Clang - это C ++). Компиляторы практически ничего не получают от включения рукописного ассемблера. Вещи, которые занимают большую часть времени, так же медленны, как и они, потому что они решают очень сложные задачи, где «сложный» означает «большую вычислительную сложность» - переписывание в сборке приносит самое большее постоянное ускорение, но это на самом деле уже не имеет значения уровень.

Кроме того, большинству компиляторов нужна высокая переносимость, поэтому об особенностях архитектуры в переднем и среднем концах не может быть и речи (а в бэкэндах они также нежелательны, поскольку они могут нарушить кросс-компиляцию).

Скажем, я покупаю новый процессор без него. Во время первой операции я хочу установить ОС, на которой работает C. Что запускает компилятор C? Есть ли в BIOS миниатюрный компилятор C?

При установке ОС (обычно) компилятор Си не запускается. Установочный компакт-диск содержит готовые двоичные файлы для этой архитектуры. Если есть включенный компилятор C (как это имеет место со многими дистрибутивами Linux), это также уже скомпилированный вариант. А в тех дистрибутивах, которые заставляют вас создавать собственное ядро ​​и т. Д., Также есть хотя бы один исполняемый файл - компилятор. Это, конечно, если вам не нужно скомпилировать собственное ядро ​​на существующей установке чего-либо с помощью компилятора C.

Если под «новым ЦП» вы имеете в виду новую архитектуру, которая не совместима с предыдущими версиями для чего-либо, что еще поддерживается, компиляторы с автономным размещением могут следовать обычной процедуре портирования: сначала напишите бэкэнд для этой новой цели, затем скомпилируйте себя для этого, и вдруг у вас есть зрелый компилятор с закаленным в битве (скомпилированным целым компилятором) внутренним бэкэндом на новой платформе.

3 голосов
/ 21 июня 2011

Если вы покупаете новую машину с предустановленной ОС, ей даже не нужно никуда включать компилятор, потому что весь исполняемый код был скомпилирован на какой-то другой машине, кто бы ни предоставлял ОС - ваша машина не не нужно ничего самому компилировать.

Как вы доберетесь до этой точки, если у вас совершенно новая архитектура процессора? В этом случае вы, вероятно, начнете с написания нового бэк-энда генерации кода для вашей новой архитектуры ЦП («цель») для существующего компилятора C, работающего на другой платформе («хост») - кросс-компилятор .

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

Это тот же принцип с новым языком: вы должны написать код на существующем языке, для которого у вас есть набор инструментов, который скомпилирует ваш новый язык в нечто, с чем вы можете работать (назовем это «компилятором начальной загрузки»). «). Как только вы это заработаете достаточно хорошо, вы можете написать компилятор на своем новом языке («настоящий компилятор»), а затем скомпилировать настоящий компилятор с помощью компилятора начальной загрузки. На этом этапе вы пишете компилятор для вашего нового языка на новом языке, и ваш язык называется "самодостаточным".

...