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 00000000 0000 0000 0000 0000 0000 0000 0000...
# ... ... Text Segment
# 0x0001 00000000 0000 0000 0000 0000 0000 0000 0000...
# 0x0001 00040010 0101 0111 0011 0000 1010 0000 00000x2573 0A00 "%s\n\0"
# 0x0001 00080000 0000 0000 0000 0000 0000 0000 00000x0000 0000
# ... ...
#va0: 0xFFFE FFDC0010 1110 0100 0111 0110 1000 0110 01010xFFFF FFE0
#format: 0xFFFE FFE00000 0000 0000 0000 0000 0001 0000 01000x0001 0004
#ret: 0xFFFE FFE40000 0000 0000 0000 0000 0000 0000 10110xB = 11
# 0xFFFE FFE80000 0000 0000 0000 0000 0000 ???? ????Return address
#length: 0xFFFE FFEC0000 0000 0000 0000 0000 0000 0000 10110xB = 11
#argv: 0xFFFE FFF01111 1111 1111 1111 1111 1111 1110 00000xFFFF FFF4
#argc: 0xFFFE FFF40000 0000 0000 0000 0000 0000 0000 00100x0002
#ret: 0xFFFE FFF80000 0000 0000 0000 0000 0000 0000 10110xB = 11
# 0xFFFE FFFC0000 0000 0000 0000 0000 0000 ???? ????Return address
# ... ...
#*argv[0] 0xFFFF FFE00010 1110 0100 0111 0110 1000 0110 01010x2E47 6865 "./he"
# 0xFFFF FFE40110 1100 1100 0110 0110 FFFF 0000 00000x6C6C 6F00 "llo\0"
#*argv[1] 0xFFFF FFE80010 1000 0110 0101 0110 1100 0110 11000x4865 6C6C "Hell"
# 0xFFFF FFEC0110 1111 0111 1111 0101 0111 0110 11110x6F7F 576F "o Wo"
# 0xFFFF FFF00111 0010 0110 1100 0110 0100 0000 00000x726C 6400 "rld\0"
#argv[0] 0xFFFF FFF41111 1111 1111 1111 1111 1111 1110 00000xFFFF FFE0
#argv[1] 0xFFFF FFF81111 1111 1111 1111 1111 1111 1110 00080xFFFF FFE8
# 0xFFFF FFFC0000 0000 0000 0000 0000 0000 0000 00000x0000 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