2014-11-20 2 views
3

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

Я хотел бы понять некоторые ключевые моменты процесса:

  1. К концу дня мне нужно превратить мой C код на языке, который конкретно мой процессор должен понять. Итак, кто заботится о том, чтобы знать мои CPU-специфичные инструкции? Операционная система?

  2. Является ли gcc конвертированием любого C в сборка язык?

  3. Я знаю (на самом деле думаю), что для каждого типа процессора мне понадобится ассемблер , который будет интерпретировать (?) Код ассемблера и переводить на мои конкретные инструкции по процессору. Где этот ассемблер (кто его отправляет)? Он поставляется с ОС?

  4. Почему именно я не вижу 0s и 1s, если я открываю двоичный файл с помощью текстового редактора?

+0

** как ** - сборщик, ** ld ** - линкер, GCC поставляется с теми –

+0

Пожалуйста, смотрите следующее: http://stackoverflow.com/questions/6264249/how-does-the-compilation-linking- process-work – Sajidkhan

+0

gcc dont конвертировать C непосредственно в сборку. Это даст вам лучшую идею: http://en.wikipedia.org/wiki/GNU_Compiler_Collection#GENERIC_and_GIMPLE – sunny1304

ответ

2

К концу дня мне нужно преобразовать свой код на язык, который должен понимать мой процессор. Итак, кто заботится о том, чтобы узнать мои инструкции по использованию процессора? Операционная система?

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

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

Является ли gcc преобразованием любого языка C в ассемблер?

Да, C (или программа на любом другом поддерживаемом языке) преобразуется в сборку GCC. Существует много шагов, и по меньшей мере два дополнительных внутренних представления используются в процессе. Подробности объясняются в документе GCC internals. Наконец, компилятор «backend» генерирует сборку простых «шаблонов», сгенерированных предыдущими проходами компилятора. Вы можете попросить GCC вывести эту сборку, используя флаг -S. Если вы специально не просите об этом, следующий шаг (сборка) будет автоматически выполнен, и вы увидите только последний исполняемый файл.

Я знаю (на самом деле догадываюсь), что для каждого типа процессора мне понадобится ассемблер, который будет интерпретировать (?) Код сборки и переводить на мои конкретные инструкции по процессору. Где этот ассемблер (кто его отправляет)? Он поставляется с ОС?

Прежде всего обратите внимание, что языки ассемблера для каждого ЦП различаются, поскольку они должны представлять язык машинного процессора 1: 1. Затем Ассемблер перевел код сборки в машинный код. Кто его отправляет? Любой, кто его строит. С GNU toolchain это часть пакета binutils, и он обычно устанавливается по умолчанию для большинства дистрибутивов Linux. Это не только доступный ассемблер. Также обратите внимание, что хотя GNU «suite» (GCC/binutils/gdb) поддерживает многие архитектуры, вам необходимо использовать соответствующий порт для вашей архитектуры. Например, ассемблер по умолчанию вашего ПК не может компилировать/собирать в машинный код ARM.

Почему именно я не вижу 0s и 1s, если я открываю двоичный файл с помощью текстового редактора?

Поскольку текстовый редактор должен отображать текстовое представление 0s и 1s. Предполагая, что каждый символ в файле занимает 8 бит, они интерпретируют каждый восьмой бит в виде одиночного символа вместо того, чтобы показывать отдельные биты. Если вы знаете, что в стандартной 8-битной ASCII-букве «A» представлено значение 65, вы также можете преобразовать это обратно в двоичный: 01000001. Немного легче преобразовать шестнадцатеричное представление обратно в двоичное. Для этого вы можете использовать инструмент hexdump (или аналогичный).

+0

отличный ответ. Есть ли язык сборки для каждого процессора, вы имеете в виду архитектуру? Поскольку я могу загрузить один и тот же двоичный файл программы, и он будет работать в любом процессоре архитектуры, для которого был скомпилирован код, правильно? – Pabluez

+0

Другое дело: Другой помощник сказал, что преобразование сборки было вариантом, но GCC имеет инструменты для непосредственного преобразования источника C в файл объекта, который будет использоваться компоновщиком (ld). Что это значит? это правда? – Pabluez

+1

