Automated Presentation of directory src/swtools/DSOs/forum93/

HUB | Up | Download | Pheedbak | Tree | Topic | A-Z | Search | Hot | New


Please be aware: what appears below are the v4.2 DT bits in auto-generated html form.
As we have the time, we will update these to reflect the current "state of the world".


README file from "forum93" directory

             ~4Dgifts/toolbox/src/swtools/DSOs/forum93 README

    `!' indicates new or updated as of version 4.2


 !  forum93.showcase:  updated to now include information on 64 bit


         This paper refers to the 8 sub-directories containing the 
         case studies code and Makefiles, and should be studied in 
      concert with the "forum93.showcase" file included here as well.


                  Case Studies in Dynamic Shared Objects

                             Jay L. Gischer
                         MIPS Technologies, Inc,
		
     In this paper we study several issues related to the use of dynamic
     shared objects (DSO) as implemented in the IRIX (tm) 5.1 operating
     system.  Each of the cases is based upon a real problem or issue 
     that has occurred during the last year or so.  But the names have 
     been changed and the problems simplified for legal and pedagogical 
     reasons.


  CASE 1:  Coordinating the build of multiple shared objects to avoid 
	   collisions.

  CASE 2:  Side-by-side comparison of calling overhead for a typical 
	   procedure call.  Compares DSO overhead to static shared 
	   library overhead.  All builds are done with cc -c -O.

  CASE 3:  This case looks at how to best write leaf/small routines to 
	   tighten the coding.

  CASE 4:  We examine certain loops with calls to very short functions, 
	   such as are found in the IRIX GL (tm) graphics library, and 
	   see how to reduce the loop overhead for such code.  For 
	   correctness, it is necessary for the compiler to generate 
	   code for function calls which loads the address of the 
	   function each time it is called.  This is because the address 
	   could potentially change during a call.  These examples show 
	   that by taking the address of the function and calling 
	   through a function pointer, the developer can effectively 
	   guarantee to the compiler that the address will not change, 
	   moving the load of the address out of the loop.

  CASE 5:  Handling platform-dependent configurations.

  CASE 6:  This case shows how shared objects can reduce the redundancy 
	   of some link lines because of the different linking semantics 
	   of DSO vs. archives.

  CASE 7:  Speeding the development cycle by reducing build/link time.  
	   Avoid relinking everything by putting the bulk of code into a 
	   shared object and preempting selected portions.

  CASE 8:  Using dlopen(), dlsym(), dlerror() to configure software at 
	   runtime.  The following example is based on languages but is 
	   not the recommended method for internationalization.


# CASE 1.
#
# Coordinating the build of multiple shared objects
# to avoid collisions.
#

# First the naive way.

6 gischer@puget: ls
Makefile   mymain.c   myso1/     myso2/
7 gischer@puget: more Makefile mymain.c
::::::::::::::
Makefile
::::::::::::::
RPATH = $(PWD)/myso1:$(PWD)/myso2

default:
        (cd myso1; make)
        (cd myso2; make)
        make mymain

mymain: mymain.o
        cc -Wl,-rpath,$(RPATH) mymain.o myso1/myso1.so myso2/myso2.so -o mymain
::::::::::::::
mymain.c
::::::::::::::
void foo1(void);
void foo2(void);

main() {
    foo1();
    foo2();
}

8 gischer@puget: cd myso1
9 gischer@puget: more *
::::::::::::::
Makefile
::::::::::::::
myso1.so: myso1.o
        ld -shared myso1.o -o myso1.so
::::::::::::::
myso1.c
::::::::::::::
#include <stdio.h>

void
foo1(void) {
    printf("This is foo1\n");
}
::::::::::::::
so_locations
::::::::::::::
myso1.so \
                :st = .text 0x5ffe0000, 0x00010000:\
                :st = .data 0x5fff0000, 0x00010000:\

10 gischer@puget: cd ../myso2
11 gischer@puget: more *
::::::::::::::
Makefile
::::::::::::::
myso2.so: myso2.o
        ld -shared myso2.o -o myso2.so
::::::::::::::
myso2.c
::::::::::::::
#include <stdio.h>

void
foo2(void) {
    printf("This is foo2\n");
}
::::::::::::::
so_locations
::::::::::::::
myso2.so \
                :st = .text 0x5ffe0000, 0x00010000:\
                :st = .data 0x5fff0000, 0x00010000:\


# Now we build the libraries and examine them to verify that they
# collide
#
12 gischer@puget: cd ..
13 gischer@puget: make
        (cd myso1; make)
        cc -O -c myso1.c
        ld -shared myso1.o -o myso1.so
        (cd myso2; make)
`myso2.so' is up to date.
        make mymain
        cc -O -c mymain.c
        cc -Wl,-rpath,/usr/people/gischer/forum/case1/slow/myso1:/usr/people/gischer/forum/case1/slow/myso2 mymain.o myso1/myso1.so myso2/myso2.so -o mymain

14 gischer@puget: elfdump -o myso1/myso1.so


                        ***PROGRAM HEADER***
    Type     Offset      Vaddr      Paddr     Filesz      Memsz      Align RWX

 REGINFO 0x000000c0 0x5ffe00c0 0x5ffe00c0 0x00000018 0x00000018 0x00000004 r--
 DYNAMIC 0x00000100 0x5ffe0100 0x5ffe0100 0x00000240 0x00000240 0x00000010 r--
    LOAD 0x00000000 0x5ffe0000 0x5ffe0000 0x00001000 0x00001000 0x00010000 r-x
    LOAD 0x00001000 0x5fff0000 0x5fff0000 0x00001000 0x00001000 0x00010000 rw-
