2.3 Layout of a Program Image

Team-FLY

After loading, the program executable appears to occupy a contiguous block of memory called a program image . Figure 2.1 shows a sample layout of a program image in its logical address space [112]. The program image has several distinct sections. The program text or code is shown in low-order memory. The initialized and uninitialized static variables have their own sections in the image. Other sections include the heap, stack and environment.

Figure 2.1. Sample layout for a program image in main memory.

graphics/02fig01.gif

An activation record is a block of memory allocated on the top of the process stack to hold the execution context of a function during a call. Each function call creates a new activation record on the stack. The activation record is removed from the stack when the function returns, providing the last-called-first-returned order for nested function calls.

The activation record contains the return address, the parameters (whose values are copied from the corresponding arguments), status information and a copy of some of the CPU register values at the time of the call. The process restores the register values on return from the call represented by the record. The activation record also contains automatic variables that are allocated within the function while it is executing. The particular format for an activation record depends on the hardware and on the programming language.

In addition to the static and automatic variables, the program image contains space for argc and argv and for allocations by malloc . The malloc family of functions allocates storage from a free memory pool called the heap . Storage allocated on the heap persists until it is freed or until the program exits. If a function calls malloc , the storage remains allocated after the function returns. The program cannot access the storage after the return unless it has a pointer to the storage that is accessible after the function returns.

Static variables that are not explicitly initialized in their declarations are initialized to 0 at run time. Notice that the initialized static variables and the uninitialized static variables occupy different sections in the program image. Typically, the initialized static variables are part of the executable module on disk, but the uninitialized static variables are not. Of course, the automatic variables are not part of the executable module because they are only allocated when their defining block is called. The initial values of automatic variables are undetermined unless the program explicitly initializes them.

Exercise 2.3

Use ls -l to compare the sizes of the executable modules for the following two C programs. Explain the results.

Version 1: largearrayinit.c

 int myarray[50000] = {1, 2, 3, 4}; int main(void) {    myarray[0] = 3;    return 0; } 

Version 2: largearray.c

 int myarray[50000]; int main(void) {     myarray[0] = 3;     return 0; } 

Answer:

The executable module for Version 1 should be about 200,000 bytes larger than that of Version 2 because the myarray of Version 1 is initialized static data and is therefore part of the executable module. The myarray of Version 2 is not allocated until the program is loaded in memory, and the array elements are initialized to 0 at that time.

Static variables can make a program unsafe for threaded execution. For example, the C library function readdir and its relatives described in Section 5.2 use static variables to hold return values. The function strtok discussed in Section 2.6 uses a static variable to keep track of its progress between calls. Neither of these functions can be safely called by multiple threads within a program. In other words, they are not thread-safe . External static variables also make code more difficult to debug because successive invocations of a function that references a static variable may behave in unexpected ways. For these reasons, avoid using static variables except under controlled circumstances . Section 2.9 presents an example of when to use variables with static storage class.

Although the program image appears to occupy a contiguous block of memory, in practice, the operating system maps the program image into noncontiguous blocks of physical memory. A common mapping divides the program image into equal- sized pieces, called pages . The operating system loads the individual pages into memory and looks up the location of the page in a table when the processor references memory on that page. This mapping allows a large logical address space for the stack and heap without actually using physical memory unless it is needed. The operating system hides the existence of such an underlying mapping, so the programmer can view the program image as logically contiguous even when some of the pages do not actually reside in memory.

Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net