10

In a C program that doesn't use recursion, it should be possible in theory to work out the maximum/worst case stack size needed to call a given function, and anything that it calls. Are there any free, open source tools that can do this, either from the source code or compiled ELF files?

Alternatively, is there a way to extract a function's stack frame size from an ELF file, so I can try to work it out manually?

I'm compiling for the MSP430 using MSPGCC 3.2.3 (I know it's an old version, but I have to use it in this case). The stack space to allocate is set in the source code, and should be as small as possible so that the rest of memory can be used for other things. I have read that you need to take account of the stack space used by interrupts, but the system I'm using already takes account of this - I'm trying to work out how much extra space to add on top of that. Also, I've read that function pointers make this difficult. In the few places where function pointers are used here, I know which functions they can call, so could take account of these cases manually if the stack space needed for the called functions and the calling functions was known.

Static analysis seems like a more robust option than stack painting at runtime, but working it out at runtime is an option if there's no good way to do it statically.

Edit:

I found GCC's -fstack-usage flag, which saves the frame size for each function as it is compiled. Unfortunately, MSPGCC doesn't support it. But it could be useful for anyone who is trying to do something similar on a different platform.

cjc
  • 101
  • 1
  • 4
  • Is this really the way to solve your problem? I was always rather generous with stack and protected it with stack canaries to see it is intact. The main problem with this approach I think is that it may raise trouble later. Such as when you need to go for larger program memory with say, 24 bit PC instead of 16 (now just general 8bit experience), or you just need some extra functionality best realized with some extra layers of calls. Then a precisely set stack may really come back on you. Of course if you are squeezing out the last bits, then OK, but I think this really should be the last. – Jubatian Jul 05 '13 at 19:08
  • "Are there any free, open source tools that can do this". There is a free version of (not open souce) IAR IDE (for 30 days or 4K code limit), in which the linker listing option generates the stack usage for the application. Even though you are using the GCC, for getting the detailed information like Stack Size (total and for each function), code size (total and for each function) and other details like memory placement and variable addresses and sizes etc, you can use IAR Embedded workbench. – Harikrishnan Aug 03 '13 at 06:51
  • possible duplicate of [Checking stack usage at compile time](http://stackoverflow.com/questions/126036/checking-stack-usage-at-compile-time) – shodanex Nov 05 '13 at 07:53

5 Answers5

2

While static analysis is the best method for determining maximum stack usage you may have to resort to an experimental method. This method cannot guarantee you an absolute maximum but can provide you with a very good idea of your stack usage.

You can check your linker script to get the location of __STACK_END and __STACK_SIZE. You can use these to fill the stack space with an easily recognizable pattern like 0xDEAD or 0xAA55. Run your code through a torture test to try and make sure as many interrupts are generated as possible.

After the test you can examine the stack space to see how much of the stack was overwritten.

LogicG8
  • 1,767
  • 16
  • 26
  • You can even declare these as extern. `extern char __STACK_END;` `&__STACK_END` will be the address of the last byte in the stack – Michael Apr 09 '15 at 22:20
0

Interesting question.

I would expect this information to be statically available in the debugging data included in debug builds.

I had a brief look at the DWARF standard, and it does specify two attributes for functions called DW_AT_frame_base and DW_AT_static_link which can be used to "computes the frame base of the relevant instance of the subroutine that immediately encloses the subroutine or entry point".

unwind
  • 391,730
  • 64
  • 469
  • 606
  • Thanks. I'm not sure how useful those are, but I did come across 'call frame information' in the DWARF spec, which looks like it might have more information. Now I just need to get GCC to generate the .debug_frame section - `-gdwarf-2 -g3` doesn't do it. – cjc Apr 01 '13 at 18:37
0

I think that the only to go is by static analysis. You need to account the space for all non-static local variables, which are going to be mostly pointers, but pointers that are going to be stored in the stack anyway, you'll need also to reserve space for the current running address within the caller, as it's going to be stored by the compiler on the stack so control can be return to the caller after your function returns, and also, you need space for all your function parameters. Based on that, if you have a tool able to count all parameters, auto variables and figure out their size, you should be able to calculate the minimum stack frame size you'll need. Please note that the compiler could also try to align values on the stack for your particular architecture, what could make the stack space requirements a little bigger that what you'd expect from this calculation.

0

Some embedded IDE can give info on stack usageduring runtime I know that IAR eembedded workbench supports it.

Be aware that you need to take in account that interrupts occur asynchronously, so take the biggest stack usage scenario and add interrupt context to it. If nested interrupts are supported like in ARM processors you need to take this in account also.

stdcall
  • 27,613
  • 18
  • 81
  • 125
0

TinyOS has some work done on stack size analysis. It is described here: http://tinyos.stanford.edu/tinyos-wiki/index.php/Stack_Analysis

They only support AVR, but say that "MSP430 is not difficult to support but this is not super high priority". In any case, the page provides lots of resources.

theamk
  • 1,420
  • 7
  • 14