15 gischer@puget: elfdump -o myso2/myso2.so


                        ***PROGRAM HEADER***
    Type     Offset      Vaddr      Paddr     Filesz      Memsz      Align RWX

 REGINFO 0x000000c0 0x5ffe00c0 0x5ffe00c0 0x00000018 0x00000018 0x00000004 r--
 DYNAMIC 0x00000100 0x5ffe0100 0x5ffe0100 0x00000240 0x00000240 0x00000010 r--
    LOAD 0x00000000 0x5ffe0000 0x5ffe0000 0x00001000 0x00001000 0x00010000 r-x
    LOAD 0x00001000 0x5fff0000 0x5fff0000 0x00001000 0x00001000 0x00010000 rw-


# now we use a central registry file to coordinate.
#
6 gischer@puget: ls
Makefile            myso1/              so_locations.init
mymain.c            myso2/
7 gischer@puget: more Makefile mymain.c so_locations.init
::::::::::::::
Makefile
::::::::::::::
RPATH = $(PWD)/myso1:$(PWD)/myso2

default: so_locations
        (cd myso1; make)
        (cd myso2; make)
        make mymain

mymain: mymain.o
        cc -Wl,-rpath,$(RPATH) mymain.o myso1/myso1.so myso2/myso2.so -o mymain

so_locations:
        cp so_locations.init so_locations
::::::::::::::
mymain.c
::::::::::::::
void foo1(void);
void foo2(void);

main() {
    foo1();
    foo2();
}

::::::::::::::
so_locations.init
::::::::::::::
$start_address=0x40000000

reserved\
        :st = $range 0x3f000000,0x01000000:

myso1.so\
        :st = $range 0x3e000000,0x01000000:

myso2.so\
        :st = $range 0x3d000000,0x01000000:


8 gischer@puget: cd myso1
9 gischer@puget: more *
::::::::::::::
Makefile
::::::::::::::
myso1.so: myso1.o
        ld -shared myso1.o -update_registry ../so_locations -o myso1.so
::::::::::::::
myso1.c
::::::::::::::
#include <stdio.h>

foo1(void) {
    printf("This is foo1\n");
}
10 gischer@puget: cd ../myso2
11 gischer@puget: more *
::::::::::::::
Makefile
::::::::::::::
myso2.so: myso2.o
        ld -shared myso2.o -update_registry ../so_locations -o myso2.so
::::::::::::::
myso2.c
::::::::::::::
#include <stdio.h>
void
foo2(void) {
    printf("This is foo2\n");
}
12 gischer@puget: cd ..
13 gischer@puget: make
        cp so_locations.init so_locations
        (cd myso1; make)
        cc -O -c myso1.c
        ld -shared myso1.o -update_registry ../so_locations -o myso1.so
        (cd myso2; make)
        cc -O -c myso2.c
        ld -shared myso2.o -update_registry ../so_locations -o myso2.so
        make mymain
        cc -O -c mymain.c
        cc -Wl,-rpath,/usr/people/gischer/forum/case1/fast/myso1:/usr/people/gischer/forum/case1/fast/myso2 mymain.o myso1/myso1.so myso2/myso2.so -o mymain
14 gischer@puget: ls
Makefile            mymain.c            myso1/              so_locations
mymain*             mymain.o            myso2/              so_locations.init
15 gischer@puget: more so_locations
$start_address=0x40000000
reserved \
                :st = $range 0x3f000000, 0x01000000:\

myso1.so \
                :st = $range 0x3e000000, 0x01000000:\
                :st = .text 0x3efe0000, 0x00010000:\
                :st = .data 0x3eff0000, 0x00010000:\

myso2.so \
                :st = $range 0x3d000000, 0x01000000:\
                :st = .text 0x3dfe0000, 0x00010000:\
                :st = .data 0x3dff0000, 0x00010000:\

# CASE 2
#
# Side-by-side comparison of calling overhead for a typical procedure
# call.  Compares DSO overhead to static shared library overhead.
# All builds are done with cc -c -O.

::::::::::::::
caller.c
::::::::::::::
int callee(int,int);

int foo[100];

void
caller(int x, int y) {

    foo[0] = callee(x,y);
    foo[1] = callee(x+1,y+1);
    foo[2] = callee(x+2,y+2);
}

::::::::::::::
callee.c
::::::::::::::
int callee(int x, int y) {

        return (x+2*y);
}

# Now the disassembly files
::::::::::::::
caller.shlib
::::::::::::::
	caller:
  [caller.c:   6] 0x0:	27bdffd8	addiu	sp,sp,-40
  [caller.c:   6] 0x4:	afbf0014	sw	ra,20(sp)
  [caller.c:   6] 0x8:	afa40028	sw	a0,40(sp)
  [caller.c:   8] 0xc:	0c000000	jal	caller
  [caller.c:   6] 0x10:	afa5002c	sw	a1,44(sp)
  [caller.c:   9] 0x14:	8fa40028	lw	a0,40(sp)
  [caller.c:   9] 0x18:	8fa5002c	lw	a1,44(sp)
  [caller.c:   8] 0x1c:	3c010000	lui	at,0
  [caller.c:   8] 0x20:	ac220000	sw	v0,0(at)
  [caller.c:   9] 0x24:	24840001	addiu	a0,a0,1
  [caller.c:   9] 0x28:	0c000000	jal	caller
  [caller.c:   9] 0x2c:	24a50001	addiu	a1,a1,1
  [caller.c:  10] 0x30:	8fa40028	lw	a0,40(sp)	# These
  [caller.c:  10] 0x34:	8fa5002c	lw	a1,44(sp)	# instructions
  [caller.c:   9] 0x38:	3c010000	lui	at,0		# all belong
  [caller.c:   9] 0x3c:	ac220004	sw	v0,4(at)	# to the 
  [caller.c:  10] 0x40:	24840002	addiu	a0,a0,2		# same
  [caller.c:  10] 0x44:	0c000000	jal	caller		# call.
  [caller.c:  10] 0x48:	24a50002	addiu	a1,a1,2		#
  [caller.c:  11] 0x4c:	8fbf0014	lw	ra,20(sp)
  [caller.c:  10] 0x50:	3c010000	lui	at,0
  [caller.c:  10] 0x54:	ac220008	sw	v0,8(at)
  [caller.c:  11] 0x58:	03e00008	jr	ra
  [caller.c:  11] 0x5c:	27bd0028	addiu	sp,sp,40

::::::::::::::
callee.shlib
::::::::::::::
	callee:
  [callee.c:   1] 0x0:	00057040	sll	t6,a1,1
  [callee.c:   1] 0x4:	03e00008	jr	ra
  [callee.c:   1] 0x8:	01c41021	addu	v0,t6,a0
  0xc:	00000000	nop


# Now the dso code

::::::::::::::
caller.dso
::::::::::::::
	caller:
  [caller.c:   6] 0x0:	3c1c0000	lui	gp,0
  [caller.c:   6] 0x4:	279c0000	addiu	gp,gp,0
  [caller.c:   6] 0x8:	0399e021	addu	gp,gp,t9
  [caller.c:   6] 0xc:	27bdffe0	addiu	sp,sp,-32
  [caller.c:   8] 0x10:	8f990000	lw	t9,0(gp)
  [caller.c:   6] 0x14:	afbf001c	sw	ra,28(sp)
  [caller.c:   6] 0x18:	afbc0018	sw	gp,24(sp)
  [caller.c:   6] 0x1c:	afa40020	sw	a0,32(sp)
  [caller.c:   8] 0x20:	0320f809	jalr	ra,t9
  [caller.c:   6] 0x24:	afa50024	sw	a1,36(sp)
  [caller.c:   8] 0x28:	8fbc0018	lw	gp,24(sp)
  [caller.c:   9] 0x2c:	8fa40020	lw	a0,32(sp)	#
  [caller.c:   9] 0x30:	8fa50024	lw	a1,36(sp)	#
  [caller.c:   8] 0x34:	8f810000	lw	at,0(gp)	
  [caller.c:   9] 0x38:	8f990000	lw	t9,0(gp)	#
  [caller.c:   9] 0x3c:	24840001	addiu	a0,a0,1		#
  [caller.c:   9] 0x40:	24a50001	addiu	a1,a1,1		#
  [caller.c:   9] 0x44:	0320f809	jalr	ra,t9		#
  [caller.c:   8] 0x48:	ac220000	sw	v0,0(at)	
  [caller.c:   9] 0x4c:	8fbc0018	lw	gp,24(sp)	#
  [caller.c:  10] 0x50:	8fa40020	lw	a0,32(sp)
  [caller.c:  10] 0x54:	8fa50024	lw	a1,36(sp)
  [caller.c:   9] 0x58:	8f810000	lw	at,0(gp)	#
  [caller.c:  10] 0x5c:	8f990000	lw	t9,0(gp)
  [caller.c:  10] 0x60:	24840002	addiu	a0,a0,2
  [caller.c:  10] 0x64:	24a50002	addiu	a1,a1,2
  [caller.c:  10] 0x68:	0320f809	jalr	ra,t9
  [caller.c:   9] 0x6c:	ac220004	sw	v0,4(at)	#
  [caller.c:  10] 0x70:	8fbc0018	lw	gp,24(sp)
  [caller.c:  11] 0x74:	8fbf001c	lw	ra,28(sp)
  [caller.c:  10] 0x78:	8f810000	lw	at,0(gp)
  [caller.c:  11] 0x7c:	27bd0020	addiu	sp,sp,32
  [caller.c:  11] 0x80:	03e00008	jr	ra
  [caller.c:  10] 0x84:	ac220008	sw	v0,8(at)
  0x88:	00000000	nop
  0x8c:	00000000	nop

::::::::::::::
callee.dso
::::::::::::::
	callee:
  [callee.c:   1] 0x0:	00057040	sll	t6,a1,1
  [callee.c:   1] 0x4:	03e00008	jr	ra
  [callee.c:   1] 0x8:	01c41021	addu	v0,t6,a0
  0xc:	00000000	nop




# CASE 3
#
# This case looks at how to best write leaf/small routines to tighten
# the coding.

5 gischer@puget: cat func.c
::::::::::::::
func.c
::::::::::::::
extern int x;
extern int y;

int func(int z) {

    if (x > 0) {
        ++y;
    }
    return (y+z);
}

6 gischer@puget: cc -c -O func.c
7 gischer@puget: dis func.o > func.o.dis
8 gischer@puget: cat func.o.dis
::::::::::::::
func.o.dis
::::::::::::::
        func:
  [func.c:   4] 0x0:    3c1c0000        lui     gp,0
  [func.c:   4] 0x4:    279c0000        addiu   gp,gp,0
  [func.c:   4] 0x8:    0399e021        addu    gp,gp,t9
  [func.c:   6] 0xc:    8f8e0000        lw      t6,0(gp)
  [func.c:   6] 0x10:   00000000        nop
  [func.c:   6] 0x14:   8dce0000        lw      t6,0(t6)
  [func.c:   6] 0x18:   00000000        nop
  [func.c:   6] 0x1c:   19c00007        blez    t6,0x3c
  [func.c:   6] 0x20:   00000000        nop
  [func.c:   6] 0x24:   8f830000        lw      v1,0(gp)
  [func.c:   7] 0x28:   00000000        nop
  [func.c:   7] 0x2c:   8c6f0000        lw      t7,0(v1)
  [func.c:   7] 0x30:   00000000        nop
  [func.c:   7] 0x34:   25f80001        addiu   t8,t7,1
  [func.c:   7] 0x38:   ac780000        sw      t8,0(v1)
  [func.c:   7] 0x3c:   8f830000        lw      v1,0(gp)
  [func.c:   9] 0x40:   00000000        nop
  [func.c:   9] 0x44:   8c790000        lw      t9,0(v1)
  [func.c:   9] 0x48:   03e00008        jr      ra
  [func.c:   9] 0x4c:   03241021        addu    v0,t9,a0

