ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
void function(int a, int b, int c)
{
char buff[4];
}
int main()
{
function(1, 2, 3);
}
0x0804835c <main+0>: push %ebp
0x0804835d <main+1>: mov %esp,%ebp
0x0804835f <main+3>: sub $0x8,%esp //why substract 8 from esp??
0x08048362 <main+6>: and $0xfffffff0,%esp
0x08048365 <main+9>: mov $0x0,%eax
0x0804836a <main+14>: sub %eax,%esp
0x0804836c <main+16>: sub $0x4,%esp //why substract 4 from esp??
0x0804836f <main+19>: push $0x3
0x08048371 <main+21>: push $0x2
0x08048373 <main+23>: push $0x1
0x08048375 <main+25>: call 0x8048354 <function>
0x0804837a <main+30>: add $0x10,%esp //and then why add back 16 or 0x10 to esp??
0x0804837d <main+33>: leave
0x0804837e <main+34>: ret
1. what the lines 0x08048362, 0x08048365, 0x0804836a ??
2. why not substract 0x12 or 18 in one single instruction? why does it substract 18?
3. why do we add 16 to esp at the end of the call? I mean should it not be before the call? You allready pused 3, 2, 1 on the stack, so does the push not automaticaly store the numbers? I mean why allocate space AFTER you pushed something on the stack, since by pushing it is already on the stack occuping space. And why 16 since an int is 4 bytes and we need only 12 ... ?
The compiler never promised that the code it generates would be identical to your source-code, only that it would do the same thing. Depending on the optimization-level used, machine-specific flags and so forth, the code might be substantially different.
For example, on many processor-types there are things like "cache lines" and the internal bus-width of the processor to think about. Multiples of 16 bytes (that is, addresses which fall on 16-byte boundaries) might be more efficiently handled by the CPU than other widths, so the compiler might "round up."
Then there are "calling conventions" to consider: who reserves space on the stack for a function, and when, and then ditto for cleaning-up. This is why the stack-management instructions occur when and where they do.
Ok, then how do I visualize correctly the stack and where the so called "junk" is? I mean in my case the stack for main would be ...
$1 - this would be 4 bytes ... ?
$2 - this would be also 4 bytes ...
$3 - the same ...
RET - always 4
EBP - always 4
buff - and this should would be 4
Well, basicly, if there are so many options and architectures and methods, how do you visualize the stack? I searched for a software to help that, but I seemed to fine none. I think I must master it myself right ... ?
"It just works." What you'll find, when any function is running, is something like this ...
<<parameters>>
<<stack frame>>
<<local variables>>
<<possible empty space here>>
<<temporary stuff from moment to moment>>
As I said, calling-conventions vary as to who is responsible for setting up the stack-frame, in which order the parameters get pushed onto the stack, and who cleans-up these various things (the caller or the callee). It's quite common to see optimizers deliberately add "extra" space here and there, e.g. to preserve alignment, because the internal on-chip buses of modern CPUs are very wide and favor certain alignments. Or there could be other reasons known only to folks like Richard Stallman.
So, fiddle with your program in various ways and notice how the assembly-code that is generated changes. Enjoy.
Your real question has less to do with assembly-language syntax than with simply trying to understand how and why the x86/C language stack works. That's definitely a commendable goal. I think Mr. Bartlett's book will help - with this, and with future questions you'll undoubtedly have.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.