7

I have the following piece of code:

extern void func1(char *array);
extern void func2(char *array);

void myfunction(void) {
    if (somecondition) {
        char var2[256];
        func2(var2);
    }
    if (someothercondition) {
    {
        char var3[3];
        func3(var3);
    }
}

I cannot get my compiler (gcc) to call func3 with only 3 bytes used for var3 in the stack. It always allocates the space for the var2 used in the scope for func2 call, even though this variable is out of scope and could have been safely removed from the stack.

I have tried several options that I found in the gcc documentation:

  • fomit-frame-pointer
  • fconserve-stack

I have tried this on both x86 and ARM architectures and it behaves identically.

The rationale behind this question is to use only the stack size that is necessary.

And the related question: if it is possible to optimize the stack space, is it possible to add the stack used for each sub-function call in the .su file generated by the option -fstack-usage .

thanks

phuclv
  • 37,963
  • 15
  • 156
  • 475
Louis Caron
  • 1,043
  • 1
  • 11
  • 17
  • 4
    It doesn't work that way. Stack space is allocated once in the function prologue, and released once in the function epilogue. It's not like the stack pointer is being thrashed about as variables go in and out of scope. You can manage stack space yourself with the `alloca` function. – user3386109 Sep 12 '22 at 17:52
  • Unfortunately, this is generated code, so I am stuck with it! Is there a documentation related to the way gcc handles the stack allocation? thanks – Louis Caron Sep 12 '22 at 18:00
  • 3
    @user3386109: Re “It doesn't work that way.”: GCC might not operate that way, but it is not mandated by the C standard, and a compiler could allocate stack space block-by-block instead of by function. – Eric Postpischil Sep 12 '22 at 18:04
  • You can try moving the blocks into functions of their own, which can be declared `static`. However, the compiler still might inline them and bring their stack use back into the function. – Eric Postpischil Sep 12 '22 at 18:05
  • 2
    Note that the stack space used commonly has little or no effect on the program unless it is exceeding the stack limit or there is some additional interaction that is confounding performance. Unless you reduce the stack use in many function calls (of different functions or recursively of the same function), you are unlikely to see considerable benefit. Why are you trying to reduce stack use in this function? – Eric Postpischil Sep 12 '22 at 18:07
  • 2
    @EricPostpischil: yes I am struggling with stack overflows that should not occur if the stack was actually used as it was intended to be when the code was written (variables have limited scope etc...). In my real example, I have a block that requires 4kB of RAM and a subfunction in another block that requires 4kB, those two sum up instead of sharing the space. I have a microcontroller with 256kB of RAM only. – Louis Caron Sep 12 '22 at 19:19
  • Perhaps you should post that code, so we can see what you are really dealing with. – user3386109 Sep 12 '22 at 19:53
  • 1
    @user3386109: Unfortunately, I can't really share the code, but it is very similar to the code I created as an example. Actually, I would like to post an answer to my question for everyone: explain why this is not possible (documentation) and show possible mechanisms (use functions). Do you have a link to the documentation explaining that the stack is allocated only once in the prologue? thanks – Louis Caron Sep 13 '22 at 07:26
  • Maybe you can use a *union* which contains the (overlayed) variables? The prologue of the function would allocate the biggest space, but not the sum of the single variables. – linuxfan says Reinstate Monica Jul 10 '23 at 04:37

1 Answers1

1

You could do something like this:

extern void func1(char *array);
extern void func2(char *array);

void _helper(/* neccessary parameters */)
{
    char var2[256];
    func2(var2);
}

void myfunction(void) {
    if (somecondition) {
        _helper(/* neccessary parameters */);
    }
    if (someothercondition) {
    {
        char var3[3];
        func3(var3);
    }
}

Because the allocation happens in a different function the compiler will only allocate the memory when the _helper is called. This is probably susceptible to optimization (inlining), but moving the helper to a different compilation unit (new c file) will prevent that.

Of course this will come at a cost of a function call and parameter copying.

Anyways, if the stack space problem is related to recursion, you should consider replacing that with an iterative solution that uses explicitly pre-allocated stack.

anton-tchekov
  • 1,028
  • 8
  • 20
  • This is the solution I came up with, but since my code is auto-generated by a close-source commercial tool, i can not modify it. I was looking for a compiler option to allow this kind of optimization. – Louis Caron Jul 10 '23 at 08:57