#
# Now we try passing parameters
#
9 gischer@puget: cat func2.c
::::::::::::::
func2.c
::::::::::::::

int func(int x, int *yp, int z) {

    if (x > 0) {
            ++*yp;
    }
    return (*yp+z);
}

10 gischer@puget: cc -c -O func2.c
11 gischer@puget: dis func2.o > func2.o.dis
12 gischer@puget: cat func2.o.dis
::::::::::::::
func2.o.dis
::::::::::::::
        func:
  [func2.c:   3] 0x0:   18800005        blez    a0,0x18
  [func2.c:   3] 0x4:   00000000        nop
  [func2.c:   4] 0x8:   8cae0000        lw      t6,0(a1)
  [func2.c:   4] 0xc:   00000000        nop
  [func2.c:   4] 0x10:  25cf0001        addiu   t7,t6,1
  [func2.c:   4] 0x14:  acaf0000        sw      t7,0(a1)
  [func2.c:   6] 0x18:  8cb80000        lw      t8,0(a1)
  [func2.c:   6] 0x1c:  03e00008        jr      ra
  [func2.c:   6] 0x20:  03061021        addu    v0,t8,a2
  0x24: 00000000        nop
  0x28: 00000000        nop
  0x2c: 00000000        nop

#
# Just for fun, try passing a struct.
#
13 gischer@puget: cat func3.c
::::::::::::::
func3.c
::::::::::::::

struct info {
    int x;
    int y;
};
   
int func(struct info *ir, int z) {

    if (ir->x > 0) {
        ++ir->y;
    }
    return (ir->y+z);
}

10 gischer@puget: cc -c -O func3.c
11 gischer@puget: dis func3.o > func3.o.dis
12 gischer@puget: cat func3.o.dis
::::::::::::::
func3.o.dis
::::::::::::::
        func:
  [func3.c:   8] 0x0:   8c8e0000        lw      t6,0(a0)
  [func3.c:   8] 0x4:   00000000        nop
  [func3.c:   8] 0x8:   19c00005        blez    t6,0x20
  [func3.c:   8] 0xc:   00000000        nop
  [func3.c:   9] 0x10:  8c8f0004        lw      t7,4(a0)
  [func3.c:   9] 0x14:  00000000        nop
  [func3.c:   9] 0x18:  25f80001        addiu   t8,t7,1
  [func3.c:   9] 0x1c:  ac980004        sw      t8,4(a0)
  [func3.c:  11] 0x20:  8c990004        lw      t9,4(a0)
  [func3.c:  11] 0x24:  03e00008        jr      ra
  [func3.c:  11] 0x28:  03251021        addu    v0,t9,a1
  0x2c: 00000000        nop



# CASE 4
#
# We examine certain loops with calls to very short functions, such as
# are found in the IRIX GL (tm) graphics library, and see how
# to reduce the loop overhead for such code.
#
# For correctness, it is necessary for the compiler to generate code for
# function calls which loads the address of the function each time it is
# called.  This is because the address could potentially change during
# a call.  These examples show that by taking the address of the
# function and calling through a function pointer, the developer can
# effectively guarantee to the compiler that the address will not
# change, moving the load of the address out of the loop.

6 gischer@puget: more loop.c
::::::::::::::
loop.c
::::::::::::::
extern float v3f(float *);

float *pts[100];

void loop() {
    int i;
    for (i=1; i<100; i++) {
        v3f(pts[i]);
    }
}
    
7 gischer@puget: cc -c -O loop.c
8 gischer@puget: dis loop.o > loop.o.dis; cat loop.o.dis
::::::::::::::
loop.o.dis
::::::::::::::
        loop:
  [loop.c:   5] 0x0:    3c1c0000        lui     gp,0
  [loop.c:   5] 0x4:    279c0000        addiu   gp,gp,0
  [loop.c:   5] 0x8:    0399e021        addu    gp,gp,t9
  [loop.c:   5] 0xc:    27bdffd8        addiu   sp,sp,-40
  [loop.c:   5] 0x10:   afb1001c        sw      s1,28(sp)
  [loop.c:   5] 0x14:   afb00018        sw      s0,24(sp)
  [loop.c:   7] 0x18:   8f900000        lw      s0,0(gp)
  [loop.c:   7] 0x1c:   8f910000        lw      s1,0(gp)
  [loop.c:   5] 0x20:   afbf0024        sw      ra,36(sp)
  [loop.c:   5] 0x24:   afbc0020        sw      gp,32(sp)
  [loop.c:   7] 0x28:   26100004        addiu   s0,s0,4
  [loop.c:   7] 0x2c:   26310190        addiu   s1,s1,400
  [loop.c:   8] 0x30:   8f990000        lw      t9,0(gp)	# start loop
  [loop.c:   8] 0x34:   8e040000        lw      a0,0(s0)	#
  [loop.c:   8] 0x38:   0320f809        jalr    ra,t9		#
  [loop.c:   8] 0x3c:   00000000        nop			#
  [loop.c:   8] 0x40:   8fbc0020        lw      gp,32(sp)	#
  [loop.c:   8] 0x44:   26100004        addiu   s0,s0,4		#
  [loop.c:   8] 0x48:   1611fff9        bne     s0,s1,0x30	#
  [loop.c:   8] 0x4c:   00000000        nop			# end loop
  [loop.c:  10] 0x50:   8fbf0024        lw      ra,36(sp)
  [loop.c:  10] 0x54:   8fb00018        lw      s0,24(sp)
  [loop.c:  10] 0x58:   8fb1001c        lw      s1,28(sp)
  [loop.c:  10] 0x5c:   03e00008        jr      ra
  [loop.c:  10] 0x60:   27bd0028        addiu   sp,sp,40
  0x64: 00000000        nop
  0x68: 00000000        nop
  0x6c: 00000000        nop

# In loop2.c we try using a function pointer.
# This effectively guarantees to the compiler that the name will not
# be re-resolved.

9 gischer@puget: cat loop2.c
::::::::::::::
loop2.c
::::::::::::::
extern float v3f(float *);

float *pts[100];

void loop() {
    int i;
    float (*vptr)(float *);
    
    vptr = v3f;
    for (i=1; i<100; i++) {
        (*vptr)(pts[i]);
    }
}
    
10 gischer@puget: cc -c -O loop2.c
11 gischer@puget: dis loop2.o > loop2.o.dis;  cat loop2.o.dis
::::::::::::::
loop2.o.dis
::::::::::::::
        loop:
  [loop2.c:   5] 0x0:   3c1c0000        lui     gp,0
  [loop2.c:   5] 0x4:   279c0000        addiu   gp,gp,0
  [loop2.c:   5] 0x8:   0399e021        addu    gp,gp,t9
  [loop2.c:   5] 0xc:   27bdffd8        addiu   sp,sp,-40
  [loop2.c:   5] 0x10:  afb2001c        sw      s2,28(sp)
  [loop2.c:   5] 0x14:  afb00014        sw      s0,20(sp)
  [loop2.c:  10] 0x18:  8f900000        lw      s0,0(gp)
  [loop2.c:  10] 0x1c:  8f920000        lw      s2,0(gp)
  [loop2.c:   5] 0x20:  afb10018        sw      s1,24(sp)
  [loop2.c:  10] 0x24:  8f910000        lw      s1,0(gp)
  [loop2.c:   5] 0x28:  afbf0024        sw      ra,36(sp)
  [loop2.c:   5] 0x2c:  afbc0020        sw      gp,32(sp)
  [loop2.c:  10] 0x30:  26100004        addiu   s0,s0,4
  [loop2.c:  10] 0x34:  26520190        addiu   s2,s2,400
  [loop2.c:  11] 0x38:  8e040000        lw      a0,0(s0)	# start loop
  [loop2.c:  11] 0x3c:  0220f809        jalr    ra,s1		#
  [loop2.c:  11] 0x40:  0220c825        or      t9,s1,zero	#
  [loop2.c:  11] 0x44:  8fbc0020        lw      gp,32(sp)	#
  [loop2.c:  11] 0x48:  26100004        addiu   s0,s0,4		#
  [loop2.c:  11] 0x4c:  1612fffa        bne     s0,s2,0x38	#
  [loop2.c:  11] 0x50:  00000000        nop			# end loop
  [loop2.c:  13] 0x54:  8fbf0024        lw      ra,36(sp)
  [loop2.c:  13] 0x58:  8fb00014        lw      s0,20(sp)
  [loop2.c:  13] 0x5c:  8fb10018        lw      s1,24(sp)
  [loop2.c:  13] 0x60:  8fb2001c        lw      s2,28(sp)
  [loop2.c:  13] 0x64:  03e00008        jr      ra
  [loop2.c:  13] 0x68:  27bd0028        addiu   sp,sp,40
  0x6c: 00000000        nop


# Finally, we hand-unroll the loop.

12 gischer@puget: cat loop3.c
::::::::::::::
loop3.c
::::::::::::::
extern float v3f(float *);

float *pts[100];

void loop() {
    register int i;
    register float (*vptr)(float *);
    
    vptr = v3f;
    for (i=1; i<100; i=i+4) {
        (*vptr)(pts[i]);
        (*vptr)(pts[i+1]);
        (*vptr)(pts[i+2]);
        (*vptr)(pts[i+3]);
    }
}

