Перейти к содержанию
    

Вставка файла ассемблера .s в файл main.c

Здравствуйте!

 

В своём проекте создал 5 файлов - main (.c, .h), PortInit (.c, .h), RegSum (.s). Собственно, весь вопросы в том, что:

1. А так вообще кто-то делает, или намного легче через __ASM написать всё в .c-файле?

2. Как правильно организовать включение текста файла RegSum.s (на языке ассемблера) в main.c, с учётом того, что это именно отдельный файл в дереве проекта, а не вставка в main.c

3. Судя по некоторым темам на форуме, есть трудности при организации функции, телом которой является .s-файл (напр, команды среды END, ENDP), разве среда не должна их выкинуть при компиляции, оставив только "железные" команды?

4. Также, немного не в теме вопроса, но:

        "Если хотя бы один из ISR, на которые ссылается таблица прерываний, определён в другом файле (а не в этом .asm), то указатель на него будет не константой. Он будет браться на этапе компоновки из таблиц экспорта .obj-файлов. А значит на этапе компиляции он неизвестен.

        "А зачем там пролог? __attribute__((naked)) скорее" З.Ы. имеется ввиду пролог функции.

Собственно, это цитаты из различных тем, которые кажутся мне интересными. Когда я читаю про таблицы экспорта, вектора прерываний, прологи функций - я понимаю, что моих знаний о том, как функционирует среда программирования и как работают устройства - маловато. Подскажите, если это возможно, хорошую литературу (Ру, Анг), которая сможет (относительно) без лишних слов дать мне представление о том, как это всё взаимосвязано. Пособия и книги, которые я видел до сих пор не дали мне представления о таких вещах. Признаюсь, стандарты языков и документацию на Keil до конца не читал.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, AzardCry сказал:

1. А так вообще кто-то делает, или намного легче через __ASM написать всё в .c-файле?

А какая разница, кто как делает?:smile: У меня есть .c-файлы, где функции написаны на asm (вставками).
А вот startup-файл - весь на ассемблере, скорее лишь потому, что я беру его стандартный из коробки Keil, и допиливаю при необходимости.

Цитата

2. Как правильно организовать включение текста файла RegSum.s (на языке ассемблера) в main.c, с учётом того, что это именно отдельный файл в дереве проекта, а не вставка в main.c

Не надо его "вставлять". Надо из этого RegSum.s экспортировать имена используемых процедур (функций) и вызывать их где Вам нужно, в том же main.c.

Цитата

3. Судя по некоторым темам на форуме, есть трудности при организации функции, телом которой является .s-файл (напр, команды среды END, ENDP), разве среда не должна их выкинуть при компиляции, оставив только "железные" команды?

END, ENDP - это не ассемблерные команды. Это директивы. Никак не трансформируются в машинные команды.

Цитата

Если хотя бы один из ISR, на которые ссылается таблица прерываний, определён в другом файле (а не в этом .asm), то указатель на него будет не константой. Он будет браться на этапе компоновки из таблиц экспорта .obj-файлов. А значит на этапе компиляции он неизвестен.

        "А зачем там пролог? __attribute__((naked)) скорее" З.Ы. имеется ввиду пролог функции.

Вообще не понял. Еще раз и помедленнее.

Цитата

Признаюсь, стандарты языков и документацию на Keil до конца не читал...

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, AzardCry сказал:

1. А так вообще кто-то делает, или намного легче через __ASM написать всё в .c-файле?

Раз возможность есть, значит кому-то это нужно?

Цитата

2. Как правильно организовать включение текста файла RegSum.s (на языке ассемблера) в main.c

Никак. Потому как ассемблер и си - это разные языки. И файлы *.s и *.c имеют разный формат.

.c-файлы компилирует си-компилятор, .s-файлы (или .asm) - транслятор ассемблера. Оба на выход выдают .obj-файлы. Которые поглощает компоновщик (являются для него входными). На выходе компоновщика - загрузочный образ прошивки (в формате: .hex, .bin или каком-то другом).

Цитата

3. Судя по некоторым темам на форуме, есть трудности при организации функции, телом которой является .s-файл

Галиматью какую-то пишете. .s-файл не может "являться телом функции".

Цитата

        "Если хотя бы один из ISR, на которые ссылается таблица прерываний, определён в другом файле (а не в этом .asm), то указатель на него будет не константой. Он будет браться на этапе компоновки из таблиц экспорта .obj-файлов. А значит на этапе компиляции он неизвестен.

И что?

Цитата

таблицы экспорта

Вам, как начинающему, это не нужно.

Изучайте примеры проектов. В многих средах программирования есть множество примеров.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 часов назад, AzardCry сказал:

В своём проекте создал 5 файлов - main (.c, .h), PortInit (.c, .h), RegSum (.s). Собственно, весь вопросы в том, что:

Вы цель свою конечную опишите. Зачем вам нужен именно ассемблерный файл в проекте? Просто, чтобы был? Вы эту функцию на Си написать не можете? Вам ассемблерного стартап-файла мало?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

21.02.2022 в 19:01, Arlleex сказал:

А какая разница, кто как делает?:smile: У меня есть .c-файлы, где функции написаны на asm (вставками).
А вот startup-файл - весь на ассемблере, скорее лишь потому, что я беру его стандартный из коробки Keil, и допиливаю при необходимости.

Не надо его "вставлять". Надо из этого RegSum.s экспортировать имена используемых процедур (функций) и вызывать их где Вам нужно, в том же main.c.

END, ENDP - это не ассемблерные команды. Это директивы. Никак не трансформируются в машинные команды.

Вообще не понял. Еще раз и помедленнее.

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

 

21.02.2022 в 19:18, jcxz сказал:

Раз возможность есть, значит кому-то это нужно?

Никак. Потому как ассемблер и си - это разные языки. И файлы *.s и *.c имеют разный формат.

.c-файлы компилирует си-компилятор, .s-файлы (или .asm) - транслятор ассемблера. Оба на выход выдают .obj-файлы. Которые поглощает компоновщик (являются для него входными). На выходе компоновщика - загрузочный образ прошивки (в формате: .hex, .bin или каком-то другом).

Галиматью какую-то пишете. .s-файл не может "являться телом функции".

И что?

Вам, как начинающему, это не нужно.

Изучайте примеры проектов. В многих средах программирования есть множество примеров.

 

21.02.2022 в 19:51, Darth Vader сказал:

Вы цель свою конечную опишите. Зачем вам нужен именно ассемблерный файл в проекте? Просто, чтобы был? Вы эту функцию на Си написать не можете? Вам ассемблерного стартап-файла мало?

 

Доброго времени, Arlleex, jcxz, Darth Vader!

2. Arlleex, а можно короткий пример того, как процедура из файла RegSum.s будет перенесена в main.c?

    jcxz, Arlleex, судя по всему, не согласен с вами, либо имеет ввиду что-то другое (мне сложно сказать).

    Darth Vader, я исключительно в образовательных целях хочу создать три файла: два .c, один .s; один .c (main) основной; из второго .c (PortInit) я делаю своего рода библиотеку для выноса части кода; третий .s (RegSum) схож по назначению с PortInit.c, но на языке ассемблера. Функцию на Си написать могу, но тогда образовательная ценность моей задумки упадёт. Задача в том чтобы из PortInit и RegSum вставлять функции в main.c, но как сделать это для последнего я не знаю, потому что не работал с ассемблером до сих пор.

 

3. jcxz, может и галиматью, заранее прошу прощения за ошибки в терминологии, сам пока не до конца разобрался :)

Изменено пользователем AzardCry
Правки

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

26 минут назад, AzardCry сказал:

jcxz, Arlleex, судя по всему, не согласен с вами, либо имеет ввиду что-то другое (мне сложно сказать)...

Почему? Не вижу противоречий:smile: А лучше конкретезируйте, в чем конкретно я, возможно, не согласен с jcxz.

Цитата

