Stack growing in wrong direction in Linux - c

I have studied that in linux system Stack grow from high memory ddress to low memory address. To test this i have written a small code:
#include<stdio.h>
void func() {
int var1;
int var2;
printf("Func: %p %p",&var1,&var2);
}
int main() {
int var1;
int var2;
printf("Main: %p %p\n",&var1,&var2);
func();
return 0;
}
While I run this in in ideone, I get following output:
Main: 0xbfd958f0 0xbfd958f4
Func: 0xbfd958f8 0xbfd958fc
According to the textbook, Func should be stored in Lower memory address than Main, but here what is happening is completely opposite. Can somebody explain me this behaviour. Here is the link to ideone.
Thank you.

Typically the stack grows down from high memory, and the heap grows up from low memory, so they will never "bump into" each other.
The stack can theoretically grow in either direction, though. x86 supports stacks growing either direction but I've never seen anyone use an upward-growing stack on purpose.
The best part is that Intel refers to downward-growing stacks as "grow up" and upward-growing stacks as "grow down."
NOTE:- You should not assume anything about the ordering of local variables inside the stack frame. The compiler might put the "first" variable "first" in the sense of pushing it at the current location, meaning the "first" variable is at a higher address. Or it could organize the variables upward in memory (more likely) giving the "first" variable a lower address. Or it could arrange the variables completely at random. If optimizing, it may even eliminate variables, or use the same memory location for more than one variable if their lifetimes don't overlap.
You can follow this link
BUFFER OVERFLOW 7
but it's still important to know that the return address is not guaranteed to be arranged in any particular way. If -fomit-frame-pointer is used, then the base pointer will not be on the stack. And as I said before, the ordering of local variables conforms to no specific convention.
Another complication is the presence of more than one calling convention in the same program. It is not generally possible just by looking at code addresses to tell what convention a function conforms to. The stack frame may look very different from what you expect.

Related

Is stack memory allocation for 64 bit computers very different from 32 bit computers?

I'm reading Jon Erickson's art of exploitation and have a general idea about memory allocation on the stack. But the book is for 32 bit systems and I own a 64 bit system. I know that stack grows along lower memory addresses so if you initialize a certain variable var_one before var_two in a function, var_one in theory, should have a larger value of memory address than var_two. However, when I'm trying some of the exploitation techniques on my 64 bit system, its not quite making sense to me. In one of the programs I initialized an int type variable after I initialized a char buffer but still the int variable was at a higher memory address than the buffer. I tried 3 things:
int pass_check(char *password) {
char pass_buffer[10];
int auth = 0;
strcpy(pass_buffer, password);
Once like the one shown above, once with auth variable initialized before pass_buffer (initialized first) and one auth variable initialized after the strcpy() line. When examining with gdb, I'm getting the same memory address of auth variable every time for each variation of the code. I'm sure I did not make any silly error, made 3 different binaries for the 3 variants, disabled ASLR and even disabled gcc code optimizer. So why am I getting a result like this?
The C compiler is not obligated to put variables in memory in the order that you initialized them in the function. In fact, it intentionally doesn't do so. A lot of modern compilers will actually put buffers after local variables when possible so that you can't overflow from a buffer into a local variable.
Concerning your comment:
I know that stack grows along lower memory addresses
Although most of the platforms have a stack growing downward, some platform do not. For example, the manual of clone() system call says that:
stacks grow downward on all processors that run Linux (except the HP PA processors)
So, for a maximum portability, it is not advised to make any assumption on the way the stack grows.
Concerning the order of the local variables, if you really need to have a deterministic order, an interesting comment on StackExchange says:
wrapping your local variables in a structure should be enough to prevent GCC reordering them.
#include <stdio.h>
struct local_vars{
int var1;
char buffer[40];
int var2;
};
int main(void)
{
struct local_vars locals;
printf("#var1=%p, #buffer=%p, #var2=%p\n", &(locals.var1), &(locals.buffer), &(locals.var2));
}
$ gcc p.c -o p
$ ./p
#var1=0x7ffef59b23e0, #buffer=0x7ffef59b23e4, #var2=0x7ffef59b240c

Assembly local variable and parameters

I have the following code
#include<stdio.h>
int adunare(int a,int b)
{
int c=3;
int d=6;
while(c>10) c++;
if(c>15) return a+b+c+d;
else return a+b+c-d;
}
int main()
{
int w=5;
int y=6;
printf("%d",adunare(w,y));
}
My question is in assembly it puts the variable w,y at the [esp+24] ,[esp+28].
Why it puts my variables there?
I know that local variables are always [ebp-....].
Why here it is not [ebp-..]?
I know that local variables are always [ebp-....]
They're not (as evidenced by your question too, I suppose).
It's legal for a compiler to compile really naively, always using a frame pointers (even in functions that don't do variable-size stack allocations) and always putting locals on the stack in the first place (which is definitely not a rule). In a first year course in university, it is sometimes pretended that that's normal, to keep things simple.
Not using a frame pointer is usually possible, it works mostly the same as if you had used one except that offsets are calculated relative to the stack pointer, which you are now only allowed to move in predictable ways. Because it has to be predictable (that is, every instructions that references a stack slot can use a constant offset to do so), this optimization cannot be used in functions that use alloca or VLAs. In your example function neither are used, so no frame pointer is necessary.
Also in general you should not expect local variables to correspond to specific stack slots in the first place, regardless of how they are addressed. It is allowed, common, and often a good thing, to keep a variable in a register over the entire lifetime of the variable. Especially if that life time is short or if the usage-density is very high. On top of that, variables with non-overlapping life times can (and should, because it reduces the stack size) share stack slots, since it would be the case that at most one of them needs storage at any one moment (thanks to the assumption of non-overlapping life times).
It's also allowed to have a variable hop from one stack slot to an other, this might happen when you swap two variables in a way that allows the swap to be resolved "virtually", by just changing which stack slot the variables live in and not actually exchanging the data.
That's probably a compiler optimization. The variables aren't used within main scope so are placed directly on the stack, ready for the function call.