13 gischer@puget: cc -c -O loop3.c
14 gischer@puget: dis loop3.o > loop3.o.dis;  cat loop3.o.dis
::::::::::::::
loop3.o.dis
::::::::::::::
        loop:
  [loop3.c:   5] 0x0:   3c1c0000        lui     gp,0
  [loop3.c:   5] 0x4:   279c0000        addiu   gp,gp,0
  [loop3.c:   5] 0x8:   0399e021        addu    gp,gp,t9
  [loop3.c:   5] 0xc:   27bdffd8        addiu   sp,sp,-40
  [loop3.c:   5] 0x10:  afb2001c        sw      s2,28(sp)
  [loop3.c:   5] 0x14:  afb00014        sw      s0,20(sp)
  [loop3.c:  10] 0x18:  8f900000        lw      s0,0(gp)
  [loop3.c:  10] 0x1c:  8f920000        lw      s2,0(gp)
  [loop3.c:   5] 0x20:  afb10018        sw      s1,24(sp)
  [loop3.c:  10] 0x24:  8f910000        lw      s1,0(gp)
  [loop3.c:   5] 0x28:  afbf0024        sw      ra,36(sp)
  [loop3.c:   5] 0x2c:  afbc0020        sw      gp,32(sp)
  [loop3.c:  10] 0x30:  26100004        addiu   s0,s0,4
  [loop3.c:  10] 0x34:  26520194        addiu   s2,s2,404
  [loop3.c:  11] 0x38:  8e040000        lw      a0,0(s0)	# start loop
  [loop3.c:  11] 0x3c:  0220f809        jalr    ra,s1		#
  [loop3.c:  11] 0x40:  0220c825        or      t9,s1     	#
  [loop3.c:  11] 0x44:  8fbc0020        lw      gp,32(sp)	#
  [loop3.c:  12] 0x48:  8e040004        lw      a0,4(s0)	# 5
  [loop3.c:  12] 0x4c:  0220f809        jalr    ra,s1		#
  [loop3.c:  12] 0x50:  0220c825        or      t9,s1     	#
  [loop3.c:  12] 0x54:  8fbc0020        lw      gp,32(sp)	#
  [loop3.c:  13] 0x58:  8e040008        lw      a0,8(s0)	#
  [loop3.c:  13] 0x5c:  0220f809        jalr    ra,s1		# 10
  [loop3.c:  13] 0x60:  0220c825        or      t9,s1     	#
  [loop3.c:  13] 0x64:  8fbc0020        lw      gp,32(sp)	#
  [loop3.c:  14] 0x68:  8e04000c        lw      a0,12(s0)	#
  [loop3.c:  14] 0x6c:  0220f809        jalr    ra,s1		#
  [loop3.c:  14] 0x70:  0220c825        or      t9,s1     	# 15
  [loop3.c:  14] 0x74:  8fbc0020        lw      gp,32(sp)	#
  [loop3.c:  14] 0x78:  26100010        addiu   s0,s0,16	#
  [loop3.c:  14] 0x7c:  1612ffee        bne     s0,s2,0x38	#
  [loop3.c:  14] 0x80:  00000000        nop			# end loop
  [loop3.c:  16] 0x84:  8fbf0024        lw      ra,36(sp)
  [loop3.c:  16] 0x88:  8fb00014        lw      s0,20(sp)
  [loop3.c:  16] 0x8c:  8fb10018        lw      s1,24(sp)
  [loop3.c:  16] 0x90:  8fb2001c        lw      s2,28(sp)
  [loop3.c:  16] 0x94:  03e00008        jr      ra
  [loop3.c:  16] 0x98:  27bd0028        addiu   sp,sp,40
  0x9c: 00000000        nop


# CASE 5
#
# Handling platform-dependent configurations
#
::::::::::::::
Makefile
::::::::::::::
default: main1 main2 main3 layer1

main1: main.o subdirs
        cc -o main1 main.o -L./platformA -lZ

main2: main.o subdirs
        cc -o main2 main.o -L./platformA -lZ -no_transitive_link

main3: main.o subdirs
        cc -o main3 main.o -L./platformB -lZ

layer1: wrapper.so 
        cc -o layer1 main.o wrapper.so -L./platformA

wrapper.so: wrapper.o subdirs
        ld -shared wrapper.o -L./platformA -lZ \
        -no_transitive_link -o wrapper.so

subdirs:
        (cd platformA; make)
        (cd platformB; make)
::::::::::::::
main.c
::::::::::::::
#include <stdio.h>

main() {
    printf("Entering Main\n");
    z();
    printf("Leaving Main\n");
}

#
# Platform A implementation of libZ.so depends on libZZ.so

::::::::::::::
Makefile
::::::::::::::
default: libZ.so

libZ.so: libZZ.so Z.o
        ld -shared Z.o libZZ.so -o libZ.so

libZZ.so: ZZ.o
        ld -shared ZZ.o -o libZZ.so

clobber: clean
        rm *.so
clean:
        rm *.o
::::::::::::::
Z.c
::::::::::::::
#include <stdio.h>
extern void zz(void);

#pragma weak z = _z

void _z() {
    printf("Entering object Z.so\n");
    zz();
    printf("Leaving object Z.so\n");
}
::::::::::::::
ZZ.c
::::::::::::::
#include <stdio.h>

void zz() {
    printf("Entering object ZZ.so\n");
    printf("Leaving object ZZ.so\n");
}

407 gischer@puget: make  
        cc -O -c ZZ.c
        ld -shared ZZ.o -o libZZ.so
        cc -O -c Z.c
        ld -shared Z.o libZZ.so -o libZ.so
408 gischer@puget: ls
Makefile       Z.o            ZZ.o           libZZ.so
Z.c            ZZ.c           libZ.so        so_locations
409 gischer@puget: elfdump -Dl libZ.so


                        ***LIBRARY LIST SECTION***
        Name         Time-Stamp           CheckSum   Flags Version
.liblist
        libZZ.so     Aug  2 15:13:04 1993 0x798421d1  NONE 


# =================================================================
# PlatformB has no such dependency and doesn't implement libZZ.so
#

::::::::::::::
Makefile
::::::::::::::
default: libZ.so

libZ.so: Z.o
        ld -shared Z.o -o libZ.so

clobber: clean
        rm *.so
clean:
        rm *.o
::::::::::::::
Z.c
::::::::::::::
#include <stdio.h>

#pragma weak z=_z

void _z() {
    printf("Entering object Z.so\n");
    printf("Leaving object Z.so\n");
}

416 gischer@puget: make 
        cc -O -c Z.c
        ld -shared Z.o -o libZ.so
417 gischer@puget: ls
Makefile       Z.c            Z.o            libZ.so        so_locations
418 gischer@puget: elfdump -Dl libZ.so

