At university, we learn about Memory Layout in C. Concepts such as Heap memory, Stack memory, BSS, etc. Whenever we discuss this type of allocation, we often see images like this:
Memory Layout of C Program - Source
But then some questions arise on this topic. The main question is: do we have a clear view of how this is done at a logical and physical level?
Since we're talking about allocation layout, what other models exist? What is really stored in the heap and stack? Can we do this in a virtual lab and explore it? What are the limits?
This repository will serve as the results of these investigations.
To begin with, my first question was:
So who implements the stack, heap, bss, etc.?
While reading the OS book [1], a passage mentioned:
'In virtual memory, when a process starts, the operating system allocates memory blocks at least for the code, data, and stack, which are released when the process ends. In real memory with variable partitions, something similar happens; when you want to start running a program, it's necessary to allocate memory for the new partition, which is released when the program ends.'
We can then imagine that as soon as a process starts, we see this image:
The stack pointer was chosen to run "downhill" (with the stack advancing toward lower memory) to simplify indexing into the stack from the user's program (positive indexing) and to simplify displaying the contents of the stack from a front panel.
Reference: https://tcm.computerhistory.org/ComputerTimeline/Chap37_intel_CS2.pdf
Read arrow_down.s, you will see that what i presented a very simplified process, but by reading it line by line, you'll be able to understand it better than just looking at the output in C.
I didn't include the system call to print the allocated addresses (it will increase the code and operations), but you can see how and why the allocation will grows down.
gcc -o output_arrow_down arrow_down.c
➜ stack_arrow_down git:(main) ✗ gcc -o output_arrow_down arrow_down.c
➜ stack_arrow_down git:(main) ✗ ./output_arrow_down
Endereco de main_local em main: 0x16b772738
Endereco de local2 em function2: 0x16b77270c
Endereco de local3 em function3: 0x16b77270c
Endereco de local1 em function1: 0x16b7726ecgcc -S -o output.s arrow_down.c gcc -c -o output.o output.s gcc -o output output.o ./output
➜ stack_arrow_down git:(main) ✗ gcc -o stack_grows_down stack_grows_down.c
➜ stack_arrow_down git:(main) ✗ gcc -S -o output.s arrow_down.c
➜ stack_arrow_down git:(main) ✗ gcc -c -o output.o output.s
➜ stack_arrow_down git:(main) ✗ gcc -o output output.o
➜ stack_arrow_down git:(main) ✗ ./output
Endereco de main_local em main: 0x16fbbe758 --> top of stack
Endereco de local2 em function2: 0x16fbbe72c
Endereco de local3 em function3: 0x16fbbe72c
Endereco de local1 em function1: 0x16fbbe70cif you want to know why we have pages and offset in allocation, see Virtual Memory Allocation And Paging
1 - Operating Systems by José Alves Marques | Paulo Ferreira | Carlos Ribeiro | Luís Veiga | Rodrigo Rodrigues
