The system keeps track of the virtual addresses [5] associated with each user process segment. This address information is available to the process and can be obtained by referencing the external variables etext , edata , and end . The addresses (not the contents) of these three variables correspond respectively to the first valid address above the text, initialized data, and uninitialized data segments. Program 1.3 shows how this information can be obtained and displayed.
[5] Logical addressescalculated and used without concern as to their actual physical location.
Program 1.3 Displaying segment address information.
File : p1.3.cxx /* Displaying process segment addresses */ #include + extern int etext, edata, end; using namespace std; int main( ){ cout << "Adr etext: " << hex << int(&etext) << " "; 10 cout << "Adr edata: " << hex << int(&edata) << " "; cout << "Adr end: " << hex << int(&end ) << " "; return 0; }
If we add a few lines of code to our original Program 1.1, we can verify the virtual address location of key identifiers in our program. Program 1.4 incorporates an inline function, SHW_ADR( ) , to display the address of an identifier.
Program 1.4 Confirming Program 1.1 address locations.
File : p1.4.cxx /* Program 1.1 modified to display identifier addresses */ #include + #include // needed for write #include // needed for strcpy #include // needed for exit using namespace std; char *cptr = "Hello World "; // static by placement 10 char buffer1[25]; inline void SHW_ADR(char *ID, int address){ cout << "The id " << ID << " is at : " << hex << address << endl; + } extern int etext, edata, end; int main( ){ void showit(char *); // function prototype 20 int i = 0; // automatic variable // display addresses cout << "Adr etext: " << hex << int(&etext) << " "; cout << "Adr edata: " << hex << int(&edata) << " "; cout << "Adr end: " << hex << int(&end ) << " "; + SHW_ADR("main", int(main)); // function addresses SHW_ADR("showit", int(showit)); SHW_ADR("cptr", int(&cptr)); // static SHW_ADR("buffer1", int(&buffer1)); SHW_ADR("i", int(&i)); // automatic 30 strcpy(buffer1, "A demonstration "); // library function write(1, buffer1, strlen(buffer1)+1); // system call showit(cptr); // function call return 0; + } void showit( char *p ){ char *buffer2; SHW_ADR("buffer2", int(&buffer2)); // display address 40 if ((buffer2= new char[ strlen(p)+1 ]) != NULL){ strcpy(buffer2, p); // copy the string cout << buffer2; // display string delete [] buffer2; // release location } else { + cerr << "Allocation error. "; exit(1); } }
A run of this program produces output (Figure 1.10) that verifies our assertions concerning the range of addresses for identifiers of different storage types. Note the actual addresses displayed by the program are system-dependent. Note that the command-line nm utility program can also be used verify the addresses displayed by Program 1.4.
Figure 1.10 Output of Program 1.4.
Adr etext: 8048bca Adr edata: 8049e18 Adr end: 8049ea8 The id main is at : 8048890 The id showit is at : 8048a44 The id cptr is at : 8049c74 The id buffer1 is at : 8049e8c The id i is at : bffffc54 A demonstration The id buffer2 is at : bffffc34 Hello World
The output of Program 1.4 is presented pictorially in Figure 1.11.
Figure 1.11. Address locations in Program 1.4.
For those with a further interest in this topic, many versions of Linux have an objdump utility that provides additional information for a specified object file.
EXERCISEWhen in the Bourne shell, investigate the commands ulimit -a and size . How does the information these commands report relate to the values of etext , edata , and end ? |
Programs and Processes
Processing Environment
Using Processes
Primitive Communications
Pipes
Message Queues
Semaphores
Shared Memory
Remote Procedure Calls
Sockets
Threads
Appendix A. Using Linux Manual Pages
Appendix B. UNIX Error Messages
Appendix C. RPC Syntax Diagrams
Appendix D. Profiling Programs