How do pointers work "under the hood" in C?

Take a simple program like this:
int main(void)
{
char p;
char *q;
q = &p;
return 0;
}
How is &p determined? Does the compiler calculate all such references before-hand or is it done at runtime? If at runtime, is there some table of variables or something where it looks these things up? Does the OS keep track of them and it just asks the OS?
My question may not even make sense in the context of the correct explanation, so feel free to set me straight.
How is &p determined? Does the compiler calculate all such references before-hand or is it done at runtime?
This is an implementation detail of the compiler. Different compilers can choose different techniques depending on the kind of operating system they are generating code for and the whims of the compiler writer.
Let me describe for you how this is typically done on a modern operating system like Windows.
When the process starts up, the operating system gives the process a virtual address space, of, let's say 2GB. Of that 2GB, a 1MB section of it is set aside as "the stack" for the main thread. The stack is a region of memory where everything "below" the current stack pointer is "in use", and everything in that 1MB section "above" it is "free". How the operating system chooses which 1MB chunk of virtual address space is the stack is an implementation detail of Windows.
(Aside: whether the free space is at the "top" or "bottom" of the stack, whether the "valid" space grows "up" or "down" is also an implementation detail. Different operating systems on different chips do it differently. Let's suppose the stack grows from high addresses to low addresses.)
The operating system ensures that when main is invoked, the register ESP contains the address of the dividing line between the valid and free portions of the stack.
(Aside: again, whether the ESP is the address of the first valid point or the first free point is an implementation detail.)
The compiler generates code for main that pushes the stack pointer by lets say five bytes, by subtracting from it if the stack is growing "down". It decreases by five because it needs one byte for p and four for q. So the stack pointer changes; there are now five more "valid" bytes and five fewer "free" bytes.
Let's say that q is the memory that is now in ESP through ESP+3 and p is the memory now in ESP+4. To assign the address of p to q, the compiler generates code that copies the four byte value ESP+4 into the locations ESP through ESP+3.
(Aside: Note that it is highly likely that the compiler lays out the stack so that everything that has its address taken is on an ESP+offset value that is divisible by four. Some chips have requirements that addresses be divisible by pointer size. Again, this is an implementation detail.)
If you do not understand the difference between an address used as a value and an address used as a storage location, figure that out. Without understanding that key difference you will not be successful in C.
That's one way it could work but like I said, different compilers can choose to do it differently as they see fit.
The compiler cannot know the full address of p at compile-time because a function can be called multiple times by different callers, and p can have different values.
Of course, the compiler has to know how to calculate the address of p at run-time, not only for the address-of operator, but simply in order to generate code that works with the p variable. On a regular architecture, local variables like p are allocated on the stack, i.e. in a position with fixed offset relative to the address of the current stack frame.
Thus, the line q = &p simply stores into q (another local variable allocated on the stack) the address p has in the current stack frame.
Note that in general, what the compiler does or doesn't know is implementation-dependent. For example, an optimizing compiler might very well optimize away your entire main after analyzing that its actions have no observable effect. The above is written under the assumption of a mainstream architecture and compiler, and a non-static function (other than main) that may be invoked by multiple callers.
This is actually an extraordinarily difficult question to answer in full generality because it's massively complicated by virtual memory, address space layout randomization and relocation.
The short answer is that the compiler basically deals in terms of offsets from some “base”, which is decided by the runtime loader when you execute your program. Your variables, p and q, will appear very close to the “bottom” of the stack (although the stack base is usually very high in VM and it grows “down”).
Address of a local variable cannot be completely calculated at compile time. Local variables are typically allocated in the stack. When called, each function allocates a stack frame - a single continuous block of memory in which it stores all its local variables. The physical location of the stack frame in memory cannot be predicted at compile time. It will only become known at run-time. The beginning of each stack frame is typically stored at run-time in a dedicated processor register, like ebp on Intel platform.
Meanwhile, the internal memory layout of a stack frame is pre-determined by the compiler at compile-time, i.e. it is the compiler who decides how local variables will be laid out inside the stack frame. This means that the compiler knows the local offset of each local variable inside the stack frame.
Put this all together and we get that the exact absolute address of a local variable is the sum of the address of the stack frame itself (the run-time component) and the offset of this variable inside that frame (the compile-time component).
This is basically exactly what the compiled code for
q = &p;
will do. It will take the current value of the stack frame register, add some compile-time constant to it (offset of p) and store the result in q.
In any function, the function arguments and the local variables are allocated on the stack, after the position (program counter) of the last function at the point where it calls the current function. How these variables get allocated on the stack and then deallocated when returning from the function, is taken care of by the compiler during compile time.
For e.g. for this case, p (1 byte) could be allocated first on the stack followed by q (4 bytes for 32-bit architecture). The code assigns the address of p to q. The address of p naturally then is 5 added or subtracted from the the last value of the stack pointer. Well, something like that, depends on how the value of the stack pointer is updated and whether the stack grows upwards or downwards.
How the return value is passed back to the calling function is something that I'm not certain of, but I'm guessing that it is passed through the registers and not the stack. So, when the return is called, the underlying assembly code should deallocate p and q, place zero into the register, then return to the last position of the caller function. Of course, in this case, it is the main function, so it is more complicated in that, it causes the OS to terminate the process. But in other cases, it just goes back to the calling function.
In ANSI C, all the local variables should be placed at the top of the function and is allocated once into the stack when entering the function and deallocated when returning from the function. In C++ or later versions of C, this becomes more complicated when local variables can also be declared inside blocks (like if-else or while statement blocks). In this case, the local variable is allocated onto the stack when entering the block and deallocated when leaving the block.
In all cases, the address of a local variable is always a fixed number added or subtracted from the stack pointer (as calculated by the compiler, relative to the containing block) and the size of the variable is determined from the variable type.
However, static local variables and global variables are different in C. These are allocated in fixed locations in the memory, and thus there's a fixed address for them (or a fixed offset relative to the process' boundary), which is calculated by the linker.
Yet a third variety is memory allocated on the heap using malloc/new and free/delete. I think this discussion would be too lengthy if we include that as well.
That said, my description is only for a typical hardware architecture and OS. All of these are also dependent on a wide variety of things, as mentioned by Emmet.
p is a variable with automatic storage. It lives only as long as the function it is in lives. Every time its function is called memory for it is taken from the stack, therefore, its address can change and is not known until runtime.

