CyberPsychotic wrote:
> hmm.,. I have written simple code which basically looks like:
>
> #include <stdlib.h>
>
> void main(int argc,char **argv,char **envp)
> { char s[1024];
> strcpy(s,"some char data");
> }
> now I look in the source, generated with gcc -S somecode.c
>
> pushl %ebp //
> movl %esp,%ebp // so here we prepare the "procedure"
> // so far I understood : passed data, previous ebp and return address for
> // each produre, is called frame here, right?
Prior to these instructions, the stack contains the return address and
any parameters (argc, argv, envp). It doesn't matter what ebp
contains; however, if you're going to modify it, you need to save it
here and restore it before returning.
>
> subl $1024,%esp // reserve memory in stack for variables?
> // (i added int foo; and got here subl $1028,%esp
> // so, it reserves memory for all varibles
> // altogether?
Yep. 1024 bytes for `s' and 4 bytes for `foo'.
After these three instructions have been executed, the stack frame has
been set up.
> pushl $.LC0 // this label points to string.
> // hmm, all arguments are passed to the calls
> // in upside-down order, i.g first parameter is
> // pushed last, right?
Yep. The stack grows downwards, so later parameters will be at
higher-numbered memory addresses.
> leal -1024(%ebp),%eax // -1024? it refers to local variable here?
This means `eax = ebp - 1024', i.e. eax points to the start of the
array `s'.
> pushl %eax // and why it pushes eax?
Because it's a parameter. The calling convention for Intel-Linux is
that all parameters are passed on the stack. So now, the bottom of the
stack contains s and a pointer to the string.
> call strcpy
> addl $8,%esp // and this thing is not clear to me..:(
> // why would it want to incement stack?
You pushed 8 bytes (2 32-bit words) onto the stack before calling
strcpy. Functions don't remove their parameters from the stack (i.e.
esp is unchanged by the function call), so the calling function needs
to remove them (well, it doesn't actually need to; if you enable
optimisation, it will omit this instruction).
> .L1:
> leave // this equal to
> // movl %ebp,%esp
> // popl %ebp
> // right?
Yep, and `enter $1024,$0' is equivalent to
pushl %ebp
movl %esp,%ebp
subl $1024,%esp
> > Upon entry to the function, the stack looks like this:
> >
> > param 3
> > param 2
> > param 1
> > return address
> > esp ->
>
>
> hmm.. and what are there params? The parameters passed to procedure?
Yep.
> I played with gdb alittle, and found that main() has argc/ **argv
> things.. so they are just pushl'ed into stack, just before main is called,
> right?
Right.
> > After the entry code has been executed, the stack looks like this:
>
> > param 3
> > param 2
> > param 1
> > return address
> > saved ebp
> /-> ebp -> local var 1
> +----| > local var 2
> | | > local var 3
> | \-> esp ->..
> |
> +-- so this offset is done by sub-call. (which reserves mem). hmm.
> compiler doesn't refer to variables by names at all here right? Does gcc
> just "remembers" only offsets for each variable is stack?
gcc converts variable names into addresses. Global (and `static'
local) variables have absolute addresses (unless you're compiling
shared libraries with `-fPIC'). Function parameters get translated to
`ebp+<offset>', (non-`static') local variables to `ebp-<offset>'.
> > Here, ebp is the `frame pointer'.
>
> and the set of local variables, is frame. is it?
The `frame' consists of the parameters, the return address, and local
variables.
> > The code which comprises the
> > function refers to the function's parameters as ebp+<offset>, and
> > local variables as ebp-<offset>.
>
> so in the listing above, it had leal $-1024(%ebp),%eax to refer to s
> variavle (load its pointer), right?
Yep. `lea' => `Load Effective Address'. The `l' suffix is for `long'
(i.e. 32-bits).
> > If you compile with the -fomit-frame-pointer switch, the entry code
> > isn't generated. Instead, parameters and local variables are
> > referenced relative to esp.
>
> I see. I wonder why frames (if i use this word right here) were involved
> at all.,.. except making things easier for debuggers, i don't see much
> profit of it.. maybe i am having something out of my sight?
Making things easier for debuggers is part of it. It also makes code
generation easier (early compilers always used stack frames). Also, if
you don't have a frame pointer, you can't restore the stack via
`leave' (or equivalent); you have to use `addl <constant>,%esp', and
keep track of what <constant> should be.
> > The purpose of the -fomit-frame-pointer switch is to make an extra
> > register (ebp) available for use within the function. On the Intel
> > processors, which have very few registers compared to most other
> > architectures, this can provide a significant increase in performance
> > for certain types of code.
>
> like which?
Typically loops which need all available registers and don't call any
other functions.
> > instructions which do exactly the same thing as the entry and exit
> > code shown above. However they are slower than the code shown above
> > (on the 486 at least; I don't know the relative timings on the
> > Pentium).
>
> slower, hmm, my book says leave takes 5 clocks,
> movl takes from 3 up to 16 clocks, and pop takes from 3 up to 16 clocks, I
> thought leave should work faster.
Hmm. 3 clocks seems rather slow for movl/popl. It's certainly quicker
on a Pentium.
> and there's another question about gdb, (if you don't mind): what would
> such message mean:
>
> 0x8048695 <_fini+69>: orb (%eax),%al
> 0x8048697 <_fini+71>: boundl 0x73(%ecx),%esp
> 0x804869a <_fini+74>: Cannot access memory at address 0x804869b.
>
>
> .. have i reached the end of segment here?
It looks like it.
> plus sometimes while doing debugs, i have "SIGFAULT in libc.XX or
> some function or whatever,..thing*) how do i see where exactly things
> are broken?
Typing `where' will give you a list of stack frames. `frame <n>' will
activate frame <n>, which will allow you to check the parameters which
are passed to it, and the values which it's passing to the function
that's being called.
Also, if you have a debug version of a library (they typically have a
`_g' suffix, e.g. `libfoo_g.a'), you can link with that. This will
enable you to select frames corresponding to library functions, and
reference parameters and variables by name.
--
Glynn Clements <[EMAIL PROTECTED]>