- Автор темы
- Добавить закладку
- #21
Часть 21 - Как скомпилировать программу
Давайте еще раз посмотрим на программу C с прошлого модуля и подробнее рассмотрим, как мы превращаем исходный код в исполняемый файл.
Чтобы скомпилировать эту программу на C, мы просто набираем:
Этот единственный шаг создаст exit.o, который является двоичным объектным файлом, и exit, который является двоичным исполняемым файлом.
Если мы хотим преобразовать этот исходный код C в ассемблер, нам нужно использовать компилятор GNU следующим образом. Начнем с выполнения следующей команды в терминале:
Начнем с переключателя -S. Ключ -S создает сопоставимый исходный код синтаксической сборки AT&T. -m32 создаст 32-разрядный исполняемый файл, а -O0 сообщит компилятору, какой объем оптимизации следует использовать при компиляции двоичного файла. Это заглавная буква O и цифра 0. Цифра 0 в этом случае означает отсутствие оптимизации, что означает, что это наиболее удобочитаемый набор инструкций. Если бы вы заменили 1, 2 или 3, объем оптимизации увеличивается по мере увеличения значений.
Этот шаг выше создает exit.s, который является эквивалентным исходным кодом языка ассемблера, как мы упоминали выше.
Затем нам нужно скомпилировать исходный код в двоичный объектный файл, который будет генерировать файл exit.o.
Наконец, нам нужно использовать компоновщик для создания фактического двоичного исполняемого кода из двоичного объектного файла, который создаст исполняемый файл с именем exit.
Ранее, когда мы исследовали вывод из исполняемого файла в программе под названием objdump и исследовали основную функцию, мы увидели следующее, за исключением того, что на этот раз мы будем использовать синтаксис языка ассемблера AT&T:
Эта команда выше создаст следующий вывод:
Давайте исследуем код в отладчике. Давайте запустим GDB, который является отладчиком GNU, и сначала перечислим исходный код, набрав l, затем установим точку останова на main и запустим программу. Наконец, мы дизассемблируем и рассмотрим вывод ниже:
В каждом из трех вышеуказанных выводов вы, по сути, увидите один и тот же набор инструкций, которые мы более подробно рассмотрим в будущих уроках.
До сих пор на протяжении всей этой серии руководств мы рассматривали язык ассемблера синтаксиса Intel. Мы собираемся сосредоточить наше внимание на синтаксисе AT&T, как я сказал выше, поскольку это естественный синтаксис, используемый в Linux с GNU Assembler и GNU Debugger.
Самая большая разница, которую вы увидите, заключается в том, что в синтаксисе AT&T источник и назначение меняются местами.
Синтаксис AT&T: movl% esp,% ebp [Это означает переместить esp в ebp.]
Синтаксис Intel: mov esp, ebp [Это означает переместить ebp в esp.]
Вы также увидите некоторые дополнительные отклонения,, которые мы рассмотрим в следующем руководстве.
Если бы мы хотели создать программу на чистом ассемблере, которая выполняет то же самое, что и выше, мы бы набрали:
Чтобы скомпилировать это, мы будем использовать ассемблер GAS и линкер:
Чтобы запустить любой исполняемый файл в Linux, вы вводите ./ и имя исполняемого двоичного файла. В этом случае мы набираем ./exit и нажимаем Энтер. Когда мы это делаем, ничего не происходит. Это хорошо, так как все, что мы сделали, это создали программу, которая выходила бы обратно в ОС.
Я с нетерпением жду встречи с вами в следующем модуле, когда мы углубимся еще больше в код ассемблера!
Давайте еще раз посмотрим на программу C с прошлого модуля и подробнее рассмотрим, как мы превращаем исходный код в исполняемый файл.
Чтобы скомпилировать эту программу на C, мы просто набираем:
Этот единственный шаг создаст exit.o, который является двоичным объектным файлом, и exit, который является двоичным исполняемым файлом.
Если мы хотим преобразовать этот исходный код C в ассемблер, нам нужно использовать компилятор GNU следующим образом. Начнем с выполнения следующей команды в терминале:
Начнем с переключателя -S. Ключ -S создает сопоставимый исходный код синтаксической сборки AT&T. -m32 создаст 32-разрядный исполняемый файл, а -O0 сообщит компилятору, какой объем оптимизации следует использовать при компиляции двоичного файла. Это заглавная буква O и цифра 0. Цифра 0 в этом случае означает отсутствие оптимизации, что означает, что это наиболее удобочитаемый набор инструкций. Если бы вы заменили 1, 2 или 3, объем оптимизации увеличивается по мере увеличения значений.
Этот шаг выше создает exit.s, который является эквивалентным исходным кодом языка ассемблера, как мы упоминали выше.
Затем нам нужно скомпилировать исходный код в двоичный объектный файл, который будет генерировать файл exit.o.
Наконец, нам нужно использовать компоновщик для создания фактического двоичного исполняемого кода из двоичного объектного файла, который создаст исполняемый файл с именем exit.
Ранее, когда мы исследовали вывод из исполняемого файла в программе под названием objdump и исследовали основную функцию, мы увидели следующее, за исключением того, что на этот раз мы будем использовать синтаксис языка ассемблера AT&T:
Эта команда выше создаст следующий вывод:
Давайте исследуем код в отладчике. Давайте запустим GDB, который является отладчиком GNU, и сначала перечислим исходный код, набрав l, затем установим точку останова на main и запустим программу. Наконец, мы дизассемблируем и рассмотрим вывод ниже:
В каждом из трех вышеуказанных выводов вы, по сути, увидите один и тот же набор инструкций, которые мы более подробно рассмотрим в будущих уроках.
До сих пор на протяжении всей этой серии руководств мы рассматривали язык ассемблера синтаксиса Intel. Мы собираемся сосредоточить наше внимание на синтаксисе AT&T, как я сказал выше, поскольку это естественный синтаксис, используемый в Linux с GNU Assembler и GNU Debugger.
Самая большая разница, которую вы увидите, заключается в том, что в синтаксисе AT&T источник и назначение меняются местами.
Синтаксис AT&T: movl% esp,% ebp [Это означает переместить esp в ebp.]
Синтаксис Intel: mov esp, ebp [Это означает переместить ebp в esp.]
Вы также увидите некоторые дополнительные отклонения,, которые мы рассмотрим в следующем руководстве.
Если бы мы хотели создать программу на чистом ассемблере, которая выполняет то же самое, что и выше, мы бы набрали:
Чтобы скомпилировать это, мы будем использовать ассемблер GAS и линкер:
Чтобы запустить любой исполняемый файл в Linux, вы вводите ./ и имя исполняемого двоичного файла. В этом случае мы набираем ./exit и нажимаем Энтер. Когда мы это делаем, ничего не происходит. Это хорошо, так как все, что мы сделали, это создали программу, которая выходила бы обратно в ОС.
Я с нетерпением жду встречи с вами в следующем модуле, когда мы углубимся еще больше в код ассемблера!