Forums

arm-gcc: avoid calling other system functions

Started by pozz May 17, 2018
I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on the 
code, arm-gcc could call some system functions that are located in Flash.

For example, if I use a switch statement, the compiler calls a piece of 
code of system libraries (that are in Flash) that use a table lookup to 
manage the switch.

Is it possible to force arm-gcc to avoid calling system functions from 
ISRs, so it can be executed completely in RAM?


[*] This is why I need to erase/write Flash memory and during these 
operations the Flash can't be read and code in Flash can't be executed.
On 2018-05-17, pozz <pozzugno@gmail.com> wrote:

> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on > the code, arm-gcc could call some system functions that are located > in Flash.
By "system functions" do you mean gcc built-in functions from libgcc? Or functions from /usr/lib/*whatever*?
> For example, if I use a switch statement, the compiler calls a piece of > code of system libraries (that are in Flash) that use a table lookup to > manage the switch.
If you're talking about libgcc, that's not what most people mean when they refer to "system libraries".
> Is it possible to force arm-gcc to avoid calling system functions
> from ISRs, so it can be executed completely in RAM?
No, I don't think there's any way to prevent gcc from emitting calls to functions provided by libgcc. However, you should be able to put the ISR code in a separate file and link it statically with libgcc, and then locate the resulting object file's code in RAM. Alternatively, you could just manually tweak your linker script to place the specific libgcc functions used by your ISR functions in RAM.
> [*] This is why I need to erase/write Flash memory and during these > operations the Flash can't be read and code in Flash can't be executed.
Using ISRs to program flash seems pretty strange... -- Grant Edwards grant.b.edwards Yow! I am a jelly donut. at I am a jelly donut. gmail.com
Il 17/05/2018 14:37, pozz ha scritto:
> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on the > code, arm-gcc could call some system functions that are located in Flash. > > For example, if I use a switch statement, the compiler calls a piece of > code of system libraries (that are in Flash) that use a table lookup to > manage the switch. > > Is it possible to force arm-gcc to avoid calling system functions from > ISRs, so it can be executed completely in RAM? > > > [*] This is why I need to erase/write Flash memory and during these > operations the Flash can't be read and code in Flash can't be executed.
Something similar to this. https://www.infineonforums.com/archive/index.php/t-4612.html?s=db90f5568d4bffd96e5e60d93e7795f5
Il 17/05/2018 15:27, Grant Edwards ha scritto:
> On 2018-05-17, pozz <pozzugno@gmail.com> wrote: > >> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on >> the code, arm-gcc could call some system functions that are located >> in Flash. > > By "system functions" do you mean gcc built-in functions from libgcc?
Yes, now I know those functions come from libgcc.
> Or functions from /usr/lib/*whatever*? > >> For example, if I use a switch statement, the compiler calls a piece of >> code of system libraries (that are in Flash) that use a table lookup to >> manage the switch. > > If you're talking about libgcc, that's not what most people mean when > they refer to "system libraries".
Built-in functions is a better name?
>> Is it possible to force arm-gcc to avoid calling system functions > > >> from ISRs, so it can be executed completely in RAM? > > No, I don't think there's any way to prevent gcc from emitting calls > to functions provided by libgcc. However, you should be able to put > the ISR code in a separate file and link it statically with libgcc, > and then locate the resulting object file's code in RAM.
It seems complex.
> Alternatively, you could just manually tweak your linker script to > place the specific libgcc functions used by your ISR functions in RAM.
Any help?
> >> [*] This is why I need to erase/write Flash memory and during these >> operations the Flash can't be read and code in Flash can't be executed. > > Using ISRs to program flash seems pretty strange... >
No, I need to serve interrupts *during* Flash erasing/writing. So the ISR code must be placed in RAM.
On 2018-05-17, pozz <pozzugno@gmail.com> wrote:
> Il 17/05/2018 15:27, Grant Edwards ha scritto: >> On 2018-05-17, pozz <pozzugno@gmail.com> wrote: >> >>> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on >>> the code, arm-gcc could call some system functions that are located >>> in Flash. >> >> By "system functions" do you mean gcc built-in functions from libgcc? > > Yes, now I know those functions come from libgcc. > >> Or functions from /usr/lib/*whatever*? >> >>> For example, if I use a switch statement, the compiler calls a piece of >>> code of system libraries (that are in Flash) that use a table lookup to >>> manage the switch. >> >> If you're talking about libgcc, that's not what most people mean when >> they refer to "system libraries". > > Built-in functions is a better name?
Calling them "libgcc functions" is probably the best choice. Anybody familiar with gcc will know what you mean.
>> No, I don't think there's any way to prevent gcc from emitting calls >> to functions provided by libgcc. However, you should be able to put >> the ISR code in a separate file and link it statically with libgcc, >> and then locate the resulting object file's code in RAM. > > It seems complex.
Embedded systems development usually is. :)
>> Alternatively, you could just manually tweak your linker script to >> place the specific libgcc functions used by your ISR functions in RAM. > > Any help?
https://sourceware.org/binutils/docs-2.30/ld/Scripts.html#Scripts https://wiki.osdev.org/Linker_Scripts http://www.bravegnu.org/gnu-eprog/ https://www.embedded.com/design/mcus-processors-and-socs/4026080/Building-Bare-Metal-ARM-Systems-with-GNU-Part-3
>> Using ISRs to program flash seems pretty strange... > > No, I need to serve interrupts *during* Flash erasing/writing. So the > ISR code must be placed in RAM.
OK, that makes more sense. -- Grant Edwards grant.b.edwards Yow! I feel like I am at sharing a ``CORN-DOG'' gmail.com with NIKITA KHRUSCHEV ...
On 17/05/18 14:37, pozz wrote:
> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on the > code, arm-gcc could call some system functions that are located in Flash. > > For example, if I use a switch statement, the compiler calls a piece of > code of system libraries (that are in Flash) that use a table lookup to > manage the switch. > > Is it possible to force arm-gcc to avoid calling system functions from > ISRs, so it can be executed completely in RAM?
There is, AFAIK, no way to force this. It is not normally a problem as ISRs should generally be as short and fast as possible. For functions that must be run from ram, don't call other functions unless it is unavoidable. And when you do, mark those functions as being in the RAM section, or as __attribute__((always_inline)). This doesn't work for language support functions - you avoid these by avoiding using such language features (such as division or software floating point).
> > [*] This is why I need to erase/write Flash memory and during these > operations the Flash can't be read and code in Flash can't be executed.
Note that you can't use ISRs during flash operations unless the vector table is also moved to ram. While you are erasing or writing flash, it is usually easiest to simply disable interrupts. If you really need an interrupt or two running, disable all but the critical ones and make sure these are short and fast.
On 17/05/18 16:18, Grant Edwards wrote:
> On 2018-05-17, pozz <pozzugno@gmail.com> wrote: >> Il 17/05/2018 15:27, Grant Edwards ha scritto: >>> On 2018-05-17, pozz <pozzugno@gmail.com> wrote: >>> >>>> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on >>>> the code, arm-gcc could call some system functions that are located >>>> in Flash. >>> >>> By "system functions" do you mean gcc built-in functions from libgcc? >> >> Yes, now I know those functions come from libgcc. >> >>> Or functions from /usr/lib/*whatever*? >>> >>>> For example, if I use a switch statement, the compiler calls a piece of >>>> code of system libraries (that are in Flash) that use a table lookup to >>>> manage the switch. >>> >>> If you're talking about libgcc, that's not what most people mean when >>> they refer to "system libraries". >> >> Built-in functions is a better name? > > Calling them "libgcc functions" is probably the best choice. Anybody > familiar with gcc will know what you mean.
Or "language support functions" or "language support library functions". These are functions that are there to make the language work, rather than part of the standard library.
Il 17/05/2018 16:18, Grant Edwards ha scritto:
> On 2018-05-17, pozz <pozzugno@gmail.com> wrote: >> Il 17/05/2018 15:27, Grant Edwards ha scritto: >>> On 2018-05-17, pozz <pozzugno@gmail.com> wrote: >>> >>>> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on >>>> the code, arm-gcc could call some system functions that are located >>>> in Flash. >>> >>> By "system functions" do you mean gcc built-in functions from libgcc? >> >> Yes, now I know those functions come from libgcc. >> >>> Or functions from /usr/lib/*whatever*? >>> >>>> For example, if I use a switch statement, the compiler calls a piece of >>>> code of system libraries (that are in Flash) that use a table lookup to >>>> manage the switch. >>> >>> If you're talking about libgcc, that's not what most people mean when >>> they refer to "system libraries". >> >> Built-in functions is a better name? > > Calling them "libgcc functions" is probably the best choice. Anybody > familiar with gcc will know what you mean. > >>> No, I don't think there's any way to prevent gcc from emitting calls >>> to functions provided by libgcc. However, you should be able to put >>> the ISR code in a separate file and link it statically with libgcc, >>> and then locate the resulting object file's code in RAM. >> >> It seems complex. > > Embedded systems development usually is. :)
Not always. Of course it depends on what you are trying to do.
>>> Alternatively, you could just manually tweak your linker script to >>> place the specific libgcc functions used by your ISR functions in RAM. >> >> Any help? > > https://sourceware.org/binutils/docs-2.30/ld/Scripts.html#Scripts > https://wiki.osdev.org/Linker_Scripts > http://www.bravegnu.org/gnu-eprog/ > https://www.embedded.com/design/mcus-processors-and-socs/4026080/Building-Bare-Metal-ARM-Systems-with-GNU-Part-3
Ok, thank you for the references.
>>> Using ISRs to program flash seems pretty strange... >> >> No, I need to serve interrupts *during* Flash erasing/writing. So the >> ISR code must be placed in RAM. > > OK, that makes more sense. >
Il 17/05/2018 17:06, David Brown ha scritto:
> On 17/05/18 14:37, pozz wrote: >> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on the >> code, arm-gcc could call some system functions that are located in Flash. >> >> For example, if I use a switch statement, the compiler calls a piece >> of code of system libraries (that are in Flash) that use a table >> lookup to manage the switch. >> >> Is it possible to force arm-gcc to avoid calling system functions from >> ISRs, so it can be executed completely in RAM? > > There is, AFAIK, no way to force this.&#2013266080; It is not normally a problem as > ISRs should generally be as short and fast as possible.
I always try to keep the ISR short, simple and fast. However a simple switch statement (a different way to write a sequence of if statements) is compiled in assembler code that uses "libgcc functions".
> For functions that must be run from ram, don't call other functions > unless it is unavoidable.
And usually I don't call functions directly from my ISR (it's gcc that calls its libgcc functions). Only a few times I need to call functions from inside the ISRs. It usually happens when I want to create a sufficiently generic low-level driver. For example, consider a UART driver. Most of the time I push the received bytes in a FIFO buffer during ISR. The mainloop polls the FIFO buffer and pop byte by byte and process them. However I sometimes need to process bytes as soon as they are received, so in ISR. For example, because the frame is addressed and I need to receive the frame only if it is directed to me (maybe because a frame addressed to another node could be much longer than the frame I can manage). In order to have a generic driver, the application calls a uart_set_callback(). In this case, the driver calls the "user" callback function when a byte is received, *during ISR*. Another example is an ADC driver that I wrote some time ago. I had 20 analog signals that I needed to convert in 4 different states, depending on the ADC value and depending on the configuration of each signal. switch(signal_conf[signal_idx]) { case CONF1: if (adc_value < 100) signal_status[signal_idx] = ALARM; if (adc_value < 200) signal_status[signal_idx] = IDLE; if (adc_value < 300) signal_status[signal_idx] = SABOT; if (adc_value < 400) signal_status[signal_idx] = SABOT+ALARM; break; case CONF1: if (adc_value < 150) signal_status[signal_idx] = ALARM; if (adc_value < 250) signal_status[signal_idx] = IDLE; if (adc_value < 350) signal_status[signal_idx] = SABOT; break; ... } In order to have a sufficiently generic ADC driver, the application calls adc_set_callback() and the ADC ISR calls this "user callback" when a new sample is available.
> And when you do, mark those functions as > being in the RAM section, or as __attribute__((always_inline)).&#2013266080; This > doesn't work for language support functions - you avoid these by > avoiding using such language features (such as division or software > floating point).
Or switch statements...
>> [*] This is why I need to erase/write Flash memory and during these >> operations the Flash can't be read and code in Flash can't be executed. > > Note that you can't use ISRs during flash operations unless the vector > table is also moved to ram.
I know.
> While you are erasing or writing flash, it is usually easiest to simply > disable interrupts.&#2013266080; If you really need an interrupt or two running, > disable all but the critical ones and make sure these are short and fast.
I'm trying to use MCU Flash to save some non-volatile configuration parameters. The user can change the configuration when he wants. At this moment, the Flash must be erase/written, however the device should work as usual.
On 18/05/18 09:07, pozz wrote:
> Il 17/05/2018 17:06, David Brown ha scritto: >> On 17/05/18 14:37, pozz wrote: >>> I'm trying to put all ISRs in RAM[*]. Unfortunately, depending on the >>> code, arm-gcc could call some system functions that are located in >>> Flash. >>> >>> For example, if I use a switch statement, the compiler calls a piece >>> of code of system libraries (that are in Flash) that use a table >>> lookup to manage the switch. >>> >>> Is it possible to force arm-gcc to avoid calling system functions >>> from ISRs, so it can be executed completely in RAM? >> >> There is, AFAIK, no way to force this. It is not normally a problem >> as ISRs should generally be as short and fast as possible. > > I always try to keep the ISR short, simple and fast. However a simple > switch statement (a different way to write a sequence of if statements) > is compiled in assembler code that uses "libgcc functions".
Can you give an small example here? That sounds very strange. gcc can use a variety of tactics for switch statements, including jump tables, calculated jumps, sequences of conditional tests, and binary trees of conditional tests - and combinations of these. But I can't think of any situation where it would use a language support function (at least, not on an ARM). (I've snipping most of the rest of the post, because it all sounds sensible enough. Just remember that if you set callback functions, these also need to be short, in ram, etc., according to need.)
> >> And when you do, mark those functions as being in the RAM section, or >> as __attribute__((always_inline)). This doesn't work for language >> support functions - you avoid these by avoiding using such language >> features (such as division or software floating point). > > Or switch statements... > > >>> [*] This is why I need to erase/write Flash memory and during these >>> operations the Flash can't be read and code in Flash can't be executed. >> >> Note that you can't use ISRs during flash operations unless the vector >> table is also moved to ram. > > I know. > >> While you are erasing or writing flash, it is usually easiest to >> simply disable interrupts. If you really need an interrupt or two >> running, disable all but the critical ones and make sure these are >> short and fast. > > I'm trying to use MCU Flash to save some non-volatile configuration > parameters. The user can change the configuration when he wants. At this > moment, the Flash must be erase/written, however the device should work > as usual.
You may be asking the impossible here. Flash writes are usually quick, and can often be squeezed in by disabling most interrupts. (DMA on things like UARTs can help give you more leeway here.) But erases take time. Many devices allow erase suspend, which is one possibility for dealing with things that /have/ to use flash while you are trying to do an erase. It can be messy and fiddly, and regular erase suspend can reduce the erase/write lifetime of the flash. And of course many devices have separate flash planes, letting you read from one plane while the other is being erased or written. But if you have a single plane flash device, and need to erase (rather than just writing in a log structure), and need to run normally while erasing - there might not be a good solution at all. A small serial e&#2013266098;prom is a very cheap way to make a much better solution.