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