#
# Now main, built on platformA, will not run correctly on platformB
#
426 gischer@puget: make -un main1
        cc -O -c main.c
        (cd platformA; make)
        (cd platformB; make)
        cc -o main1 main.o -L./platformA -lZ
427 gischer@puget: setenv LD_LIBRARY_PATH ./platformA
428 gischer@puget: main1
Entering Main
Entering object Z.so
Entering object ZZ.so
Leaving object ZZ.so
Leaving object Z.so
Leaving Main
429 gischer@puget: setenv LD_LIBRARY_PATH ./platformB
430 gischer@puget: main1
15222:main1: rld: Fatal Error: cannot map libZZ.so under path (./platformB/libZZ.so:/lib/libZZ.so:/usr/lib/libZZ.so:/lib/cmplrs/cc/libZZ.so:/usr/lib/cmplrs/cc/libZZ.so:) 


#
# So we can use -no_transitive_link to fix this.  First, when building main:n
#

431 gischer@puget: make -un main2
        cc -O -c main.c
        (cd platformA; make)
        (cd platformB; make)
        cc -o main2 main.o -L./platformA -lZ -no_transitive_link
432 gischer@puget: setenv LD_LIBRARY_PATH ./platformA
433 gischer@puget: main2
Entering Main
Entering object Z.so
Entering object ZZ.so
Leaving object ZZ.so
Leaving object Z.so
Leaving Main
434 gischer@puget: setenv LD_LIBRARY_PATH ./platformB
435 gischer@puget: main2
Entering Main
Entering object Z.so
Leaving object Z.so
Leaving Main

#
# We can duck the issue by building on platformB
# This isn't recommended.
#
438 gischer@puget: make main3
        (cd platformA; make)
        (cd platformB; make)
        cc -o main3 main.o -L./platformB -lZ
439 gischer@puget: setenv LD_LIBRARY_PATH ./platformA
440 gischer@puget: main3
Entering Main
Entering object Z.so
Entering object ZZ.so
Leaving object ZZ.so
Leaving object Z.so
Leaving Main
441 gischer@puget: setenv LD_LIBRARY_PATH ./platformB
442 gischer@puget: main3
Entering Main
Entering object Z.so
Leaving object Z.so
Leaving Main


#
# Finally, we can hide this in the library by using a wrapper.
# This also makes use of weak symbols
#
::::::::::::::
wrapper.c
::::::::::::::
#include <stdio.h>

extern void _z(void);

void z() {
    printf("Entering wrapper\n");
    _z();
    printf("Leaving wrapper\n");
}

443 gischer@puget: make layer1
        (cd platformA; make)
        (cd platformB; make)
        ld -shared wrapper.o -L./platformA -lZ \
        -no_transitive_link -o wrapper.so
        cc -o layer1 main.o wrapper.so -L./platformA
444 gischer@puget: setenv LD_LIBRARY_PATH :.:./platformA:
445 gischer@puget: layer1
Entering Main
Entering wrapper
Entering object Z.so
Entering object ZZ.so
Leaving object ZZ.so
Leaving object Z.so
Leaving wrapper
Leaving Main
446 gischer@puget: setenv LD_LIBRARY_PATH :.:./platformB
447 gischer@puget: layer1
Entering Main
Entering wrapper
Entering object Z.so
Leaving object Z.so
Leaving wrapper
Leaving Main



#
# CASE 6
#
# This case shows how shared objects can reduce the redundancy of
# some link lines because of the different linking semantics of DSO
# vs. archives.

::::::::::::::
Makefile
::::::::::::::
default: test2 test3

libA.a: f1.o f3.o
        ar r libA.a f1.o f3.o

libB.a: f2.o
        ar r libB.a f2.o

libA.so: libA.a
        ld -shared -all libA.a -o libA.so

libB.so: libB.a
        ld -shared -all libB.a -o libB.so

# This build will fail due to an unresolved variable
#
test1: test.o libA.a libB.a
        cc test.o libA.a libB.a -o test1

# This build works, showing the need to name the same archive more than
# once on a link line.
#
test2: test.o libA.a libB.a
        cc test.o libA.a libB.a libA.a -o test2

# Such multiple listings are unnecessary with shared objects, as seen in
# the following
#
test3: test.o libA.so libB.so
        cc test.o libA.so libB.so -o test3

clean:
        rm -rf *.o

clobber: clean
        rm -rf *.so *.a test1 test2 test3

::::::::::::::
f1.c
::::::::::::::
#include <stdio.h>

extern void f2(void);

void f1(void) {
    printf("Entering f1\n");
    f2();
    printf("Exiting f1\n");
}
::::::::::::::
f2.c
::::::::::::::
#include <stdio.h>

extern void f3(void);

void f2(void) {
    printf("Entering f2\n");
    f3();
    printf("Leaving f2\n");
}

::::::::::::::
f3.c
::::::::::::::
#include <stdio.h>

void f3(void) {
    printf("This is f3\n");
}
::::::::::::::
test.c
::::::::::::::
#include <stdio.h>

extern void f1(void);

main() {
    f1();
}

#
# With archive linking semantics it is sometimes necessary to
# mention libraries more than once on the link line.
#
455 gischer@puget: make test1
        cc -O -c test.c
        cc -O -c f1.c
        cc -O -c f3.c
        ar r libA.a f1.o f3.o
ar: Warning: creating libA.a
        cc -O -c f2.c
        ar r libB.a f2.o
ar: Warning: creating libB.a
        cc test.o libA.a libB.a -o test1
ld:
Unresolved:
f3
*** Error code 1 (bu21)

