简体   繁体   中英

Stack: low memory vs high memory address actual location?

I've been reading about stack and memory address location in a few tutorials and wondering why their reference of low and high memory location are different?

This is confusing.

Eg

Low Memory Address located at the top while High Memory Address at the bottom 在此处输入图片说明

Low Memory Address located at the bottom while High Memory Address at the top 在此处输入图片说明

When I try it with a simple C program, it seems like Low Memory Address is located on the top. From bfbf7498 > bfbf749c > bfbf74a0 > bfbf74a4 > bfbf74a8 > bfbf74ac

user@linux:~$ cat > stack.c                     
#include <stdio.h>

int main()
{
        int A = 3;
        int B = 5;
        int C = 8;
        int D = 10;
        int E = 11;
        int F;
        F = B + D;

        printf("+-----------+-----+-----+-----+\n");
        printf("| Address   | Var | Dec | Hex |\n");
        printf("|-----------+-----+-----+-----|\n");
        printf("| %x  | F         | %d  | %X   |\n",&F,F,F);
        printf("| %x  | E         | %d  | %X   |\n",&E,E,E);
        printf("| %x  | D         | %d  | %X   |\n",&D,D,D);
        printf("| %x  | C         | 0%d  | %X   |\n",&C,C,C);
        printf("| %x  | B         | 0%d  | %X   |\n",&B,B,B);
        printf("| %x  | A         | 0%d  | %X   |\n",&A,A,A);
        printf("+-----------+-----+-----+-----+\n");
}
user@linux:~$ 

user@linux:~$ gcc -g stack.c -o stack ; ./stack 
+-----------+-----+-----+-----+
| Address   | Var | Dec | Hex |
|-----------+-----+-----+-----|
| bfbf7498  | F   | 15  | F   |
| bfbf749c  | E   | 11  | B   |
| bfbf74a0  | D   | 10  | A   |
| bfbf74a4  | C   | 08  | 8   |
| bfbf74a8  | B   | 05  | 5   |
| bfbf74ac  | A   | 03  | 3   |
+-----------+-----+-----+-----+
user@linux:~$ 

Why does the stack address grow towards decreasing memory addresses?

This thread has a pretty good answer to your question. It also has a pretty good visual.

https://unix.stackexchange.com/questions/4929/what-are-high-memory-and-low-memory-on-linux?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa

This is also a pretty good explanation (but related specifically to unix/linux)

Essentially it is totally dependent on the platform though

Explanation of why some stack memories grow differently:

There are a number of different methods used, depending on the OS (linux realtime vs. normal) and the language runtime system underneath:

1) dynamic, by page fault

typically preallocate a few real pages to higher addresses and assign the initial sp to that. The stack grows downward, the heap grows upward. If a page fault happens somewhat below the stack bottom, the missing intermediate pages are allocated and mapped. Effectively increasing the stack from the top towards the bottom automatically. There is typically a maximum up to which such automatic allocation is performed, which can or can not be specified in the environment (ulimit), exe-header, or dynamically adjusted by the program via a system call (rlimit). Especially this adjustability varies heavily between different OSes. There is also typically a limit to "how far away" from the stack bottom a page fault is considered to be ok and an automatic grow to happen. Notice that not all systems' stack grows downward: under HPUX it (used?) to grow upward so I am not sure what a linux on the PA-Risc does (can someone comment on this).

2) fixed size

other OSes (and especially in embedded and mobile environments) either have fixed sizes by definition, or specified in the exe header, or specified when a program/thread is created. Especially in embedded real time controllers, this is often a configuration parameter, and individual control tasks get fix stacks (to avoid runaway threads taking the memory of higher prio control tasks). Of course also in this case, the memory might be allocated only virtually, untill really needed.

3) pagewise, spaghetti and similar

such mechanisms tend to be forgotten, but are still in use in some run time systems (I know of Lisp/Scheme and Smalltalk systems). These allocate and increase the stack dynamically as-required. However, not as a single contigious segment, but instead as a linked chain of multi-page chunks. It requires different function entry/exit code to be generated by the compiler(s), in order to handle segment boundaries. Therefore such schemes are typically implemented by a language support system and not the OS itself (used to be earlier times - sigh). The reason is that when you have many (say 1000s of) threads in an interactive environment, preallocating say 1Mb would simply fill your virtual address space and you could not support a system where the thread needs of an individual thread is unknown before (which is typically the case in a dynamic environment, where the use might enter eval-code into a separate workspace). So dynamic allocation as in scheme 1 above is not possible, because there are would be other threads with their own stacks in the way. The stack is made up of smaller segments (say 8-64k) which are allocated and deallocated from a pool and linked into a chain of stack segments. Such a scheme may also be requried for high performance support of things like continuations, coroutines etc.

Modern unixes/linuxes and (I guess, but not 100% certain) windows use scheme 1) for the main thread of your exe, and 2) for additional (p-)threads, which need a fix stack size given by the thread creator initially. Most embedded systems and controllers use fixed (but configurable) preallocation (even physically preallocated in many cases).

Sorry if this answer is a bit dense, I'm not sure to simply it and still give a valid explanation. As for why the example you gave in C has Low Memory Address located on the top, the simplest way of explaining it is that C was built like that.

It isn't exactly clear what your question is. What Arjun was answering is why does stack memory grow down (decreading memory addresses) instead of up (increasing memory addresses) and the simple answer to this is it is arbitrary. It really doesn't matter, but an architecture has to choose one or the other - there are typically cpu instructions that manipulate the stack and they are expecting a particular implementation.

The other possible question you may be asking is related to visual references from multiple sources. In your example above, you have one diagram showing low addresses at the top and you have another showing low addresses at the bottom. They are both showing the stack growing down from larger addresses down to smaller addresses. Again this is arbitrary, the authors needed to choose one or the other and they are communicating to you their choice. If you want to compare them side by side you may want to flip one so they have similar orientations.

By the way, your example code is showing that the stack does indeed start from high addresses and grow down (the memory address of 'A' is allocated first and has a higher memory address than the others).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM