Showing posts with label Unix System Programming (C Python). Show all posts
Showing posts with label Unix System Programming (C Python). Show all posts

Memcache and Binary Protocol

A very good Memcache Story explains memcache basic.

Article about binary protocol.

Unix Files and Directories

Key Concepts:

A filesystem normally has boot block, super block, i-node list, directory and data blocks.

The i-node contains all the information about the file: the file type, the file's access permission bits, the size of the file, pointers to the data blocks for the file, and so on. Most of the information in the stat structure is obtained from the i-node. Only two items are stored in the directory entry: the filename and the i-node number.

When renaming a file without changing filesystems, the actual content of the file need not be moved - all that needs to be done is to have a new directory entry point to the existing i-node and have the old directory entry removed.

Since the i-node number in the directory entry points to an i-node in the same filesystem, we cannot have a directory entry pint to an-inode in a different filesystem. This is why hardlink can't cross filesystems.

With a symbolic link, the actual contents of the file (the data blocks) contains the name of the file that the symbolic link points to.

Each i-node has a link count that contains the number of directory entries that point to the i-node. When the link count goes to 0 can the file be deleted. This is why "unlinking a file" does not always mean "deleting the blocks associated with the file." They is why the function that removes a directory is called unlink and not delete.

Any leaf directory always has a link count of 2. The value of 2 is from the directory entry that names the directory and from the entry for dot in that directory. What about the / filesystem's link count? Are the . and .. pointing to the same place or different ones?

Every directory in the working directory causes the working directory's link count to be increased by 1. (the .. entry of the new subdirectory)

Only a superuser process can create a new link that points to a directory. The reason is that doing this can cause loops in the filesystem.

When a file is closed the kernel first checks the count of the number of processes that have the file open. If this count has reached 0 then the kernel checks the link count, and if it is 0, the file's contents are deleted.

A directory is just a file containing directory entries(filenames and associate i-node numbers). Adding, deleting, or modifying these directory entries can affect all three times associated with that directory. With permissions, we can create new files in the direcotry and remove files from it, but we can't write to the directory itself. Only the kernel can write to a directory.



R
eferences:

Unix UFS i-node Structure is explained at this site.

A very good lecture note about file system is at here.

A very good brief introduction of Unix filesystems and Linux extfs and ext2fs is at : http://web.mit.edu/tytso/www/linux/ext2intro.html

For a complete description of Unix Files and Directories, please read Richard Stevens' Advanced Programming in the UNIX Environment.





stat man page.
http://www.manpages.info/linux/stat.2.html


They all return a stat structure, which contains the following fields:

struct stat {
dev_t st_dev; /* device */
ino_t st_ino; /* inode */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device type (if inode device) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last change */
};

The value st_size gives the size of the file (if it is a regular file
or a symlink) in bytes. The size of a symlink is the length of the
pathname it contains, without trailing NUL.

The value st_blocks gives the size of the file in 512-byte blocks.
(This may be smaller than st_size/512 e.g. when the file has holes.)
The value st_blksize gives the "preferred" blocksize for efficient file
system I/O. (Writing to a file in smaller chunks may cause an ineffi-
cient read-modify-rewrite.)

Not all of the Linux filesystems implement all of the time fields.
Some file system types allow mounting in such a way that file accesses
do not cause an update of the st_atime field. (See `noatime' in
mount(8).)

The field st_atime is changed by file accesses, e.g. by execve(2),
mknod(2), pipe(2), utime(2) and read(2) (of more than zero bytes).
Other routines, like mmap(2), may or may not update st_atime.

The field st_mtime is changed by file modifications, e.g. by mknod(2),
truncate(2), utime(2) and write(2) (of more than zero bytes). More-
over, st_mtime of a directory is changed by the creation or deletion of
files in that directory. The st_mtime field is not changed for changes
in owner, group, hard link count, or mode.

The field st_ctime is changed by writing or by setting inode informa-
tion (i.e., owner, group, link count, mode, etc.).



Sample code:

/* statinfo.c - demonstrates using stat() to obtain
* file information.
* - some members are just numbers...
*/
#include
#include
#include

void show_stat_info(char *, struct stat *);

int main(int ac, char *av[])
{
struct stat info; /* buffer for file info */

if (ac>1)
if( stat(av[1], &info) != -1 ){
show_stat_info( av[1], &info );
return 0;
}
else
perror(av[1]); /* report stat() errors */
return 1;
}
void show_stat_info(char *fname, struct stat *buf)
/*
* displays some info from stat in a name=value format
*/
{
printf(" inode: %o\n", buf->st_ino); /* inode */
printf(" mode: %o\n", buf->st_mode); /* type + mode */
printf(" links: %d\n", buf->st_nlink); /* # links */
printf(" user: %d\n", buf->st_uid); /* user id */
printf(" group: %d\n", buf->st_gid); /* group id */
printf(" size: %d\n", buf->st_size); /* file size */
printf("modtime: %d\n", buf->st_mtime); /* modified */
printf(" name: %s\n", fname ); /* filename */
}

Execution:

[root@ipc4 filesystems]# ./fileinfo /etc/passwd
mode: 100644
links: 1
user: 0
group: 0
size: 1888
modtime: 1256242470
name: /etc/passwd

-rw-r--r-- 1 root root 1888 Oct 22 13:14 /etc/passwd


stat -> st_mode tells us inode's type, suid,sgid,sticky, ugo permissions.
The mode (100644) or -rw-r--r-- is the value of st_mode (type+mode), the type is 1000 and
the (unix file access) mode is 644.

It's binary and its bit break down are defined as below:

1000 644 => 1000 0 0 0 110 110 100
type suid sgid sticky u(rw-) group(r--) other(r--)

For type's value, it's defined as follow in

S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 fifo

About file's a_time, c_time, m_time

The field st_atime is changed by file accesses, e.g. by execve(2),
mknod(2), pipe(2), utime(2) and read(2) (of more than zero bytes).
Other routines, like mmap(2), may or may not update st_atime.

The field st_mtime is changed by file modifications, e.g. by mknod(2),
truncate(2), utime(2) and write(2) (of more than zero bytes). More-
over, st_mtime of a directory is changed by the creation or deletion
of files in that directory. The st_mtime field is not changed for
changes in owner, group, hard link count, or mode.

The field st_ctime is changed by writing or by setting inode informa-
tion (i.e., owner, group, link count, mode, etc.).

------------------------------------




A simple 'ls' command in C:

main( argc, *argv[] )
while ( -- argc )
do do_ls ( *argv )
done

do_ls (dir[])
opendir ( dir )
dostat (direntp->d_name);
closedir(dir);

dostat ( *filename)
stat (filename, &stat_info)
show_file_info (filename, & stat_info);

show_file_info ( *filename, stat_info)
mode_to_letters (stat_info->st_mode, modestr)
uid_to_name (stat_info->st_uid)
gid_to_name (stat_info->st_gid)
utilitiy_functions
uid_to_name,
gid_to_name,
mode_to_letters;



/* lss.c
* purpose list contents of directory or directories
* action if no args, use . else list files in args
* note uses stat and pwd.h and grp.h
* BUG: try lss /tmp
*/
#include
#include
#include
#include

void do_ls(char[]);
void dostat(char *);
void show_file_info( char *, struct stat *);
void mode_to_letters( int , char [] );
char *uid_to_name( uid_t );
char *gid_to_name( gid_t );

main(int ac, char *av[])
{
if ( ac == 1 )
do_ls( "." );
else
while ( --ac ){
printf("%s:\n", *++av );
do_ls( *av );
}
}

void do_ls( char dirname[] )
/*
* list files in directory called dirname
*/
{
DIR *dir_ptr; /* the directory */
struct dirent *direntp; /* each entry */

if ( ( dir_ptr = opendir( dirname ) ) == NULL )
fprintf(stderr,"ls1: cannot open %s\n", dirname);
else
{
while ( ( direntp = readdir( dir_ptr ) ) != NULL )
dostat( direntp->d_name );
closedir(dir_ptr);
}
}

void dostat( char *filename )
{
struct stat info;

if ( stat(filename, &info) == -1 ) /* cannot stat */
perror( filename ); /* say why */
else /* else show info */
show_file_info( filename, &info );
}

void show_file_info( char *filename, struct stat *info_p )
/*
* display the info about 'filename'. The info is stored in struct at *info_p
*/
{
char *uid_to_name(), *ctime(), *gid_to_name(), *filemode();
void mode_to_letters();
char modestr[11];

mode_to_letters( info_p->st_mode, modestr );

printf( "%s" , modestr );
printf( "%4d " , (int) info_p->st_nlink);
printf( "%-8s " , uid_to_name(info_p->st_uid) );
printf( "%-8s " , gid_to_name(info_p->st_gid) );
printf( "%8ld " , (long)info_p->st_size);
printf( "%.12s ", 4+ctime(&info_p->st_mtime));
printf( "%s\n" , filename );

}

/*
* utility functions
*/

/*
* This function takes a mode value and a char array
* and puts into the char array the file type and the
* nine letters that correspond to the bits in mode.
* NOTE: It does not code setuid, setgid, and sticky
* codes
*/
void mode_to_letters( int mode, char str[] )
{
strcpy( str, "----------" ); /* default=no perms */

if ( S_ISDIR(mode) ) str[0] = 'd'; /* directory? */
if ( S_ISCHR(mode) ) str[0] = 'c'; /* char devices */
if ( S_ISBLK(mode) ) str[0] = 'b'; /* block device */

if ( mode & S_IRUSR ) str[1] = 'r'; /* 3 bits for user */
if ( mode & S_IWUSR ) str[2] = 'w';
if ( mode & S_IXUSR ) str[3] = 'x';

if ( mode & S_IRGRP ) str[4] = 'r'; /* 3 bits for group */
if ( mode & S_IWGRP ) str[5] = 'w';
if ( mode & S_IXGRP ) str[6] = 'x';

if ( mode & S_IROTH ) str[7] = 'r'; /* 3 bits for other */
if ( mode & S_IWOTH ) str[8] = 'w';
if ( mode & S_IXOTH ) str[9] = 'x';
}

#include

char *uid_to_name( uid_t uid )
/*
* returns pointer to username associated with uid, uses getpw()
*/
{
struct passwd *getpwuid(), *pw_ptr;
static char numstr[10];

if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){
sprintf(numstr,"%d", uid);
return numstr;
}
else
return pw_ptr->pw_name ;
}

#include

char *gid_to_name( gid_t gid )
/*
* returns pointer to group number gid. used getgrgid(3)
*/
{
struct group *getgrgid(), *grp_ptr;
static char numstr[10];

if ( ( grp_ptr = getgrgid(gid) ) == NULL ){
sprintf(numstr,"%d", gid);
return numstr;
}
else
return grp_ptr->gr_name;
}

[root@ipc4 filesystems]# ./lss /home/shan/prog/unix .
/home/shan/prog/unix:
drwxr-xr-x 2 root root 4096 Oct 28 22:00 .
drwxr-xr-x 3 root root 4096 Oct 28 17:23 ..
filesystems: No such file or directory
.:
-rw-r--r-- 1 root root 3446 Oct 28 17:00 ls2.c
-rwxr-xr-x 1 root root 5382 Oct 28 19:09 fileinfo
-rw-r--r-- 1 root root 332 Oct 28 16:58 Makefile
-rwxr-xr-x 1 root root 7101 Oct 28 19:43 ls2
drwxr-xr-x 2 root root 4096 Oct 28 22:00 .
-rwxr-xr-x 1 root root 5075 Oct 28 17:00 filesize
drwxr-xr-x 3 root root 4096 Oct 28 17:23 ..
-rw-r--r-- 1 root root 322 Oct 28 16:58 filesize.c
-rw-r--r-- 1 root root 1216 Oct 28 19:09 fileinfo.c
-rw-r--r-- 1 root root 4467 Oct 28 19:12 fs.txt
-rw-r--r-- 1 root root 9524 Oct 28 19:04 stat.man
-rwxr-xr-x 1 root root 5382 Oct 28 19:09 f
-rw-r--r-- 1 root root 718 Oct 28 16:59 ls1.c
-rwxr-xr-x 1 root root 7101 Oct 28 22:00 lss
-rw-r--r-- 1 root root 3446 Oct 28 21:58 lss.c




Unix Processes

MultiProcesses vs MultiThreaded




Unix Program Image in Main Memory

A program is a sequence of machine-language instructions stored in a file. Running a program means loading that list of machine-language instructions into memory and having the CPU execute the instructions, one by one.

Let's spend 1 minute to find out what is a process and how it is loaded into the memory.

A process is the memory space and settings with which the program runs.


To look at the processes from Unix SA's prospective, let's start with Unix command 'ps'.
[root@ipc4 ~]# ps -fal
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
0 S root 16611 3560 0 76 0 - 1487 - 11:14 tty7 0:00:00 /usr/
4 S root 16635 16522 0 77 0 - 1393 wait 11:20 pts/2 0:00:00 su
4 S root 16636 16635 0 75 0 - 1463 wait 11:20 pts/2 0:00:00 -bash
0 S shan 16710 15966 0 78 0 - 5570 322557
11:38 pts/0 0:00:00 ./multi
4 S root 16714 16166 0 77 0 - 1101 wait 11:39 pts/1 0:00:00 su
4 S root 16715 16714 0 77 0 - 1438 wait 11:39 pts/1 0:00:00 -bash
4 S root 16749 16715 0 60 -20 - 5996 322557
11:39 pts/1 0:00:00 ./multi
4 R root 16755 16636 0 77 0 - 729 - 11:43 pts/2 0:00:00 ps

The column marked S shows the status of each process. R is running, S is sleeping. WCHAN shows why a process is sleeping.

A process has a size, shown in the SZ column. This number
represents the amount of memory the process is using. The size of a process change as it runs. A program that allocates memory when it runs can get larger. Memory in a Unix system is divided into kernel space and user space. Processes live in user space.

Columns marked PRI and NI contain priority and nicesness levels of the process. The kernel uses these values to decide when to run processes or the priority of the processes.

TTY shows which terminal the process is connected to. If no tty, the process is started at startup.

Among the above processes, there are two instances of program "./multi", one runs under user "shan" and another runs under "root". The one under "root" pid 16749's nice value is "-20" and priority is "60", which has much higher priority than the one runs under "shan". That's because the root started multi with nice value of -20.
You can use command "renice" to adjust the nice value of a process.

#nice -n -20 ./multi


The commands "ps ax" or "ps lax" (in linux) will show you all the running system processes, you will realize that a lot of processes don't have terminal ( TTY column marked ?) because they are started when the system starts up not typed by a user at command line.


[root@ipc4 prog]# ps ax
PID TTY STAT TIME COMMAND
1 ? S 0:00 init [5]
2 ? S 0:00 [migration/0]
3 ? SN 0:00 [ksoftirqd/0]
4 ? S 0:00 [migration/1]
5 ? SN 0:00 [ksoftirqd/1]
6 ? S 0:00 [events/0]
7 ? S 0:00 [events/1]
8 ? S 0:00 [khelper]
9 ? S 0:00 [kacpid]
22 ? S 0:00 [kblockd/0]
23 ? S 0:00 [kblockd/1]
33 ? S 0:00 [pdflush]
24 ? S 0:00 [khubd]
34 ? S 0:00 [pdflush]
36 ? S 0:00 [aio/0]
37 ? S 0:00 [aio/1]
35 ? S 0:01 [kswapd0]
111 ? S 0:00 [kseriod]
182 ? S 0:00 [scsi_eh_0]
194 ? S 0:00 [kmirrord/0]
195 ? S 0:00 [kmirrord/1]
203 ? S 0:03 [kjournald]
982 ? Ss 0:00 udevd
1668 ? S 0:00 [kjournald]
2175 ? Ss 0:00 syslogd -m 0
2179 ? Ss 0:00 klogd -x
2190 ? Ss 0:08 irqbalance
2208 ? Ss 0:00 portmap
2228 ? Ss 0:00 rpc.statd
2261 ? Ss 0:00 rpc.idmapd
2306 ? S 0:00 /usr/local/sbin/ypserv
2309 ? S 0:00 /usr/local/sbin/rpc.yppasswdd
2317 ? Sl 0:00 ypbind
2372 ? Ss 0:00 /usr/sbin/acpid
2435 ? Ss 0:52 /usr/sbin/vmware-guestd --background /var/run/vmware-
2491 ? Ssl 0:00 /usr/sbin/named -u named -t /var/named/chroot
2504 ? Ss 0:00 /usr/sbin/sshd
2532 ? SLs 0:00 ntpd -u ntp:ntp -p /var/run/ntpd.pid -g
2552 ? Ss 0:02 sendmail: accepting connections
2560 ? Ss 0:00 sendmail: Queue runner@01:00:00 for /var/spool/client
2571 ? Ss 0:00 gpm -m /dev/input/mice -t imps2
2591 ? Ss 0:00 crond
2617 ? Ss 0:00 xfs -droppriv -daemon
2636 ? Ss 0:00 /usr/sbin/atd
2655 ? Ssl 0:00 dbus-daemon-1 --system
2666 ? Ss 0:00 cups-config-daemon
2677 ? Ss 0:26 hald
2699 ? S 0:00 /bin/sh /usr/bin/mysqld_safe --datadir=/var/lib/mysql
2713 tty1 Ss+ 0:00 /sbin/mingetty tty1
2715 tty2 Ss+ 0:00 /sbin/mingetty tty2

Process is program in action.

How shell runs program?

A. User types program's name 'a.out'

B. The shell creates a new process to run the program ;

C. The shell loads the program from the disk into the process;
(done by execvp( const *prog, const char *argv[])

D. The program runs in its process until it is done.

Note: The kernel loads the program from the disk into CURRENT process, replacing the coe and data of current process.

In the following code, the message "ls is done. bye." will NOT be displayed, because it was erased by execvp.

The exec system call clears out the current program code from the current process, then, in the now empty process, puts the code of the program named in the exec call, and then runs that new program. exec also changes the memory allocation of the process to fit the space requirement of the new program. Note, the following code
printf("* * * ls is done. bye\n") will not be executed.

/* exec1.c
*/

main()
{
char *arglist[3];

arglist[0] = "ls";
arglist[1] = "-l";
arglist[2] = 0 ;
printf("* * * About to exec ls -l\n");
execvp( "ls" , arglist );
printf("* * * ls is done. bye\n");
}

[shan@ipc4 uulp]$ ./exec
* * * About to exec ls -l
total 124
-rw-rw-r-- 1 shan shan 2593 Nov 4 12:37 bounce.c
-rw-rw-r-- 1 shan shan 476 Nov 4 12:38 bounce.h
-rwxrwxr-x 1 shan shan 4924 Nov 4 15:03 exec
-rw-rw-r-- 1 shan shan 262 Nov 4 15:03 exec.c
-rw-rw-r-- 1 shan shan 1300 Nov 4 15:04 exec.out
drwxrwxr-x 2 shan shan 4096 Nov 4 12:43 game
-rwxrwxr-x 1 shan shan 4975 Nov 4 12:31 ignore
-rw-rw-r-- 1 shan shan 258 Nov 4 12:31 ignore.c
-rwxrwxr-x 1 shan shan 4989 Nov 4 12:21 job-1
-rwxrwxr-x 1 shan shan 6710 Nov 4 12:28 play
-rw-rw-r-- 1 shan shan 3271 Nov 4 12:28 play.c
-rwxrwxr-x 1 shan shan 5013 Nov 4 12:12 signal
-rw-rw-r-- 1 shan shan 399 Nov 4 12:21 signal.c




From Unix internal, let's see a process' memory layout:

1. Text Segment.
This is the machine instructions that are executed by CPU.

2.
Initialized data segment.
It contains variables that are specifically initialized in the program.


3. Uninitialized data segment or "bss" (block started by symbol).
Data in this segment is initialized by the kernel (0 or null pointers) before the program starts executing. e.g. C declaration long sum[2000];


4. Stack.
This is where automatic variables are stored, along with information that is saved each time a function is called.


5. Heap.
Dynamic memory allocation usually takes place in heap.


Unix 'size' command reports the sizes in bytes of the text, data, and bss segments.

[root@ipc4 prog]# size ~shan/prog/multi
text data bss dec hex filename
1389 280 8 1677 68d /home/shan/prog/multi

[root@ipc4 prog]# size /usr/bin/gcc

text data bss dec hex filename

89316 1576 932 91824 166b0 /usr/bin/gcc



Now, let's see how process (a running program) is loaded into the memory:



* In Linux processes loaded from a file system (using either the execve() or spawn() system calls) are in ELF format.

* If the file system is on a block-oriented device, the code and data are loaded into main memory.

* If the file system is memory mapped (e.g. ROM/Flash image), the code needn't be loaded into RAM, but may be executed in place.

* This approach makes all RAM available for data and stack, leaving the code in ROM or Flash. In all cases, if the same process is loaded more than once, its code will be shared.

* Before we can run an executable, firstly we have to load it into memory.

* This is done by the loader, which is generally part of the operating system. The loader does the following things (from other things):

1. Memory and access validation - Firstly, the OS system kernel reads in the program file’s header information and does the validation for type, access permissions, memory requirement and its ability to run its instructions. It confirms that file is an executable image and calculates memory requirements.

2. Process setup includes:

1) Allocates primary memory for the program's execution.
2) Copies address space from secondary to primary memory.
3) Copies the .text and .data sections from the executable into primary memory.
4) Copies program arguments (e.g., command line arguments) onto the stack.
5) Initializes registers: sets the esp (stack pointer) to point to top of stack, clears the rest.
6) Jumps to start routine, which: copies main()'s arguments off of the stack, and jumps to main().

* Address space is memory space that contains program code, stack, and data segments or in other word, all data the program uses as it runs.

* The memory layout, consists of three segments (text, data, and stack), see the attached figure.

* The dynamic data segment is also referred to as the heap, the place dynamically allocated memory (such as from malloc() and new) comes from. Dynamically allocated memory is memory allocated at run time instead of compile/link time.

* This organization enables any division of the dynamically allocated memory between the heap (explicitly) and the stack (implicitly). This explains why the stack grows downward and heap grows upward.



Below is a multithreaded C code, let's compile it and dump the object file content using readelf program.

[root@ipc4 prog]# cat multi.c
#include
#include

#define NUM 500

main()
{
pthread_t t1,t2;

long sum[1000];
int maxcount=99;

void *print_msg(void *);

pthread_create(&t1, NULL, print_msg, (void *) "hello");
pthread_create(&t2, NULL, print_msg, (void *) " world\n");
pthread_join(t1,NULL);
pthread_join(t2,NULL);
}

void *print_msg(void *m)
{
char *cp = (char *) m;
int i;
for (i=0 ; i<>
printf("%s",m);
fflush(stdout);
sleep(1);
}
return NULL;
}

[root@ipc4 prog]# gcc -g -v multi.c -lpthread -o multi
Reading specs from /usr/lib/gcc/i386-redhat-linux/3.4.3/specs
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-java-awt=gtk --host=i386-redhat-linux
Thread model: posix
gcc version 3.4.3 20050227 (Red Hat 3.4.3-22.1)
/usr/libexec/gcc/i386-redhat-linux/3.4.3/cc1 -quiet -v multi.c -quiet -dumpbase multi.c -auxbase multi -g -version -o /tmp/ccoHQEeG.s
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/3.4.3/include
/usr/include
End of search list.
GNU C version 3.4.3 20050227 (Red Hat 3.4.3-22.1) (i386-redhat-linux)
compiled by GNU C version 3.4.3 20050227 (Red Hat 3.4.3-22.1).
GGC heuristics: --param ggc-min-expand=64 --param ggc-min-heapsize=64314
as -V -Qy -o /tmp/ccw7Cttf.o /tmp/ccoHQEeG.s
GNU assembler version 2.15.92.0.2 (i386-redhat-linux) using BFD version 2.15.92.0.2 20040927
/usr/libexec/gcc/i386-redhat-linux/3.4.3/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o multi /usr/lib/gcc/i386-redhat-linux/3.4.3/../../../crt1.o /usr/lib/gcc/i386-redhat-linux/3.4.3/../../../crti.o /usr/lib/gcc/i386-redhat-linux/3.4.3/crtbegin.o -L/usr/lib/gcc/i386-redhat-linux/3.4.3 -L/usr/lib/gcc/i386-redhat-linux/3.4.3 -L/usr/lib/gcc/i386-redhat-linux/3.4.3/../../.. /tmp/ccw7Cttf.o -lpthread -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i386-redhat-linux/3.4.3/crtend.o /usr/lib/gcc/i386-redhat-linux/3.4.3/../../../crtn.o





[root@ipc4 prog]# readelf -hS ~shan/prog/multi
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048410
Start of program headers: 52 (bytes into file)
Start of section headers: 2460 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 28
Section header string table index: 25

Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048114 000114 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048128 000128 000020 00 A 0 0 4
[ 3] .hash HASH 08048148 000148 000040 04 A 4 0 4
[ 4] .dynsym DYNSYM 08048188 000188 0000b0 10 A 5 1 4
[ 5] .dynstr STRTAB 08048238 000238 0000aa 00 A 0 0 1
[ 6] .gnu.version VERSYM 080482e2 0002e2 000016 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 080482f8 0002f8 000050 00 A 5 2 4
[ 8] .rel.dyn REL 08048348 000348 000010 08 A 4 0 4
[ 9] .rel.plt REL 08048358 000358 000030 08 A 4 11 4
[10] .init PROGBITS 08048388 000388 000017 00 AX 0 0 4
[11] .plt PROGBITS 080483a0 0003a0 000070 04 AX 0 0 4
[12] .text PROGBITS 08048410 000410 00023c 00 AX 0 0 4
[13] .fini PROGBITS 0804864c 00064c 00001a 00 AX 0 0 4
[14] .rodata PROGBITS 08048668 000668 000019 00 A 0 0 4
[15] .eh_frame PROGBITS 08048684 000684 000004 00 A 0 0 4
[16] .ctors PROGBITS 08049688 000688 000008 00 WA 0 0 4
[17] .dtors PROGBITS 08049690 000690 000008 00 WA 0 0 4
[18] .jcr PROGBITS 08049698 000698 000004 00 WA 0 0 4
[19] .dynamic DYNAMIC 0804969c 00069c 0000d0 08 WA 5 0 4
[20] .got PROGBITS 0804976c 00076c 000004 04 WA 0 0 4
[21] .got.plt PROGBITS 08049770 000770 000024 04 WA 0 0 4
[22] .data PROGBITS 08049794 000794 00000c 00 WA 0 0 4
[23] .bss NOBITS 080497a0 0007a0 000008 00 WA 0 0 4
[24] .comment PROGBITS 00000000 0007a0 000123 00 0 0 1
[25] .shstrtab STRTAB 00000000 0008c3 0000d7 00 0 0 1
[26] .symtab SYMTAB 00000000 000dfc 0004c0 10 27 44 4
[27] .strtab STRTAB 00000000 0012bc 0002a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
[root@ipc4 prog]# readelf -a ~shan/prog/multi
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048410
Start of program headers: 52 (bytes into file)
Start of section headers: 2460 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 28
Section header string table index: 25

Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048114 000114 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048128 000128 000020 00 A 0 0 4
[ 3] .hash HASH 08048148 000148 000040 04 A 4 0 4
[ 4] .dynsym DYNSYM 08048188 000188 0000b0 10 A 5 1 4
[ 5] .dynstr STRTAB 08048238 000238 0000aa 00 A 0 0 1
[ 6] .gnu.version VERSYM 080482e2 0002e2 000016 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 080482f8 0002f8 000050 00 A 5 2 4
[ 8] .rel.dyn REL 08048348 000348 000010 08 A 4 0 4
[ 9] .rel.plt REL 08048358 000358 000030 08 A 4 11 4
[10] .init PROGBITS 08048388 000388 000017 00 AX 0 0 4
[11] .plt PROGBITS 080483a0 0003a0 000070 04 AX 0 0 4
[12] .text PROGBITS 08048410 000410 00023c 00 AX 0 0 4
[13] .fini PROGBITS 0804864c 00064c 00001a 00 AX 0 0 4
[14] .rodata PROGBITS 08048668 000668 000019 00 A 0 0 4
[15] .eh_frame PROGBITS 08048684 000684 000004 00 A 0 0 4
[16] .ctors PROGBITS 08049688 000688 000008 00 WA 0 0 4
[17] .dtors PROGBITS 08049690 000690 000008 00 WA 0 0 4
[18] .jcr PROGBITS 08049698 000698 000004 00 WA 0 0 4
[19] .dynamic DYNAMIC 0804969c 00069c 0000d0 08 WA 5 0 4
[20] .got PROGBITS 0804976c 00076c 000004 04 WA 0 0 4
[21] .got.plt PROGBITS 08049770 000770 000024 04 WA 0 0 4
[22] .data PROGBITS 08049794 000794 00000c 00 WA 0 0 4
[23] .bss NOBITS 080497a0 0007a0 000008 00 WA 0 0 4
[24] .comment PROGBITS 00000000 0007a0 000123 00 0 0 1
[25] .shstrtab STRTAB 00000000 0008c3 0000d7 00 0 0 1
[26] .symtab SYMTAB 00000000 000dfc 0004c0 10 27 44 4
[27] .strtab STRTAB 00000000 0012bc 0002a8 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00688 0x00688 R E 0x1000
LOAD 0x000688 0x08049688 0x08049688 0x00118 0x00120 RW 0x1000
DYNAMIC 0x00069c 0x0804969c 0x0804969c 0x000d0 0x000d0 RW 0x4
NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4

Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag
06

Dynamic section at offset 0x69c contains 21 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libpthread.so.0]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x8048388
0x0000000d (FINI) 0x804864c
0x00000004 (HASH) 0x8048148
0x00000005 (STRTAB) 0x8048238
0x00000006 (SYMTAB) 0x8048188
0x0000000a (STRSZ) 170 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x8049770
0x00000002 (PLTRELSZ) 48 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8048358
0x00000011 (REL) 0x8048348
0x00000012 (RELSZ) 16 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x80482f8
0x6fffffff (VERNEEDNUM) 2
0x6ffffff0 (VERSYM) 0x80482e2
0x00000000 (NULL) 0x0

Relocation section '.rel.dyn' at offset 0x348 contains 2 entries:
Offset Info Type Sym.Value Sym. Name
0804976c 00000a06 R_386_GLOB_DAT 00000000 __gmon_start__
080497a0 00000305 R_386_COPY 080497a0 stdout

Relocation section '.rel.plt' at offset 0x358 contains 6 entries:
Offset Info Type Sym.Value Sym. Name
0804977c 00000107 R_386_JUMP_SLOT 00000000 fflush
08049780 00000207 R_386_JUMP_SLOT 00000000 pthread_create
08049784 00000407 R_386_JUMP_SLOT 00000000 sleep
08049788 00000507 R_386_JUMP_SLOT 00000000 __libc_start_main
0804978c 00000607 R_386_JUMP_SLOT 00000000 printf
08049790 00000707 R_386_JUMP_SLOT 00000000 pthread_join

There are no unwind sections in this file.

Symbol table '.dynsym' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 293 FUNC GLOBAL DEFAULT UND fflush@GLIBC_2.0 (2)
2: 00000000 396 FUNC GLOBAL DEFAULT UND pthread_create@GLIBC_2.1 (3)
3: 080497a0 4 OBJECT GLOBAL DEFAULT 23 stdout@GLIBC_2.0 (2)
4: 00000000 626 FUNC GLOBAL DEFAULT UND sleep@GLIBC_2.0 (2)
5: 00000000 221 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.0 (2)
6: 00000000 54 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.0 (2)
7: 00000000 692 FUNC GLOBAL DEFAULT UND pthread_join@GLIBC_2.0 (4)
8: 0804866c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
9: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
10: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

Symbol table '.symtab' contains 76 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048114 0 SECTION LOCAL DEFAULT 1
2: 08048128 0 SECTION LOCAL DEFAULT 2
3: 08048148 0 SECTION LOCAL DEFAULT 3
4: 08048188 0 SECTION LOCAL DEFAULT 4
5: 08048238 0 SECTION LOCAL DEFAULT 5
6: 080482e2 0 SECTION LOCAL DEFAULT 6
7: 080482f8 0 SECTION LOCAL DEFAULT 7
8: 08048348 0 SECTION LOCAL DEFAULT 8
9: 08048358 0 SECTION LOCAL DEFAULT 9
10: 08048388 0 SECTION LOCAL DEFAULT 10
11: 080483a0 0 SECTION LOCAL DEFAULT 11
12: 08048410 0 SECTION LOCAL DEFAULT 12
13: 0804864c 0 SECTION LOCAL DEFAULT 13
14: 08048668 0 SECTION LOCAL DEFAULT 14
15: 08048684 0 SECTION LOCAL DEFAULT 15
16: 08049688 0 SECTION LOCAL DEFAULT 16
17: 08049690 0 SECTION LOCAL DEFAULT 17
18: 08049698 0 SECTION LOCAL DEFAULT 18
19: 0804969c 0 SECTION LOCAL DEFAULT 19
20: 0804976c 0 SECTION LOCAL DEFAULT 20
21: 08049770 0 SECTION LOCAL DEFAULT 21
22: 08049794 0 SECTION LOCAL DEFAULT 22
23: 080497a0 0 SECTION LOCAL DEFAULT 23
24: 00000000 0 SECTION LOCAL DEFAULT 24
25: 00000000 0 SECTION LOCAL DEFAULT 25
26: 00000000 0 SECTION LOCAL DEFAULT 26
27: 00000000 0 SECTION LOCAL DEFAULT 27
28: 08048434 0 FUNC LOCAL DEFAULT 12 call_gmon_start
29: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
30: 08049688 0 OBJECT LOCAL DEFAULT 16 __CTOR_LIST__
31: 08049690 0 OBJECT LOCAL DEFAULT 17 __DTOR_LIST__
32: 08049698 0 OBJECT LOCAL DEFAULT 18 __JCR_LIST__
33: 0804979c 0 OBJECT LOCAL DEFAULT 22 p.0
34: 080497a4 1 OBJECT LOCAL DEFAULT 23 completed.1
35: 08048458 0 FUNC LOCAL DEFAULT 12 __do_global_dtors_aux
36: 0804848c 0 FUNC LOCAL DEFAULT 12 frame_dummy
37: 00000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
38: 0804968c 0 OBJECT LOCAL DEFAULT 16 __CTOR_END__
39: 08049694 0 OBJECT LOCAL DEFAULT 17 __DTOR_END__
40: 08048684 0 OBJECT LOCAL DEFAULT 15 __FRAME_END__
41: 08049698 0 OBJECT LOCAL DEFAULT 18 __JCR_END__
42: 08048628 0 FUNC LOCAL DEFAULT 12 __do_global_ctors_aux
43: 00000000 0 FILE LOCAL DEFAULT ABS multi.c
44: 0804969c 0 OBJECT GLOBAL DEFAULT 19 _DYNAMIC
45: 08048668 4 OBJECT GLOBAL DEFAULT 14 _fp_hw
46: 00000000 293 FUNC GLOBAL DEFAULT UND fflush@@GLIBC_2.0
47: 00000000 396 FUNC GLOBAL DEFAULT UND pthread_create@@GLIBC_2.1
48: 08049688 0 NOTYPE GLOBAL HIDDEN ABS __fini_array_end
49: 08049798 0 OBJECT GLOBAL HIDDEN 22 __dso_handle
50: 080485e4 66 FUNC GLOBAL DEFAULT 12 __libc_csu_fini
51: 08048388 0 FUNC GLOBAL DEFAULT 10 _init
52: 080497a0 4 OBJECT GLOBAL DEFAULT 23 stdout@@GLIBC_2.0
53: 08048410 0 FUNC GLOBAL DEFAULT 12 _start
54: 00000000 626 FUNC GLOBAL DEFAULT UND sleep@@GLIBC_2.0
55: 08049688 0 NOTYPE GLOBAL HIDDEN ABS __fini_array_start
56: 08048590 82 FUNC GLOBAL DEFAULT 12 __libc_csu_init
57: 080497a0 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
58: 080484b8 123 FUNC GLOBAL DEFAULT 12 main
59: 00000000 221 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
60: 08049688 0 NOTYPE GLOBAL HIDDEN ABS __init_array_end
61: 08049794 0 NOTYPE WEAK DEFAULT 22 data_start
62: 00000000 54 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.0
63: 0804864c 0 FUNC GLOBAL DEFAULT 13 _fini
64: 08049688 0 NOTYPE GLOBAL HIDDEN ABS __preinit_array_end
65: 08048533 91 FUNC GLOBAL DEFAULT 12 print_msg
66: 00000000 692 FUNC GLOBAL DEFAULT UND pthread_join@@GLIBC_2.0
67: 080497a0 0 NOTYPE GLOBAL DEFAULT ABS _edata
68: 08049770 0 OBJECT GLOBAL DEFAULT 21 _GLOBAL_OFFSET_TABLE_
69: 080497a8 0 NOTYPE GLOBAL DEFAULT ABS _end
70: 08049688 0 NOTYPE GLOBAL HIDDEN ABS __init_array_start
71: 0804866c 4 OBJECT GLOBAL DEFAULT 14 _IO_stdin_used
72: 08049794 0 NOTYPE GLOBAL DEFAULT 22 __data_start
73: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
74: 08049688 0 NOTYPE GLOBAL HIDDEN ABS __preinit_array_start
75: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__

Histogram for bucket list length (total of 3 buckets):
Length Number % of total Coverage
0 0 ( 0.0%)
1 1 ( 33.3%) 10.0%
2 0 ( 0.0%) 10.0%
3 1 ( 33.3%) 40.0%
4 0 ( 0.0%) 40.0%
5 0 ( 0.0%) 40.0%
6 1 ( 33.3%) 100.0%

Version symbols section '.gnu.version' contains 11 entries:
Addr: 00000000080482e2 Offset: 0x0002e2 Link: 4 (.dynsym)
000: 0 (*local*) 2 (GLIBC_2.0) 3 (GLIBC_2.1) 2 (GLIBC_2.0)
004: 2 (GLIBC_2.0) 2 (GLIBC_2.0) 2 (GLIBC_2.0) 4 (GLIBC_2.0)
008: 1 (*global*) 0 (*local*) 0 (*local*)

Version needs section '.gnu.version_r' contains 2 entries:
Addr: 0x00000000080482f8 Offset: 0x0002f8 Link to section: 5 (.dynstr)
000000: Version: 1 File: libpthread.so.0 Cnt: 2
0x0010: Name: GLIBC_2.0 Flags: none Version: 4
0x0020: Name: GLIBC_2.1 Flags: none Version: 3
0x0030: Version: 1 File: libc.so.6 Cnt: 1
0x0040: Name: GLIBC_2.0 Flags: none Version: 2




Bonus for UNIX Admins:

[shan@ipc4 uulp]$ which ps options can do this?

PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
7196 7197 7197 7197 pts/5 7424 Ss 500 0:00 -bash
7197 7415 7415 7197 pts/5 7424 S 500 0:00 \_ ./fork2
7415 7416 7415 7197 pts/5 7424 S 500 0:00 | \_ ./fork2
7416 7417 7415 7197 pts/5 7424 S 500 0:00 | | \_ ./fork2
7417 7419 7415 7197 pts/5 7424 S 500 0:00 | | | \_ ./fork2
7416 7421 7415 7197 pts/5 7424 S 500 0:00 | | \_ ./fork2
7415 7418 7415 7197 pts/5 7424 S 500 0:00 | \_ ./fork2
7418 7420 7415 7197 pts/5 7424 S 500 0:00 | | \_ ./fork2
7415 7422 7415 7197 pts/5 7424 S 500 0:00 | \_ ./fork2
7197 7424 7424 7197 pts/5 7424 R+ 500 0:00 \_ ps ajf


Or this?

7194 7194 7194 ? 00:00:00 sshd
7196 7194 7194 ? 00:00:02 sshd
7197 7197 7197 pts/5 00:00:00 bash
7426 7426 7197 pts/5 00:00:00 fork2
7427 7426 7197 pts/5 00:00:00 fork2
7428 7426 7197 pts/5 00:00:00 fork2
7429 7426 7197 pts/5 00:00:00 fork2
7431 7426 7197 pts/5 00:00:00 fork2
7430 7426 7197 pts/5 00:00:00 fork2
7432 7426 7197 pts/5 00:00:00 fork2
7433 7426 7197 pts/5 00:00:00 fork2
7434 7434 7197 pts/5 00:00:00 ps
2514 2514 2514 ? 00:00:00 xinetd


(answers in whites: ps ajf and ps -ejH )