make: fatal error.
456 gischer@puget: make test2
        cc test.o libA.a libB.a libA.a -o test2
#
# Much of this need is eliminated by the use of shared objects
#
457 gischer@puget: make test3
        ld -shared -all libA.a -o libA.so
        ld -shared -all libB.a -o libB.so
        cc test.o libA.so libB.so -o test3
458 gischer@puget: test2
Entering f1
Entering f2
This is f3
Leaving f2
Exiting f1
459 gischer@puget: test3
Entering f1
Entering f2
This is f3
Leaving f2
Exiting f1


# CASE 7
#
# Speeding the development cycle by reducing build/link time.
#
# Avoid relinking everything by putting the bulk of code into a shared
# object and preempting selected portions.
::::::::::::::
Makefile
::::::::::::::
default: main1 

main1: bigthing.so main.o
        cc main.o bigthing.so -Wl,-rpath,`pwd` -o main1

bigthing.so: bigthing.o
        ld -shared bigthing.o -o bigthing.so

main2: bigthing.so newthing.so main.o
        cc main.o newthing.so bigthing.so -Wl,-rpath,`pwd` -o main2

newthing.so: newthing.o
        ld -shared newthing.o -o newthing.so
::::::::::::::
bigthing.c
::::::::::::::
/* This file simulates a giant shared object.  In real life
 * there would be many source files and many object files used
 * to build the object.
 */

#include <stdio.h>

void func1() {
    printf("This is the old func1.\n\n");
}

void func2() {
    printf("This is the old func2, which is buggy.\n\n");
}

void func3() {
    printf("This is the old func3, which calls func2.\n");
    func2();
}
::::::::::::::
main.c
::::::::::::::
#include <stdio.h>

extern void func1(void);
extern void func2(void);
extern void func3(void);

main() {
    func1();
    func2();
    func3();
}

#
# Build bigthing in nightly build or some such; test.
#
466 gischer@puget: make 
        cc -O -c bigthing.c
        ld -shared bigthing.o -o bigthing.so
        cc -O -c main.c
        cc main.o bigthing.so -Wl,-rpath,`pwd` -o main1
467 gischer@puget: main1
This is the old func1.

This is the old func2, which is buggy.

This is the old func3, which calls func2.
This is the old func2, which is buggy.
#
# As bugs are discovered rebuild small objects and link them in
# as shared objects, preempting the functions in the big thing.
#
::::::::::::::
newthing.c
::::::::::::::
#include <stdio.h>

void func2() {
    printf("This is the new func2, which is fixed.\n\n");
}

469 gischer@puget: make main2
        cc -O -c newthing.c
        ld -shared newthing.o -o newthing.so
        cc main.o newthing.so bigthing.so -Wl,-rpath,`pwd` -o main2
470 gischer@puget: main2
This is the old func1.

This is the new func2, which is fixed.

This is the old func3, which calls func2.
This is the new func2, which is fixed.


#
# CASE 8
#
# Using dlopen(), dlsym(), dlerror() to configure software at runtime.
#
# The following example is based on languages but is not the
# recommended method for internationalization.
#
::::::::::::::
Makefile
::::::::::::::
default: main english.so french.so spanish.so german.so

main: main.o
        cc main.o -ldl -Wl,-rpath,`pwd` -o main

english.so: english.o
        ld -shared english.o -o english.so

french.so: french.o
        ld -shared french.o -o french.so

spanish.so: spanish.o
        ld -shared spanish.o -o spanish.so

german.so: german.o
        ld -shared german.o -o german.so


::::::::::::::
main.c
::::::::::::::
#include <dlfcn.h>
#include <stdio.h>


main() {
    char choice;
    void *handle;
    void (*msg)(int);

    printf("What language would you like your messages in?\n\n");
    printf("   1: English\n\n");
    printf("   2: Spanish\n\n");
    printf("   3: German\n\n");
    printf("   4: French\n\n");

    scanf("%c", &choice);

    switch (choice) {
    case '1':
        handle = dlopen("english.so", RTLD_LAZY);
        break;

    case '2':
        handle = dlopen("spanish.so", RTLD_LAZY);
        break;

    case '3':
        handle = dlopen("german.so", RTLD_LAZY);
        break;

    case '4':
        handle = dlopen("french.so", RTLD_LAZY);
        break;

    }   

    if (handle == NULL) {
        fprintf(stderr, "%s\n", dlerror());
        exit(1);
    }

    msg =  dlsym(handle, "message");
    if (msg == NULL) {
        fprintf(stderr, "%s\n", dlerror());
        exit(2);
    }

    (*msg)(1);
    
    (void) getc(stdin);
}

::::::::::::::
english.c
::::::::::::::
#include <stdio.h>

void message() {
    printf("Give Jay a raise!\n");
}
::::::::::::::
french.c
::::::::::::::
#include <stdio.h>

void message() {
    printf("Donnez une augmentacion a Wilson!\n");
}
::::::::::::::
german.c
::::::::::::::
#include <stdio.h>

void message() {
    printf("Geben Sie Lilian mehr geld!\n");
}
::::::::::::::
spanish.c
::::::::::::::
#include <stdio.h>

void message() {
    printf("Da le un aumente de sueldo a Sun.\n");
}

Files of interest from "src/swtools/DSOs/forum93" directory

Documentation

Subdirectories


Select any combo of files you'd like to send yourself a compressed tar image of. Executables/scripts are indicated with a trailing `*' character. (Depending upon the browser, it may be necessary to hold down the Ctrl key to select/deselect disjoint items.) a compressed tar image of the above-selected items.
OR, ...
a compressed tar image of the entire forum93 directory.

Copyright © 1995, Silicon Graphics, Inc.