Next | Prev | Up | Top | Contents | Index

An Example Application

An examination of the following application, app1, illustrates the steps necessary to port from o32 to n32. As you can see, app1 is trivial in functionality, but it is constructed to point out several of the issues involved in converting code from o32 to n32.

App1 contains the following files:

Figure 4-1 shows a call tree is for the app1 program. It illustrates that main() calls get_gp(), foo() and printf(). The function foo() calls regs() and printf(), while regs() calls malloc() and free(). The figure also shows that app1 is linked against two shared objects, libc.so and regs.so.

Figure 4-1 : Call Tree for App1 The source code for the original versions of main.c, foo.c, gp.s. and regs.s are shown below.

/* main.c */
extern void foo();

main()
{
   unsigned gp,ra,sp, get_regs();
   double d1 = 1.0;
   double d2 = 2.0;
   double res;

   gp = get_gp();
   printf("gp is 0x%x\n", gp);
   foo(7, 3.14, &gp, &ra, 
       &sp, d1, &d2, &res);
}

/* foo.c */

#include <stdarg.h>

void foo(int narg, ...)
{
  va_list ap;
  double d1;
  double daddr1, *daddr2, *resaddr; 
  unsigned *gp, *ra, *sp;

  va_start(ap, narg);
  printf("Number of Arguments is: %d\n",narg);

  d1 = va_arg(ap, double);
  printf("%e\n",d1);

  gp = va_arg(ap, unsigned*);
  ra = va_arg(ap, unsigned*);
  sp = va_arg(ap, unsigned*);

  daddr1 = va_arg(ap, double);
  daddr2 = va_arg(ap, double*);
  resaddr = va_arg(ap, double*);

  printf("first  double precision argument is %e\n",daddr1);
  printf("second double precision argument is %e\n",*daddr2);

  regs(gp, ra, sp, daddr1, daddr2, resaddr);
  printf("Back from assembly routine\n");
  printf("gp is 0x%x\n",*gp);
  printf("ra is 0x%x\n",*ra);
  printf("sp is 0x%x\n",*sp);
  printf("result of double precision add is %e\n",*resaddr);

  va_end(ap);
}

/* gp.s */
#include <regdef.h>
#include <asm.h>

LEAF(get_gp)
        move  v0, gp
        j     ra
        .end  get_gp

/* regs.s */
#include <regdef.h>

        .text
        .globlregs          # make regs external
        .entregs 2
regs:
        .set noreorder
        .cploadt9           # setup gp
        .set reorder
        subu   sp, 32       # create stack frame
        sw     ra, 28(sp)   # save return address
        .cprestore     24   # for caller saved gp 
                            # save gp 24(sp)
        sw     gp, 0(a0)    # return gp in first arg
        sw     ra, 0(a1)    # return ra in second arg
        sw     sp, 0(a2)    # return sp in third arg

        li     a0, 1000     # call libc routines
        jal    malloc       # for illustrative purposes
        move   a0, v0       # to make regs
        jal    free         # a nested function

        lw     t0, 56(sp)   # get fifth argument from stack
        lwc1   $f4, 4(t0)   # load it in fp register
        lwc1   $f5, 0(t0)   # fp values are stored in LE  
                            # format
        lwc1   $f6, 52(sp)  # get fourth argument from stack
        lwc1   $f7, 48(sp)  # fp values are stored in LE
                            # format

        add.d  $f8, $f4, $f6  # do the calculation
        lw     t0, 60(sp)     # get the sixth argument
                              # from the stack
        swc1   $f8, 4(t0)     # save the result
        swc1   $f9, 0(t0)     # fp values are stored in LE

    lw     ra, 28(sp)     # get return address
    addu   sp, 32         # pop stack
    j      ra             # return to caller
    .end regs


Next | Prev | Up | Top | Contents | Index