need explanation of how memory address work in this C program

I have a very simple C program where I am (out of my own curiosity) investigating which memory addresses are used to allocate local variables. My program is:
#include <stdio.h>
int main()
{
char buffer_1[8], buffer_2[8], buffer_3[8];
printf("address of buffer_1 %p\n", buffer_1);
printf("address of buffer_2 %p\n", buffer_2);
printf("address of buffer_3 %p\n", buffer_3);
return 0;
}
output is as follows:
address of buffer_1 0x7fff5fbfec30
address of buffer_2 0x7fff5fbfec20
address of buffer_3 0x7fff5fbfec10
my question is: why do the address seem to be getting smaller? Is there some logic to this? thank you.
The compiler is allowed to do whatever it wants with your automatic variables. In this case it just looks like it's putting them consecutively on the stack. On most popular systems in use today, stacks grow downwards.
Most compilers allocate stack memory for local variables in one step, at the very beginning pf the function. The memory is allocated as a single continuous block. Under these circumstances, the compiler, obviously, is free to use absolutely any memory layout for local variables inside that block. If can put them there so that the addresses increase in the order of declaration. Or decrease. Or arranged randomly. It is an implementation detail. And there's not much logic behind it.
It is quite possible that in your case the compiler tried to "pretend" that the memory for the arrays was allocated in the stack sequentially and independently (even though that was not the case). If on your platform stack grows downwards (as it does on many platforms), then it is expected that object declared later will have smaller addresses.
But again, functions don't allocate local objects individually. And on top of that the language makes no guarantees about any relationships between local object addresses. So, there's no real reason to prefer one ordering over the other.
The output of your C program is platform-dependent, compiler-dependent.
There cannot be just one perfect answer because the address arrangements vary based on:
Whether the system is little or big endian.
What kind of OS you are compiling on.
What kind of memory architecture you are compiling for.
What kind of compiler you are using(and compilers might have bugs too)
Whether you are on 64-bit or 32-bit platform.
And so much more.
But most important of all, is the type of processor architecture. :)
Here is a list of stack growth strategies per processor:
x86,PDP11 Downwards
System z In a linked list fashion, downwards, mostly.
ARM Select-able and can grow in either up or downward.
Mostek6502 Downwards (but only 256 bytes).
SPARC In a circular fashion with a sliding window, a limited depth stack.
RCA1802A Subject to SCRT(Standard Call and Return Technique) implementation.
But, in general, your compiler, at compile-time should map those addresses into the binary file generated. Then at the run-time, the binary file may occupy(or may pretend to occupy) a sequential set of memory addresses. And in your case the addresses printed by your C source, show that the stack is growing downward.
Basically compiler has responsibility to allocate memory to all the variables .
Array gets address on stack. but it has nothing to do with the o/p you are getting.
Basically The thing is compiler found the contiguous space(or chunk of memory) empty at that time and hence it allocated it to your program.

