Hello World
When a program is executed it is loaded into its virtual memory space. The compiled machine code instructions are loaded into the text segment, which is placed at the bottom of memory, i.e., from 0x0000 0000 upward; and any static data is placed in the data segment, which is located just after it.
In contrast, runtime information, such as the parameters and environment variables are placed at the top of memory, i.e., from 0xFFFF FFFC downward; and the stack is then initialised just below this (and grows downward in memory).
This example does not discuss the dynamic heap which is initialised just after the data segment, and which grows upward in memory toward the heap.
Remember, how a program is stored in memory will differ depending on the machine architecture, operating system, programming language, and compiler used. Also this is a simplified example.
Table 1. shows the contents of the memory after the program below (hello.c) has run. The representation of memory in Table 1 shows the data segment, which is contained within the memory addresses between 0x0000 10000 and 0x0000 1036; and the stack segment, which is shown contained within the memory addresses 0xFFFF FFDC and 0xFFFF FFFFC.
Table 1. - Memory content after execution. | ||||
# | Label | Memory Address | Binary value stored at address | Interpretation |
---|---|---|---|---|
# | 0x0000 0000 | 0000 0000 0000 0000 0000 0000 0000 0000 | ... | |
# | ... | ... | Text Segment | |
# | 0x0001 0000 | 0000 0000 0000 0000 0000 0000 0000 0000 | ... | |
# | 0x0001 0004 | 0010 0101 0111 0011 0000 1010 0000 0000 | 0x2573 0A00 "%s\n\0" | |
# | 0x0001 0008 | 0000 0000 0000 0000 0000 0000 0000 0000 | 0x0000 0000 | |
# | ... | ... | ||
# | va0: | 0xFFFE FFDC | 0010 1110 0100 0111 0110 1000 0110 0101 | 0xFFFF FFE0 |
# | format: | 0xFFFE FFE0 | 0000 0000 0000 0000 0000 0001 0000 0100 | 0x0001 0004 |
# | ret: | 0xFFFE FFE4 | 0000 0000 0000 0000 0000 0000 0000 1011 | 0xB = 11 |
# | 0xFFFE FFE8 | 0000 0000 0000 0000 0000 0000 ???? ???? | Return address | |
# | length: | 0xFFFE FFEC | 0000 0000 0000 0000 0000 0000 0000 1011 | 0xB = 11 |
# | argv: | 0xFFFE FFF0 | 1111 1111 1111 1111 1111 1111 1110 0000 | 0xFFFF FFF4 |
# | argc: | 0xFFFE FFF4 | 0000 0000 0000 0000 0000 0000 0000 0010 | 0x0002 |
# | ret: | 0xFFFE FFF8 | 0000 0000 0000 0000 0000 0000 0000 1011 | 0xB = 11 |
# | 0xFFFE FFFC | 0000 0000 0000 0000 0000 0000 ???? ???? | Return address | |
# | ... | ... | ||
# | *argv[0] | 0xFFFF FFE0 | 0010 1110 0100 0111 0110 1000 0110 0101 | 0x2E47 6865 "./he" |
# | 0xFFFF FFE4 | 0110 1100 1100 0110 0110 FFFF 0000 0000 | 0x6C6C 6F00 "llo\0" | |
# | *argv[1] | 0xFFFF FFE8 | 0010 1000 0110 0101 0110 1100 0110 1100 | 0x4865 6C6C "Hell" |
# | 0xFFFF FFEC | 0110 1111 0111 1111 0101 0111 0110 1111 | 0x6F7F 576F "o Wo" | |
# | 0xFFFF FFF0 | 0111 0010 0110 1100 0110 0100 0000 0000 | 0x726C 6400 "rld\0" | |
# | argv[0] | 0xFFFF FFF4 | 1111 1111 1111 1111 1111 1111 1110 0000 | 0xFFFF FFE0 |
# | argv[1] | 0xFFFF FFF8 | 1111 1111 1111 1111 1111 1111 1110 0008 | 0xFFFF FFE8 |
# | 0xFFFF FFFC | 0000 0000 0000 0000 0000 0000 0000 0000 | 0x0000 0000 |
The stack segment contains two stack frames: the first was created when the function 'main' was called and is composed of a return address (for execution to jump back to), the return value, and the two parameters argc and argv that are passed to main. the second was created when the function 'printf' was called and is composed of a return address, the return value, and the two parameters that are passed to printf.
Note, it is likely that printf would have also called functions that would have created stack frames, but, as they are beyond the scope of this example, I will not attempt to show them.
$ ./hello "Hello world"
hello.c
int main( int argc, char** argv ) { int length = 99; length = printf( "%s\n", argv[0] ); return length; }
References