AzardCry 0 21 февраля, 2022 Опубликовано 21 февраля, 2022 · Жалоба Здравствуйте! В своём проекте создал 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 до конца не читал. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 21 февраля, 2022 Опубликовано 21 февраля, 2022 · Жалоба 4 часа назад, AzardCry сказал: 1. А так вообще кто-то делает, или намного легче через __ASM написать всё в .c-файле? А какая разница, кто как делает? У меня есть .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 до конца не читал... Начать с гугления, как происходит трансляция исходных файлов программы в исполняемый (препроцессирование, компиляция, линковка). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 21 февраля, 2022 Опубликовано 21 февраля, 2022 · Жалоба 4 часа назад, AzardCry сказал: 1. А так вообще кто-то делает, или намного легче через __ASM написать всё в .c-файле? Раз возможность есть, значит кому-то это нужно? Цитата 2. Как правильно организовать включение текста файла RegSum.s (на языке ассемблера) в main.c Никак. Потому как ассемблер и си - это разные языки. И файлы *.s и *.c имеют разный формат. .c-файлы компилирует си-компилятор, .s-файлы (или .asm) - транслятор ассемблера. Оба на выход выдают .obj-файлы. Которые поглощает компоновщик (являются для него входными). На выходе компоновщика - загрузочный образ прошивки (в формате: .hex, .bin или каком-то другом). Цитата 3. Судя по некоторым темам на форуме, есть трудности при организации функции, телом которой является .s-файл Галиматью какую-то пишете. .s-файл не может "являться телом функции". Цитата "Если хотя бы один из ISR, на которые ссылается таблица прерываний, определён в другом файле (а не в этом .asm), то указатель на него будет не константой. Он будет браться на этапе компоновки из таблиц экспорта .obj-файлов. А значит на этапе компиляции он неизвестен. И что? Цитата таблицы экспорта Вам, как начинающему, это не нужно. Изучайте примеры проектов. В многих средах программирования есть множество примеров. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Darth Vader 0 21 февраля, 2022 Опубликовано 21 февраля, 2022 · Жалоба 5 часов назад, AzardCry сказал: В своём проекте создал 5 файлов - main (.c, .h), PortInit (.c, .h), RegSum (.s). Собственно, весь вопросы в том, что: Вы цель свою конечную опишите. Зачем вам нужен именно ассемблерный файл в проекте? Просто, чтобы был? Вы эту функцию на Си написать не можете? Вам ассемблерного стартап-файла мало? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AzardCry 0 24 февраля, 2022 Опубликовано 24 февраля, 2022 (изменено) · Жалоба 21.02.2022 в 19:01, Arlleex сказал: А какая разница, кто как делает? У меня есть .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, может и галиматью, заранее прошу прощения за ошибки в терминологии, сам пока не до конца разобрался :) Изменено 24 февраля, 2022 пользователем AzardCry Правки Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 24 февраля, 2022 Опубликовано 24 февраля, 2022 · Жалоба 26 минут назад, AzardCry сказал: jcxz, Arlleex, судя по всему, не согласен с вами, либо имеет ввиду что-то другое (мне сложно сказать)... Почему? Не вижу противоречий А лучше конкретезируйте, в чем конкретно я, возможно, не согласен с 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(); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
majorka65 1 24 февраля, 2022 Опубликовано 24 февраля, 2022 (изменено) · Жалоба Я вставляю и вызываю asm в asm ( KEIL, stm32). Изменено 24 февраля, 2022 пользователем majorka65 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AzardCry 0 11 марта, 2022 Опубликовано 11 марта, 2022 (изменено) · Жалоба 24.02.2022 в 14:14, Arlleex сказал: Почему? Не вижу противоречий А лучше конкретезируйте, в чем конкретно я, возможно, не согласен с 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 - уже вижу, что разногласий нет. Скорее я неверно сформулировал вопрос, изначально, конечно, имелись ввиду вызовы функций из файлов различного формата, пример чего вы и предоставили. Изменено 11 марта, 2022 пользователем AzardCry Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 11 марта, 2022 Опубликовано 11 марта, 2022 · Жалоба 24 minutes ago, AzardCry said: Насколько я успел понять до этого времени, аргументы функции переносятся в регистры с 0-го по N-ый соответственно по порядку из записи в "()", а вернуть их можно с помощью команды RET. Гуглите документ под названием AAPCS. Значение возвращается в нулевом регистре, никаких команд не нужно. 25 minutes ago, AzardCry said: Также интересно, почему для того, чтобы функция "видела себя" в различных файлах, в .s необходима "EXPORT", а в Си (.h-файле) никакой директивы для этого не предусмотрено. В Си статические функции тоже "не видны", считайте, что в ассемблере они статические по умолчанию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 11 марта, 2022 Опубликовано 11 марта, 2022 · Жалоба 1 час назад, AzardCry сказал: Благодарю за пример! Не подскажите, как сделать ту же функцию, но только принимающую значение из .c-файла и возвращающую в него же результат: Насколько я успел понять до этого времени, аргументы функции переносятся в регистры с 0-го по N-ый соответственно по порядку из записи в "()", а вернуть их можно с помощью команды RET. На сайте ПО (сайт Keil) написано, что эта (RET) команда возвращает данные из стека (также в примерах фигурирует BX LR). Да уж.... С такой кашей в голове рано что-то писать на asm. "функцию, но только принимающую значение из .c-файла и возвращающую в него же результат" - no comments. RET vs BX LR: в тех ЦП, в которых есть RET, нету BX LR. А в которых есть BX LR - нету RET. Определитесь всё таки - о каком ЦП ведёте речь? Иначе не понять - что и куда у вас "переносится". Ибо в разных CPU/компиляторах/соглашениях вызова - разные регистры и разный порядок передачи аргументов. PS: Читайте параграф "Соглашения вызова" ("Calling conventions") в документации на ваш компилятор. Что-то типа: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AzardCry 0 17 марта, 2022 Опубликовано 17 марта, 2022 · Жалоба 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 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 17 марта, 2022 Опубликовано 17 марта, 2022 · Жалоба 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 в ассемблере - синонимы. Есть ли разница в использовании. которая определяет применение каждой директивы в том или ином случае? Разницы нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться