Since get_gp() is a leaf routine that is linked in the same DSO where it is called, no changes are required to port it to n32. However, you have to recompile it.
On the other hand, regs() requires a lot of work. The issues that need to be addressed are detailed below.
The n32 ABI, on the other hand, follows the convention that $gp is callee saved. This means that $gp is saved at the beginning of each routine and restored right before that routine itself returns. This is accomplished through the use of .cpsetup, an assembler pseudo instruction.
The recommended way to deal with these various pseudo instructions is to use the macros provided in <sys/asm.h>. The macros below will provide correct use of these pseudo instructions whether compiled for o32 or for n32.
Argument | o32 | n32 |
---|---|---|
argument1 | a0 | a0 |
argument2 | a1 | a1 |
argument3 | a2 | a2 |
argument4 | $sp+16 | $f15 |
argument5 | $sp+24 | a4 |
argument6 | $sp+28 | a5 |
Note: Under o32, there are no a4 and a5 registers, but under n32 they must be saved on the stack because they are used after calls to an external function. The code fragment that illustrates accessing the arguments under n32 is shown below:
mov.d $f4,$f15 # 5th argument in 5th fp # arg. register l.d $f6,0(a4) # fourth argument in # fourth arg. register s.d $f8,0(a5) # save in 6th arg. reg
/* regs.s */ #include <sys/regdef.h> #include <sys/asm.h> .text LOCALSZ=5 # save ra, a4, a5, gp, $f15 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK RAOFF=FRAMESZ-(1*SZREG) # stack offset where ra is saved A4OFF=FRAMESZ-(2*SZREG) # stack offset where a4 is saved A5OFF=FRAMESZ-(3*SZREG) # stack offset where a5 is saved GPOFF=FRAMESZ-(4*SZREG) # stack offset where gp is saved FPOFF=FRAMESZ-(5*SZREG) # stack offset where $f15 is # saved # a4, a5, and $f15 don't have to # be saved, but no harm done in # doing so NESTED(regs, FRAMESZ, ra) # define regs to be a nested # function SETUP_GP # used for caller saved gp PTR_SUBU sp,FRAMESZ # setup stack frame SETUP_GP64(GPOFF, regs) # used for callee saved gp SAVE_GP(GPOFF) # used for caller saved gp REG_S ra, RAOFF(sp) # save ra on stack #if (_MIPS_SIM != _MIPS_SIM_ABI32) # not needed for o32 REG_S a4, A4OFF(sp) # save a4 on stack (argument 4) REG_S a5, A5OFF(sp) # save a5 on stack (argument 5) s.d $f15,FPOFF(sp) # save $f15 on stack (argument 6) #endif /* _MIPS_SIM != _MIPS_SIM_ABI32 */ 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 malloc jal malloc # for illustration purposes only move a0, v0 # call free jal free # go into libc.so twice # this is why a4, a5, $f15 # had to be saved #if (_MIPS_SIM != _MIPS_SIM_ABI32) # not needed for o32 l.d $f15,FPOFF(sp) # restore $f15 (argument #6) REG_L a4, A4OFF(sp) # restore a4 (argument #4) REG_L a5, A5OFF(sp) # restore a5 (argument #5) #endif /* _MIPS_SIM != _MIPS_SIM_ABI32 */ #if (_MIPS_SIM == _MIPS_SIM_ABI32) # for o32 arguments will # need to be pulled from the # stack lw t0,FRAMESZ+24(sp) # fifth argument is 24 # relative to original sp l.d $f4,0(t0) # use l.d for correct code # on both mips1 & mips2 l.d $f6,FRAMESZ+16(sp) # fourth argument is 16 # relative to original sp add.d $f8, $f4, $f6 # do the calculation lw t0,FRAMESZ+28(sp) # sixth argument is 28 # relative to original sp s.d $f8,0(t0) # save the result there #else # n32 args are in regs mov.d $f4,$f15 # 5th argument in 5th fp # arg. register l.d $f6,0(a4) # fourth argument in # fourth arg. register add.d $f8, $f4, $f6 # do the calculation s.d $f8,0(a5) # save in 6th arg. reg #endif /* _MIPS_SIM != _MIPS_SIM_ABI32 */ REG_L ra, RAOFF(sp) # restore return address RESTORE_GP64 # restore gp for n32 # (callee saved) PTR_ADDU sp,FRAMESZ # pop stack j ra # return to caller .endregs