Какова роль файлов .s в проекте C? - PullRequest
22 голосов
/ 21 марта 2012

Я работаю с чипом ARM Cortex M3 (STM32F2), и ST предоставляет «стандартную периферийную библиотеку». Он имеет несколько полезных файлов .c и .h. Также есть файлы .s.

Какова цель этих файлов .s в контексте проекта C? Как мне получить мой компилятор / компоновщик /? принять их во внимание?

Ответы [ 4 ]

34 голосов
/ 22 марта 2012

Расширение .s - это соглашение, используемое GNU и многими другими цепями инструментов для файлов ассемблера.

В последний раз я посмотрел, что стандартная периферийная библиотека STM32 не содержит файлов ассемблера, однако библиотека CMSIS содержит код запуска для различных компонентов STM32, например, startup_stm32f2xx.s - это код запуска для всех устройств серии STM32F2xx. Существуют разные реализации для разных цепочек инструментов; вам нужно создать и связать файл, связанный с вашей конкретной деталью и цепочкой инструментов. Если вы используете пример проекта, который создает и запускает, или IDE, которая создает проекты для конкретных деталей, это, вероятно, уже будет выполнено - если у вас есть код, который запускает, он, безусловно, имеет.

Способ построения и связывания кода будет зависеть от того, какую цепочку инструментов вы используете. Большинство инструментов на основе IDE автоматически распознают расширение и вызывают ассемблер для создания объектного файла, который будет связан как любой другой. Точное содержимое немного отличается в разных версиях цепочки инструментов, но в первую очередь создает среду выполнения C (стек и куча), инициализирует процессор, определяет исходную таблицу векторов прерываний / исключений, инициализирует статические данные и переходит к main ().

Ядро файла для версии Keil / ARM RealView, например, выглядит следующим образом:

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

Reset_Handler - адрес регистра счетчика программ (ПК), который будет установлен после сброса процессора.

SystemInit - это внешняя функция кода C, которая выполняет основную часть инициализации - для этого может потребоваться настройка вашего оборудования. Cortex-M необычен тем, что может запускать код C сразу после сброса, поскольку таблица векторов включает в себя как адрес сброса, так и начальный адрес указателя стека, который автоматически загружается в регистр SP при сбросе. В результате вам не нужно много знаний ассемблера, чтобы запустить его.

__main() - это точка входа, поставляемая компилятором для вашего кода C. Это не функция main (), которую вы пишете, но она выполняет инициализацию для стандартной библиотеки, статических данных, кучи перед вызовом вашей функции main ().

Версия GCC несколько сложнее, поскольку выполняет большую часть работы, выполняемой __main() в версии Keil / ARM RealView, но по сути выполняет ту же функцию.

Обратите внимание, что в CMSIS SystemInit() определяется в system_stm32f2xx.c и может нуждаться в настройке для вашей платы (правильная частота кристалла, настройка PLL, внешняя конфигурация SRAM и т. Д.). Поскольку это код на Си и он хорошо прокомментирован, вам, вероятно, будет удобнее с ним работать.

8 голосов
/ 21 марта 2012

Они обычно содержат ассемблерный код. Ассемблер превращает их в объектные файлы, которые впоследствии связываются компоновщиком с основным материалом. Но я думаю, что это зависит от компилятора, набора инструментов и т. Д.

2 голосов
/ 13 марта 2019

Файлы .s обычно содержат таблицы Vector. Он определяет, что должна делать система при возникновении прерывания. Эта таблица (код) помещается в определенный вами адрес памяти в файле компоновщика. Например, каждый раз, когда происходит сброс, с чего, а точнее, откуда должен начинаться ваш процессор, какой код он должен запускать. аналогично, существуют другие обработчики (векторы прерываний). В STM32 обычно контроллер зацикливается на определенных обработчиках. Как показано в приведенном ниже примере: См. Эту ссылку для подробного объяснения

    .section INTERRUPT_VECTOR, "x"
    .global _Reset
    _Reset:
      B Reset_Handler /* Reset */
      B . /* Undefined */
      B . /* SWI */
      B . /* Prefetch Abort */
      B . /* Data Abort */
      B . /* reserved */
      B . /* IRQ */
      B . /* FIQ */

    Reset_Handler:
      LDR sp, =stack_top
      BL c_entry
      B .

Этот код сборки позже преобразуется в объектные файлы и связывается с вашими файлами .c и .ld для создания файлов .elf или .bin.

1 голос
/ 22 марта 2012

Возможно, у вас есть среда разработки на основе Keil для вашего набора ST. В зависимости от версии вашего компилятора, файл проекта должен иметь разные разделы для C, C ++ и ассемблерного кода. В вашей среде IDE откройте проект и найдите «Свойства проекта» или что-то в этом роде.

Вы можете импортировать и экспортировать символы в и из кода ассемблера, чтобы он и код C / C ++ связывались. С Keil все это достаточно хорошо интегрируется.

Директива EXPORT указывает ассемблеру сделать указанный символ общедоступным, чтобы ваш код C / C ++ мог на него ссылаться.

Директива IMPORT сообщает ассемблеру, что указанный символ определен в другом месте и будет разрешен во время соединения.

...