How to judge the growth direction of the stack.
For a man accustomed to the i386 series of machines, this seems like a boring problem, because the stack is growing from a high address to a low address. However, obviously this is not the purpose of the problem, since the problem is taken out, the question is not only the I386 series of machines, across the hardware platform is the first factor to consider the problem.
In an age of great material enrichment, unless there is no way back, we will not use the assembly to solve the problem, and for this system programming flavor problem, C is a good choice. The next question is how to use C to solve the problem.
Where does c use the stack? People who know a little about C will immediately give the answer, yes, function. We know that local variables are present in the stack. It seems that the question was immediately answered, with a function declaring two local variables and then comparing the addresses of two variables so that the answer can be obtained.
Wait a minute, how do you compare the addresses of two variables?
First to declare the first in the stack, so the address of its first variable, if it is high, is to grow from the top down. First-in-first stack declared. Where does this conclusion come from? This is how the general compiler handles it. If it's not normal. This seemingly correct approach is actually dependent on the compiler, so portability is challenged.
Then the function adds a parameter, compares the parameter and the local variable position, the parameter certainly first enters the stack. So why not local variables first into the stack. The first reaction is how possible, but there is nothing to think about. Therefore, this method also relies on the implementation of the compiler.
Then what is not dependent on the compiler?
Recall how the function is invoked. When a function is executed, information about the function appears in the stack, such as parameters, return addresses, and local variables. When it calls another function, the information that it calls that function is placed on the stack when its stack information remains unchanged.
Seems to have found something, yes, two functions of the relevant information location is fixed, it must be called first function its information first into the stack, and then call the function after its information into the stack. Then the answer to the question emerges.
For example, design two functions, one as the caller and the other as the callee. The callee takes an address (that is, a pointer) as its own entry parameter, the caller's incoming address is the address of one of its local variables, and then the caller compares the address with its own local variable address to determine the growth direction of the stack.
Given a solution, let's take a look back and see why the previous approach was a problem. Why a function cannot solve this problem. This probably explains the procedure of the function call, we mention that the information about the function is fed together into the stack, which includes parameters, return addresses, local variables, and so on, and in the terminology of the computer, there is a story called a stack frame, which refers to something that relates to a function call. The relative order of these things within a stack frame is determined by the compiler, so there is a dependency on the compiler to do comparisons only within a stack frame. As far as this problem is concerned, parameters and local variables, even return addresses, are the same because they are within the same stack frame and the comparisons between them do not solve the problem, and they are all relevant information about a function, so it is difficult to solve the problem with a function.
Well, now that you have this understanding, you can obviously expand the previous solution, you can compare the two stacks of anything, such as the respective entry parameters, can determine the growth direction of the stack.
Wild Fantasy, will not have the compiler each time to leave something special, and so the next function stack frame into the stack, in the left of the things into the stack. That's a good way to break it. If any one knows such a magical compiler, may as well tell me. We can draw the author of it and beat it to death.
#include <stdio.h>
void func1 ();
void Func2 (int *a);
void Func1 ()
{
int a=0;
Func2 (&a);
}
void Func2 (int *a)
{
int b=0;
printf ("%x\n%x\n", a,&b);
}
int main ()
{
func1 ();
}
Results:
29f6ac
29f5c8
Please press any key to continue ...
You can see the,a>b; indicating the growth direction upward. The growth direction of the stack in the computer grows from the high address to the low address direction.
Why the stack is growing downward.
"This problem is related to the allocation rules for virtual address spaces, each executable C program, from the low address to the high address sequence is: TEXT,DATA,BSS, heap, stack, environment parameter variables; The heap and stack have a large address space idle, in the need to allocate space, heap to rise, stack down. ”
This design allows the heap and stack to take full advantage of the free address space. if the stack goes up, we have to specify a strict dividing line between the stack and the heap, but how is the demarcation line determined? Average score. But some programs use more heap space, and some programs use more stack space. So this can happen: A program crashes because of stack overflow, in fact it has a lot of idle heap space, but we can not use these idle heap space. So, the best way to do this is to get the heap and stack to go up and down, so that they can share the rest of the address space to the maximum extent of utilization.
Oh, in fact, when you understand this principle, you will not be surprised by the design of the computer scientists of the amazing intelligence and wisdom.
(The stack direction is the opposite of the minimum condition that occurs, the stack overlaps).
Why do you want to separate the heap from the stack?
Why should the heap and stack distinguish between. Is it possible to store data in stacks?
First, from the point of view of software design, the stack represents the processing logic, and the heap represents the data.
This separation makes the processing logic clearer. The thought of divide and conquer. The idea of isolation and modularity is embodied in all aspects of software design.
Second, heap and stack separation, so that the contents of the heap can be shared by multiple stacks (also can be understood as multiple threads to access the same object). The benefits of this sharing are many. On the one hand, this sharing provides an effective means of data interaction (e.g. shared memory), on the other hand, shared constants and caches in the heap can be accessed by all stacks, saving space.
Third, the stack because of the needs of the runtime, such as saving the context of the system operation, the need for the division of the address section. Because stacks can only grow upwards, they limit the ability of the stack to store content. In the heap, the objects in the heap can grow dynamically as needed, so the stack and heap splits make the dynamic growth possible, and only one address in the stack should be recorded in the corresponding stacks.
The object-oriented is the perfect combination of heap and stack. In fact, there is no difference in execution between object-oriented programs and previously structured programs. However, the introduction of object-oriented, so that the way of thinking about the problem has changed, and more close to the natural way of thinking. When we take the object apart, you will find that the object's attributes are actually data, stored in the heap, and the object's behavior (method) is to run the logic and put it on the stack. When we write the object, we actually write the data structure and the logic of processing it. I have to admit, the object-oriented design is really beautiful.
Recursive overflow Reason:
1. The recursion level is too deep.
2. Artificial
#include
int main ()
{
char name[8];
printf ("Please type your name:");
Gets (name);
printf ("Hello,%s!", name);
return 0;
}
Stack Overflow
Now we do it again, enter IPXODIAAAAAAAAAAAAAAA, after executing gets (name), because the name string we entered is too long to fit in the name array, we have to continue writing ' A ' to the top of the memory. Because the stack's growth direction is opposite to the memory's growth direction, these ' A ' cover the old elements of the stack. We can see that the Ebp,ret have been covered by ' a '. When main returns, the ' AAAA ' ASCII code: 0x41414141 is used as the return address, and the CPU attempts to execute the instructions at 0x41414141, resulting in an error. This is a stack overflow.
3. How to use Stack Overflow
We have created a stack overflow. The principle can be summed up as follows: since string processing functions (gets,strcpy, etc.) are not monitored and restricted by arrays, we can modify the return address by using a character array to write out of bounds, overwriting the values of the old elements in the stack. (MORE: http://security.ctocio.com.cn/tips/485/7723985.shtml).
What is the difference between a heap (heap) and a stack (stack)?
The simple can be understood as:
Heap: Is the location of the space allocated by functions such as malloc. The address is increased from low to high.
Stack: Is the automatic allocation of variables, as well as the use of some space when the function calls. The address is reduced from high to low.
Preliminary knowledge-memory allocation for programs
The memory used by a program compiled by C + + is divided into the following sections
1, stack area (stack)-by the compiler automatically assigned to release, store the function of the parameter values, local variables and other values. The operation is similar to the stack in the data structure.
2, heap area (heap)-Generally by the programmer assigned to release, if the programmer does not release, the program at the end may be reclaimed by the OS. Note that it is different from the heap in the data structure, the distribution is similar to the list, hehe.
3, Global area (static)--------------------------------------------------------------- -System release after the program is finished
4, literal constant area-the constant string is here. Released by system after program is finished
5, program code area-the binary code that holds the function body.
Second, the example procedure
This is written by a predecessor, very detailed
Main.cpp
int a = 0; Global initialization Area
Char *p1; Global uninitialized Zone
Main ()
{
int b; Stack
Char s[] = "ABC"; Stack
Char *p2; Stack
Char *p3 = "123456"; 123456 in the constant area, p3 on the stack.
static int c = 0; global (static) initialization area
P1 = (char *) malloc (10);
P2 = (char *) malloc (20);
Areas that are allocated 10 and 20 bytes are in the heap area.
strcpy (P1, "123456"); 123456 is placed in the constant area, the compiler may optimize it to a place with the "123456" that P3 points to.
}
Theory knowledge of heap and stack
2.1 Application Methods
Stack
Automatically assigned by the system. For example, declare a local variable int b in a function; The system automatically opens up space for B in the stack
Heap
Requires programmers to apply themselves, and indicate size, in C malloc function
such as P1 = (char *) malloc (10);
Using the new operator in C + +
such as P2 = (char *) malloc (10);
But note that P1, p2 itself is in the stack.
2.2
Response of System after application
Stack: As long as the remaining space of the stack is larger than the application space, the system will provide memory for the program, otherwise it will be reported abnormal stack overflow.
Heap: First you should know that the operating system has a record of the free memory address of the list, when the system received the application of the program,
Will traverse the list to find the first heap node that is larger than the requested space, the node is then removed from the list of free nodes, and the space of the node is allocated to the program, and for most systems, the size of this assignment is recorded at the first address in the memory space, so that The DELETE statement in your code can properly free this memory space. In addition, because the size of the found heap node does not necessarily equal the size of the application, the system automatically puts the extra part back into the free list.
2.3 Limit of application size
Stacks: In Windows, stacks are data structures that extend to a low address and are a contiguous area of memory. The address of the top of the stack and the maximum capacity of the stack are predetermined by the system, in Windows, the size of the stack is 2M (also some say 1M, in short, a compile-time constant), if the application space over the stack of remaining space, will prompt overflow. Therefore, the space can be obtained from the stack is small.
Heap: The heap is a data structure that is extended to a high address and is a contiguous area of memory. This is because the system is used to store the free memory address of the list, nature is discontinuous, and the link list of the traversal direction is from the low address to the high address. The size of the heap is limited by the virtual memory available in the computer system. This shows that the heap to obtain a more flexible space, but also relatively large.
2.4 Comparison of the efficiency of the application:
The stack is automatically allocated by the system, faster. But programmers are out of control.
A heap is a memory that is allocated by new, typically slower, and prone to memory fragmentation, but is most convenient to use.
In addition, in Windows, the best way is to allocate memory with VirtualAlloc, he is not in the heap, nor in the stack is directly in the process of the address space to keep a fast memory, although the most inconvenient to use. But speed, and most flexible.
2.5 stacks and stacks of stored content
Stacks: When a function is called, the first stack is the address of the next instruction in the main function (the next executable statement of the function call statement). Then there are the parameters of the function, in most C compilers, the parameters are pushed from right to left, and then the local variables in the function. Note that static variables are not in the stack.
When the function call is finished, the local variable first goes out of the stack, then the argument, and the last stack pointer points to the address that was first saved, the next instruction in the main function, where the program continues to run.
Heap: The size of the heap is usually stored in a byte at the head of the heap. The specifics of the heap are arranged by the programmer.
2.6 Comparison of access efficiency
Char s1[] = "AAAAAAAAAAAAAAA";
Char *s2 = "BBBBBBBBBBBBBBBBB";
The AAAAAAAAAAA is assigned at run time;
And the BBBBBBBBBBB is determined at compile time;
However, in future accesses, the array on the stack is faster than the string that the pointer points to (for example, a heap).
Like what:
#include
void Main ()
{
char a = 1;
Char c[] = "1234567890";
Char *p = "1234567890";
A = c[1];
A = p[1];
Return
}
The corresponding assembly code
10:a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0fh]
0040106A 4D FC mov byte ptr [ebp-4],cl
11:a = p[1];
0040106D 8B EC mov edx,dword ptr [ebp-14h]
00401070 8A mov al,byte ptr [edx+1]
00401073 FC mov-byte ptr [ebp-4],al
The first reads the elements in the string directly into the register CL, while the second type refers to the edx, which reads the characters according to the edx, which is obviously slow.