Более или менее ... В архитектуре x86 имеется много процессоров, но в каждом поколении ЦП добавляются новые инструкции. Поэтому не все процессоры в архитектуре совместимы. Насколько я знаю, GCC-серверы всегда создают код сборки внутри, а «драйвер компилятора» вызывает ассемблер для его сборки и создания объектного файла. Поскольку вы всегда будете иметь binutils, если вы хотите использовать GCC, это не проблема. Другие компиляторы могут генерировать машинный код напрямую. – dbrank0

8

Много бывает :)

Вот некоторые из ключевых шагов (кстати, они являются, как я думаю, компиляция, следующие шаги только мимолетное сходство с шагами, определенными в стандарте).

  1. препроцессора работает на исходный файл.

    Предварительно процессор делает все рода вещи для нас, в том числе:

    • Он выполняет три-глифов (специальные три последовательности символов, которые представляют некоторые из специальных символов, что ранние клавишные не было) замена.
    • Он выполняет макро замена (т.е. #define) путем простой замены текстового
    • Она захватывает любые файлов заголовки и копируют их все содержимое в котором #include линии была.

    Под Linux, программа, которая делает это m4, и с помощью gcc вы можете остановиться после этого шага, используя -E флаг.

  2. После выполнения предварительной обработки, у нас есть файл, который содержит всю информацию, необходимую для анализатор запустить и проверить наш синтаксис, и испускают сборку. В Linux программа, которая, скорее всего, делает это cc1, и используя gcc, вы можете остановить после этого шага, используя флаг -s.

  3. Узел преобразуется в код объекта мимо, скорее всего, программа gas (GNU Assembler), и с помощью gcc вы можете остановиться на этом этапе, используя -c флаг.

  4. Наконец один или несколько объектных файлов, вместе с библиотеками, преобразуются в исполняемый по линкера. Линкером под Linux обычно является ld, и с помощью gcc без каких-либо специальных флагов выполняется весь путь через это.

+0

Спасибо за ваш ответ. Я попытаюсь использовать флаг -C и увидеть код сборки, который генерирует gcc. Не могли бы вы обновить свой ответ, чтобы охватить 4 вопроса, которые я перечислил в моем первоначальном вопросе? Если вы знаете ответы, конечно. спасибо в advace – Pabluez

+1

Вы не увидите никакой сборки, вы передаете опцию '-c', которая будет компилироваться для объекта. Вам нужно передать параметр '-S', который будет компилироваться в сборку (формат по умолчанию AT & T). Чтобы вывести сборку формата 'intel', передайте опцию' -masm = intel'. Итак, если вы хотите сборку в формате intel: 'gcc -S -masm = intel -o outfile.asm infile.c' –

+1

Хорошее объяснение традиционного компилятора.Существует также промежуточный код между -E и -S (gimple ?, llvm ir и т. Д.), Который может быть полезен только при работе с JIT-компилятором. – technosaurus

6

Поскольку вы конкретно упоминается «К концу дня мне нужно превратить мой C код на языке, который конкретно мой процессор должен понять,» Я объясню немного о том, как компиляторы работы.

Типичные компиляторы делают несколько вещей.

Во-первых, они делают что-то, называемое лексированием. Этот шаг принимает индивидуальные символы и объединяет их в «токены», которые понимаются на следующем шаге. Этот шаг различает языковые слова (например, «для» и «если» в C), операторы (например, «+»), константы (например, целые и строковые литералы) и другие. То, что он отличает, зависит от самого языка.

Следующий шаг - это синтаксический анализатор, который берет поток токенов, создаваемых лексером, и (обычно) преобразует его во что-то, называемое «Абстрактное синтаксическое дерево», или AST. AST представляет собой вычисления, выполненные программой, с структурами данных, которые может перемещаться компилятором. Обычно AST не зависит от языка, а компиляторы, такие как GCC, могут анализировать разные языки в общем формате AST, который может понять следующий шаг (генератор кода).

Наконец, код-генератор проходит через AST и выводит код, который представляет семантику AST, то есть код, который фактически выполняет вычисления, которые представляет AST.

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

В случае С (и многих других) Ассемблер обычно не является последним шагом. Ассемблер создает объекты, называемые объектными файлами, которые содержат нерешенные ссылки на функции в других объектных файлах или библиотеках (например, printf в стандартной библиотеке C или функции из других файлов C в вашем проекте). Эти объектные файлы передаются тому, что называется «компоновщик», задачей которого является объединение всех объектных файлов в один двоичный файл и разрешение всех нерешенных ссылок в объектных файлах.

Наконец, после всех этих шагов у вас есть полный исполняемый двоичный файл.

Обратите внимание на то, что GCC и многие, многие другие компиляторы работают, но это не обязательно так. Любая программа, которую вы могли бы написать, которая точно принимает поток кода C и выводит поток другого кода (сборка, машинный код, даже javascript), который является эквивалентным, является компилятором.

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

+1

Хорошая дискуссия. Единственное, чего не хватает ** Что создает компоновщик **. Краткая дискуссия о том, какой формат 'ELF' (и конкурирующие форматы) будет полезен [** Исполняемый и связующий формат (ELF) **] (http: //www.skyfree.org/linux/references/ELF_Format.pdf). Это сделает его достаточно полным. –

+0

Большое спасибо. Я подумал об этом, но он, похоже, не подходил. Существует много исполняемых двоичных форматов, и как именно они отформатированы, на самом деле не кажется актуальным. –

+0

отличное объяснение. У меня все еще есть 4 вопроса в вопросе, на которые нужно ответить. Еще один вопрос вытекает из вашего ответа: возможно ли, чтобы опытный программист сборки написал «скрипт оболочки bash», который преобразует сам Bash в сборку, я мог бы сделать его исполняемым, связанным с ld? – Pabluez

1

К концу дня мне нужно превратить мой C код на языке, который конкретно мой процессор должен понять. Итак, кто заботится о том, чтобы узнать мои инструкции по использованию процессора? Операционная система?

Центральный процессор.

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

Это довольно хорошая концептуальная модель для простого программирования на С.


Является ли GCC преобразования любого C на ассемблере?

Если вы попросите его. Опция -S будет генерировать список сборок. Для ПК вы можете выбрать синтаксис AT & T, который является уродливым, как грех, переполненным знаками процента и обычным синтаксисом Intel. К сожалению, AT & T (выбирается через -masm=att IIRC) по умолчанию, но вы можете использовать -masm=intel, чтобы получить обычную сборку.

Если вы не просите его произвести сборку, то gcc предположительно генерирует объектный код непосредственно из его внутреннего абстрактного синтаксического дерева (AST).

Получение языка сборки в качестве промежуточной формы просто добавляет сложности и неэффективности, поэтому я очень сомневаюсь, что это так.


Я знаю, что на самом деле (думает), что для каждого типа процессора я нужен ассемблер, который будет интерпретировать (?) Код сборки и перевести на мой процессоре конкретных инструкции. Где этот ассемблер (кто его отправляет)? Он поставляется с ОС?

Вам не нужен такой ассемблер. Но gcc поставляется с ассемблером, as. Unix-подобные OS-es обычно имеют gcc и as в комплекте, в то время как Windows не содержит инструментов разработчика. Инструменты разработчика Microsoft, однако, бесплатны для загрузки, теперь (на прошлой неделе или около того), включая полную среду Visual Studio. Ассемблер Microsoft - ml.exe и известен как MASM, Macro Assembler (как будто других макросборщиков не было).


Почему именно я не могу увидеть и 0s 1s, если я открываю двоичный файл с помощью текстового редактора?

Это зависит от текстового редактора, хотя я не знаю ни одного, который может представлять 0 и 1; текстовые редакторы предназначены для интерпретации байтов как текста.

Вы можете просто написать такой текстовый редактор, если хотите.

Справедливое предупреждение: оно не имеет практического применения, о котором я могу думать.


Наконец в отношении вопроса в названии,

Каковы основные шаги позади компиляции?

На практике существуют два основных этапа: компиляция и связывая. Шаг компиляции далее подразделены инте предварительной обработки и основного языка компиляции, то есть,

        компиляции → связывая

& hellip; действительно

        (предварительная обработка → основной язык сборник) → связь

В ходе предварительной обработки исходных файлов кода объединяются с помощью #include директив. Это создает полный блок перевода исходного кода. Компиляция основного языка переводит это в файл объектного кода , который содержит машинный код с некоторыми нерешенными ссылками.

Затем, наконец, шаг связывания объединяет файлы объектных кодов (включая содержимое содержимого объектного кода в библиотеках), чтобы создать единый полный исполняемый файл.

Смежные вопросы