Hello, because I am writing a recursive function I wanted to see how much room I had in the stack and am curious how I might calculate the amount of space that my function uses.
Also, when I ran getrlimit to see how much space that I had I got -1 as the maximum limit, I’m not certain what size the structures fields are but I assumed int when printf-ing, so does this mean unlimited or what?
On 2014-10-03, ballsystemlord <ballsystemlord@no-mx.forums.opensuse.org> wrote:
>
> Hello, because I am writing a recursive function I wanted to see how
> much room I had in the stack and am curious how I might calculate the
> amount of space that my function uses.
How much stack space your function uses is known at compile time. If you compile with gcc invoking the `-S’ flag and
look at the assembler of the function in the assembler file (maincode.s), you can see how much is subtracted from the
stack pointer (ESP or RSP). If you want to keep an eye on the stack pointer during runtime, of course you can use gdb,
but to step throuch assembler instructions, you need to use something like:
disp/i $pc
si
… and changes to the stack pointer at the start of functions (assuming you put the gdb’s breakpoints at the right
place) will hit you right in your face!
Also, when I ran getrlimit to see how much space that I had I got -1 as
the maximum limit, I’m not certain what size the structures fields are
but I assumed int when printf-ing, so does this mean unlimited or what?
Not quite sure what you mean (also I’m not familiar with retrlimit). The size of structure fields are known at compile
time and can be easily outputted without having to resort to assembler, e.g.:
# include <stdio.h>
struct eg {
int foo;
double bar;
};
int main() {
struct eg ex;
printf("Bytes used by foo field: %d
", (char*)&ex.bar - (char*)&ex.foo);
return 0;
}
…yields…
sh-4.2$ gcc a.c
sh-4.2$ ./a.out
Bytes used by foo field: 8
sh-4.2$
On 2014-10-03, flymail <flymail@no-mx.forums.opensuse.org> wrote:
> How much stack space your function uses is known at compile time. If you compile with gcc invoking the `-S’ flag and
look at the assembler of the function in the assembler file (maincode.s), you can see how much is subtracted from the
stack pointer (ESP or RSP).
… and of course this doesn’t just include explicit subtraction instructions but the number of `push’ calls aswell.
… incidently, for the program listed above (a.c), you can see the stack size used for the main() function:
sh-4.2$ gcc -S a.c
sh-4.2$ cat a.s
.file "a.c"
.section .rodata
..LC0:
.string "Bytes used by foo field: %d
"
.text
.globl main
.type main, @function
main:
..LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $8, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
..LFE0:
.size main, .-main
.ident "GCC: (SUSE Linux) 4.8.1 20130909 [gcc-4_8-branch revision 202388]"
.section .note.GNU-stack,"",@progbits
sh-4.2$
… the stack size if revealed by the line `subq $16, %rsp’.
Thanks, flymail. I can’t read assembler, yet, but it seems to me that in the case of my function the stack pointer is only incremented (or would it be decremented since the stack stacks down on an x86-64), by 208 bytes (if $208 == bytes), and that seems kinda small for a mostly auto generated function, which, when generated is 600KiB. I called gcc -O0 so, I doubt that it’s an optimization problem, still it’s not a finished function and so some of the code may appear dead to gcc. FYI I eliminated the other functions in the file prior to compilation so it is the correct one.
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $208, %rsp
On 2014-10-23, ballsystemlord <ballsystemlord@no-mx.forums.opensuse.org> wrote:
> Thanks, flymail. I can’t read assembler, yet, but it seems to me that in
> the case of my function the stack pointer is only incremented (or would
> it be decremented since the stack stacks down on an x86-64), by 208
> bytes (if $208 == bytes), and that seems kinda small for a mostly auto
> generated function, which, when generated is 600KiB. I called gcc -O0
> so, I doubt that it’s an optimization problem, still it’s not a finished
> function and so some of the code may appear dead to gcc. FYI I
> eliminated the other functions in the file prior to compilation so it is
> the correct one.
The stack pointer subtraction is only relevant for the scope of the function you are looking at. If the specific
function is a stem function rather than a leaf function, the minuend of the subtraction (not to mention the number of
push calls) is of very limited (or any) use. If you have a stem function with conditional branches/loops (e.g.
for/if/while/etc…) affecting the number of downstream function calls, there’s no way of being certain of the stack
pointer movement at compile time. And things get even trickier with recursive calls…
Therefore the only way you can work out the total stack manipulations is at runtime. I can think of three ways this can
be done.
- gdb (although you’ll need to be fairly patient and confident using gdb to use it in this way).
- use an IDE that charts stack usage with judicious use of program pauses (I assume this exists).
Of course the UNIX specification includes outputting the maximum stack size (typically 8 MB)…
sh-4.2$ ulimit -s
…but I can’t see any way of using this to help you determine the stack usage in your C programs.
Well, having just looked at valgrind there is a tool called hellgrind which might help, the last time I used it though valgrind segfaulted (but the program I was using it on was valid as far as memcheck, gdb, and yours truly could tell). And, come to think of it, ulimit could be set super low and then my program would die and I could tell from that how big the stack is…
But, I was more interested in a single functions affect on the stack then my whole programs. Still if I just created an int main(void) and had it call the function with dummy arguments. Hmmm… maybe I should ask the gcc folks, they might be able to give me a few pointers.
I wrote that wrong. The valgrind tool I’m thinking of is called massif not hellgrind (I was reading the hellgrind docs.)