This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

MIPS asm prologue macros


Hi!

The "MIPSpro(TM) N32 ABI Handbook" shows an attached code (slightly
cleaned up by me) to explain how to write assembly for ABIs
({O,N}{32,64}).  The start of a sample assembly function looks like:

NESTED(asmfunc, FRAMESZ, ra)
	move	t0, gp	# save entering gp
			# SIM_ABI64 has gp callee save
			# no harm for SIM_ABI32
	SETUP_GPX(t8)
	PTR_SUBU sp, FRAMESZ
	SETUP_GP64(GPOFF, asmfunc)
	SAVE_GP(GPOFF)
	:

Questions:

- I'm not sure where / when the t0 value is restored into GP.

- Has anyone invented any macros which can handle all the four ABI
  cases cleanly?

Masao
Using a Different Subroutine Linkage
------------------------------------

Under n32, more registers are used to pass arguments to called
subroutines.  The registers that are saved by the calling and called
subroutines are also different under this convention, which is
described in detail in Chapter 2, "Calling Convention
Implementations", page 5.  As a result, a different register naming
convention exists.  The compiler predefines _MIPS_SIM and this enables
macros in <sys/asm.h> and <sys/regdef.h>.  Some important
ramifications of the subroutine linkage convention are outlined in the
following.

The _MIPS_SIM_NABI32 model (n32), defines four additional argument
registers for a total of eight argument registers: $4..$11.  The
additional four argument registers come at the expense of the temp
registers in <sys/regdef.h>.  In this model, there are no registers
t4..t7, so any code using these registers does not compile under this
model.  Similarly, the register names a4..a7 are not available under
the _MIPS_SIM_ABI32 model.  (Note that those temporary registers are
not lost; the argument registers can serve as scratch registers also,
with certain constraints.)

To make it easier to convert assembler code, the new names ta0, ta1,
ta2, and ta3 are available under both _MIPS_SIM models.  These alias
with t4..t7 in the o32 ABI, and with a4..a7 in the n32 ABI.

Another facet of the linkage convention is that the caller no longer
has to reserve space for a called function in which to store its
arguments.  The called routine allocates space for storing its
arguments on its own stack, if desired.  The NARGSAVE define in
<sys/asm.h> helps with this.  The following example handles assembly
language coding issues for n32 and KPIC (KPIC requires that the asm
coder deals with PIC issues).  It creates a template for the start and
end of a generic assembly language routine.  The template is followed
by relevant defines and macros from <sys/asm.h>.

#include <sys/regdef.h>
#include <sys/asm.h>
#include <sys/fpregdef.h>

LOCALSZ= 7 # save gp ra and any other needed registers
/* For this example 7 items are saved on the stack */
/* To access the appropriate item use the offsets below */
FRAMESZ=	(((NARGSAVE + LOCALSZ) * SZREG) + ALSZ) & ALMASK
RAOFF=		FRAMESZ - (1 * SZREG)
GPOFF=		FRAMESZ - (4 * SZREG)
A0OFF=		FRAMESZ - (5 * SZREG)
A1OFF=		FRAMESZ - (6 * SZREG)
T0OFF=		FRAMESZ - (7 * SZREG)

NESTED(asmfunc, FRAMESZ, ra)
	move	t0, gp	# save entering gp
			# SIM_ABI64 has gp callee save
			# no harm for SIM_ABI32
	SETUP_GPX(t8)
	PTR_SUBU sp, FRAMESZ
	SETUP_GP64(GPOFF, asmfunc)
	SAVE_GP(GPOFF)
/* Save registers as needed here */
	REG_S	ra, RAOFF(sp)
	REG_S	a0, A0OFF(sp)
	REG_S	a1, A1OFF(sp)
	REG_S	t0, T0OFF(sp)

/* do real work here */
/* safe to call other functions */

/* restore saved regsisters as needed here */
	REG_L	ra, RAOFF(sp)
	REG_L	a0, A0OFF(sp)
	REG_L	a1, A1OFF(sp)
	REG_L	t0, T0OFF(sp)

/* setup return address, $gp and stack pointer */
	REG_L	ra, RAOFF(sp)
	RESTORE_GP64
	PTR_ADDU sp, FRAMESZ
	bne	v0, zero, err
	j ra
END(asmfunc)

/*
 * The following macro definitions are
 * from /usr/include/sys/asm.h */
 */

#if (_MIPS_SIM == _MIPS_SIM_ABI32)

/*
 * Set gp when at 1st instruction
 */

#define SETUP_GP						\
	.set	noreorder;					\
	.cpload	t9;						\
	.set	reorder

/* Set gp when not at 1st instruction */
#define SETUP_GPX(tmp)						\
	.set	noreorder;					\
	move	tmp, ra;	/* save old ra */		\
	bal	10f;		/* find addr of cpload */	\
	 nop;							\
10:	.cpload	ra;						\
	move	ra, tmp;					\
	.set	reorder;

#define SETUP_GPX_L(tmp, l)					\
	.set	noreorder;					\
	move	tmp, ra;	/* save old ra */		\
	bal	l;		/* find addr of cpload */	\
	 nop;							\
l:	.cpload	ra;						\
	move	ra, tmp;					\
	.set	reorder;

#define SAVE_GP(x) \
	.cprestore x;	/* save gp trigger t9/jalr conversion */

#define SETUP_GP64(offset, func)
#define SETUP_GPX64(offset, tmp)
#define SETUP_GPX64_L(offset, tmp, l)
#define RESTORE_GP64
#define USE_ALT_CP(reg)

#else /* (_MIPS_SIM == _MIPS_SIM_ABI64) || (_MIPS_SIM == _MIPS_SIM_NABI32) */

/*
 * For callee-saved gp calling convention:
 */

#define SETUP_GP
#define SETUP_GPX(tmp)
#define SETUP_GPX_L(tmp, l)
#define SAVE_GP(x)

#define SETUP_GP64(offset, func) \
	.cpsetup t9, offset, func

#define SETUP_GPX64(offset, tmp)				\
	move	tmp, ra;	/* save old ra */		\
	.set	noreorder;					\
	bal	10f;		/* find addr of .cpsetup */	\
	 nop;							\
10:	.set	reorder;					\
	.cpsetup ra, offset, 10b;				\
	move	ra, tmp

#define SETUP_GPX64_L(offset, tmp, l)				\
	move	tmp, ra;	/* save old ra */		\
	.set	noreorder;					\
	bal	l;		/* find addr of .cpsetup */	\
	 nop;							\
l:	.set	reorder;					\
	.cpsetup ra, offset, l;					\
	move	ra, tmp

#define RESTORE_GP64 \
	.cpreturn

#define USE_ALT_CP(reg) \
	.cplocal	reg	/* use alternate register for context pointer */

#endif /* _MIPS_SIM != _MIPS_SIM_ABI32 */

/*
 * Stack Frame Definitions
 */

#if (_MIPS_SIM == _MIPS_SIM_ABI32)
#define NARGSAVE	4	/* space for 4 arg regs must be alloc*/
#endif

#if (_MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32)
#define NARGSAVE	0	/* no caller responsibilities */
#endif

#define ALSZ		15	/* align on 16 byte boundary */
#define ALMASK		(~0xf)

#if (_MIPS_ISA == _MIPS_ISA_MIPS1 || _MIPS_ISA == _MIPS_ISA_MIPS2)
#define SZREG		4
#endif

#if (_MIPS_ISA == _MIPS_ISA_MIPS3 || _MIPS_ISA == _MIPS_ISA_MIPS4)
#define SZREG		8
#endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]