Arlleex, а можно короткий пример того, как процедура из файла RegSum.s будет перенесена в main.c?

.s

Скрытый текст

  PRESERVE8
  THUMB
  AREA |.text|, CODE, READONLY

SwitchContext
  PROC
    EXPORT SwitchContext
  
    push {lr}
    push {r1-r12}
    mrs   r1, XPSR
    push {r1}
  
    ...
  
    pop  {r1}
    msr  XPSR, r1
    pop  {r1-r12}
    pop  {pc}
  ENDP
  ALIGN
  END

.h

Скрытый текст

#ifndef EXAMPLE_H
#define EXAMPLE_H

void SwitchContext();

#endif

.c (например, где-то в main.c)

Скрытый текст

#include "example.h"

void func(void) {
  int a;
  int b;
  ...
  SwitchContext();
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я вставляю и вызываю asm в asm ( KEIL, stm32).

Изменено пользователем majorka65

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24.02.2022 в 14:14, Arlleex сказал:

Почему? Не вижу противоречий:smile: А лучше конкретезируйте, в чем конкретно я, возможно, не согласен с jcxz.

.s

  Показать содержимое


  PRESERVE8
  THUMB
  AREA |.text|, CODE, READONLY

SwitchContext
  PROC
    EXPORT SwitchContext
  
    push {lr}
    push {r1-r12}
    mrs   r1, XPSR
    push {r1}
  
    ...
  
    pop  {r1}
    msr  XPSR, r1
    pop  {r1-r12}
    pop  {pc}
  ENDP
  ALIGN
  END

.h

  Показать содержимое


#ifndef EXAMPLE_H
#define EXAMPLE_H

void SwitchContext();

#endif

.c (например, где-то в main.c)

  Показать содержимое


#include "example.h"

void func(void) {
  int a;
  int b;
  ...
  SwitchContext();
}

Доброго времени, Arllex!

 

Благодарю за пример! Не подскажите, как сделать ту же функцию, но только принимающую значение из .c-файла и возвращающую в него же результат:

 

Насколько я успел понять до этого времени, аргументы функции переносятся в регистры с 0-го по N-ый соответственно по порядку из записи в "()", а вернуть их можно с помощью команды RET. На сайте ПО (сайт Keil) написано, что эта (RET) команда возвращает данные из стека (также в примерах фигурирует BX LR). Собственно, как именно передать условный аргумент "FirstNum" и вернуть из RegSum.s в main.c значение, присвоив его какой-либо переменной, чтобы потом использовать его далее, остаётся не ясным. Прошу пояснить или указать мне на материалы, которые проясняют данный вопрос.

 

Также интересно, почему для того, чтобы функция "видела себя" в различных файлах, в .s необходима "EXPORT", а в Си (.h-файле) никакой директивы для этого не предусмотрено.

 

"Никак. Потому как ассемблер и си - это разные языки. И файлы *.s и *.c имеют разный формат." - Касательно несогласия вас и jcxz - уже вижу, что разногласий нет. Скорее я неверно сформулировал вопрос, изначально, конечно, имелись ввиду вызовы функций из файлов различного формата, пример чего вы и предоставили.

Изменено пользователем AzardCry

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 minutes ago, AzardCry said:

Насколько я успел понять до этого времени, аргументы функции переносятся в регистры с 0-го по N-ый соответственно по порядку из записи в "()", а вернуть их можно с помощью команды RET.

Гуглите документ под названием AAPCS. Значение возвращается в нулевом регистре, никаких команд не нужно.

 

25 minutes ago, AzardCry said:

Также интересно, почему для того, чтобы функция "видела себя" в различных файлах, в .s необходима "EXPORT", а в Си (.h-файле) никакой директивы для этого не предусмотрено.

В Си статические функции тоже "не видны", считайте, что в ассемблере они статические по умолчанию.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, AzardCry сказал:

Благодарю за пример! Не подскажите, как сделать ту же функцию, но только принимающую значение из .c-файла и возвращающую в него же результат:

 

Насколько я успел понять до этого времени, аргументы функции переносятся в регистры с 0-го по N-ый соответственно по порядку из записи в "()", а вернуть их можно с помощью команды RET. На сайте ПО (сайт Keil) написано, что эта (RET) команда возвращает данные из стека (также в примерах фигурирует BX LR).

Да уж.... С такой кашей в голове рано что-то писать на asm.  :unknw:

"функцию, но только принимающую значение из .c-файла и возвращающую в него же результат" - no comments.  :crazy:

RET vs BX LR: в тех ЦП, в которых есть RET, нету BX LR. А в которых есть BX LR - нету RET. Определитесь всё таки - о каком ЦП ведёте речь? Иначе не понять - что и куда у вас "переносится". Ибо в разных CPU/компиляторах/соглашениях вызова - разные регистры и разный порядок передачи аргументов.

 

PS: Читайте параграф "Соглашения вызова" ("Calling conventions") в документации на ваш компилятор. Что-то типа:  1466738765_IARforARMcallingconventions.png.2cc72c2157a3737c6344f1dcc9b8bb7f.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

11.03.2022 в 14:03, aaarrr сказал:

Гуглите документ под названием AAPCS. Значение возвращается в нулевом регистре, никаких команд не нужно.

 

В Си статические функции тоже "не видны", считайте, что в ассемблере они статические по умолчанию.

Доброго дня, Aaarrr! Благодарю за ответ! Не подскажете ли в завершение этого вопроса, как мне понять (В документе AAPCS сказано, что аргументы переносятся в регистры R0-R3, а возвращаемое значение - в R0...):

 

1. Куда я возвращаю значение в Си или как мне вернуть значение в переменную Си, я хочу в дальнейшем результат вычислений использовать как аргумент в цикле, внутри которого мигает светодиод (а команды return и переменной (напр. return RetVal), куда будет возвращаться значение, в коде Си нет...

2. SimpleSum в итоге есть адрес ячейки в памяти программ (что видно при отладке) и выполнение программы переходит на него. Где заканчивается выполнение этой функции? В конце процедуры start (т.е. в ассемблере данный символ является просто меткой в процедуре, где компилятор обозначает конец её "тела")?

3. Keil пишет, что GLOBAL и EXPORT в ассемблере - синонимы. Есть ли разница в использовании. которая определяет применение каждой директивы в том или ином случае?

 

Мой код Си в заголовочном файле:

 

extern int SimpleSum(int Value);

 

Вызов функции в исполняемом файле:

 

SimpleSum(FirstNum); //помещаю значение переменной FirstNum для использования в вычислениях

 

Часть ассемблерного кода в области DATA:

 

GLOBAL SimpleSum

 

Часть ассемблерного кода в области CODE

 

start PROC

 

SimpleSum

    ....Здесь ассемблерный код (два цикла с метками Loop1(2) и командами между ним)...

    MOV R0, R3 ;Move value to R0 to return

ENDP

ALIGN

END

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, AzardCry said:

1. Куда я возвращаю значение в Си или как мне вернуть значение в переменную Си, я хочу в дальнейшем результат вычислений использовать как аргумент в цикле, внутри которого мигает светодиод (а команды return и переменной (напр. return RetVal), куда будет возвращаться значение, в коде Си нет...

int x = SimpleSum(FirstNum);

 

2 hours ago, AzardCry said:

2. SimpleSum в итоге есть адрес ячейки в памяти программ (что видно при отладке) и выполнение программы переходит на него. Где заканчивается выполнение этой функции? В конце процедуры start (т.е. в ассемблере данный символ является просто меткой в процедуре, где компилятор обозначает конец её "тела")?

С точки зрения ассемблера конец функции - ENDP. С точки зрения процессора концом является команда возврата, которая в приведенном коде отсутствует (напр., mov pc, lr).

 

2 hours ago, AzardCry said:

3. Keil пишет, что GLOBAL и EXPORT в ассемблере - синонимы. Есть ли разница в использовании. которая определяет применение каждой директивы в том или ином случае?

Разницы нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...