how to find if stack increases upwards or downwards?

how to find if stack increases upwards or downwards?
This is very platform-dependent, and even application-dependent.
The code posted by Vino only works in targets where parameters are passed on the stack AND local variables are allocated from the stack, in that order. Many compilers will assign fixed memory addresses to parameters, or pass parameters in registers. While common, passing parameters on the stack is one of the least efficient ways to get data into and out of a function.
Look at the disassembly for your compiled app and see what code the compiler is generating. If your target has native stack manipulation commands (like PUSH and POP) that the compiler is using, then the CPU datasheet/reference manual will tell you which direction the stack is growing. However, the compiler may choose to implement its own stack, in which case you'll have to do some digging.
Or, read the stack pointer, push something on the stack, and read the stack pointer again. Compare the results of the first and second read to determine the direction in which the pointer moves.
For future reference: if you include some details about your target architecture (embedded? PC? Linux, Windows? GCC? VC? Watcom? blah blah blah) you'll get more meaningful answers.
One possible way is...
#include <stdio.h>
void call(int *a)
{
int b;
if (&b > a)
printf("Stack grows up.\n");
else
printf("Stack grows down.\n");
}
int main ()
{
int a;
call(&a);
return 0;
}
Brute force approach is to fill your memory with a known value say 0xFF. Push some items on the stack. Do a memory dump. Push some more items on the stack. Do another memory dump.
Create function with many local variables.
Turn off optimizations.
Either print the assembly language..
Or when debugging, display as mixed source and assembly language.
Note the stack pointer (or register) before the function is executed.
Single-step through the function and watch the stack pointer.
In general, whether a compiler uses incrementing or decrementing stack pointers is a very minor issue as long as the issue is consistent and working. This is one issue that rarely occupies my mind. I tend to concentrate on more important topics, such as quality, correctness and robustness.
I'll trust the compiler to correctly handle stack manipulation. I don't trust recursive functions, especially on embedded or restricted platforms.

Resources