Source to EXTERNAL_HEADERS/architecture/ppc/asm_help.h
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/* Copyright (c) 1996 NeXT Software, Inc. All rights reserved.
*
* File: architecture/ppc/asm_help.h
* Author: Mike DeMoney, NeXT Software, Inc.
*
* This header file defines macros useful when writing assembly code
* for the PowerPC processors.
* r12 is used as the tmp register / PICIFY base.
*
* HISTORY
* 20-May-97 Umesh Vaishampayan ([email protected])
* Implemented Dynamic / PIC macros.
*
* 28-Dec-96 Umesh Vaishampayan ([email protected])
* added ".align" directive to various macros to avoid alignment
* faults. Moved Register Usage #defines to reg_help.h as that's
* where they should have been in the first place.
* Added Dynamic / PIC macroes for routines which refernce external
* symbols. Not implemented fully as yet.
*
* 05-Nov-92 Mike DeMoney ([email protected])
* Created.
*/
#ifndef _ARCH_PPC_ASM_HELP_H_
#define _ARCH_PPC_ASM_HELP_H_
#import <architecture/ppc/reg_help.h>
#ifdef __ASSEMBLER__
/*
* ppc stack frames look like this after procedure prolog has
* been executed:
*
* Higher address:
* .........
* +-------------------------------+
* | caller's LR |
* +-------------------------------+
* | caller's CR |
* +-------------------------------+
* Caller's SP->| caller's caller's sp | ^^ Caller's Frame ^^
* +===============================+ vv Called Rtn Frame vv
* | Save Area for | FPF 31
* ..........
* | Caller's FPF's | FPF n
* +-------------------------------+
* | Save Area for | GRF 31
* ..........
* | Caller's GRF's | GRF n
* +-------------------------------+
* | alignment pad |
* ............
* | (if necessary) |
* +-------------------------------+
* | Local |
* ........
* | Variables |
* +-------------------------------+
* SP + X -> | aN for FUTURE call |
* +-------------------------------+
* ..........
* +-------------------------------+
* SP + 28 -> | a1 for FUTURE call |
* +-------------------------------+
* SP + 24 -> | a0 for FUTURE call |
* +-------------------------------+
* SP + 20 -> | caller's TOC |
* +-------------------------------+
* SP + 16 -> | reserved |
* +-------------------------------+
* SP + 12 -> | reserved |
* +-------------------------------+
* SP + 8 -> | LR callee-save for FUTURE call|
* +-------------------------------+
* SP + 4 -> | CR callee-save for FUTURE call|
* +-------------------------------+
* SP -> | caller's sp |
* +===============================+
* Lower address:
*
* NOTE: All state with the exception of LR and CR are saved in the
* called routines frame. LR and CR are saved in the CALLER'S FRAME.
*
* ALSO NOTE: Args to the called routine are found in the caller's frame.
*/
/*
* ARG(n) -- stack offset to n'th argument
*
* NOTE CAREFULLY! These macros start numbering arguments at 1 (NOT 0)
* The first argument is ARG(1).
*
* ALSO NOTE: This stack offset is only valid if using routine
* DOES NOT alter SP.
*
*/
#define ARG(n) ((((n) - 1) * 4) + 24)
/*
* Macros for building stack frame according to C calling conventions.
* lr, cr, and sp are saved.
*
* NOTE WELL: localvarsize is in bytes, maxargsout is a count of words,
* grfsaved and fpfsaved is a count of registers. BE SURE TO COUNT
* BOTH FP (r31) AND sN REGISTERS IN THE COUNT OF GRF REGISTERS SAVED!
* This will be TWO more than the N of the highest sN register you
* save: s2 implies you are saving s2, s1, s0, and fp => grfsaved
* should be 4!
*
* FURTHER NOTE: These macros do NOT SAVE GRF or FPF registers. User
* must do that. GRF sN regs should be saved via
* stmw sN,SAVED_GRF_S(N)(sp)
* where N is the highest numbered s* register to be saved. E.g. if
* s0, s1, and s2 are to be saved use:
* stmw s2,SAVED_GRF_S(2)(sp)
* Note that this also saves fp.
* An individual saved grf can be loaded via:
* lwz s2,SAVED_GRF_S(2)(sp)
* Analogous stuff works for fpf's.
*
* NOTE: these simple routines will be replaced with more complicated
* ones once we know what the linker and gdb will require as for as
* register use masks and frame declarations.
*
* Warning: ROUND_TO_STACK is only to be used in assembly language;
* for C usage, use ROUND_FRAME() in reg_help.h.
*/
#define ROUND_TO_STACK(len) \
(((len) + STACK_INCR - 1) / STACK_INCR * STACK_INCR)
#define BUILD_FRAME(localvarsize, maxargsout, grfsaved, fpfsaved) \
.set __argoutsize, ROUND_TO_STACK((maxargsout) * 4) @\
.if __argoutsize < 32 @\
.set __argoutsize,32 @\
.endif @\
.set __framesize, ROUND_TO_STACK( \
24 + __argoutsize + (localvarsize) \
+ 4*(grfsaved) + 8*(fpfsaved)) @\
.set __grfbase,(__framesize - 4*(grfsaved) - 8*(fpfsaved)) @\
.set __fpfbase,(__framesize - 8*(fpfsaved)) @\
mflr r0 @\
mfcr r12 @\
stw r0,8(sp) @\
stw r12,4(sp) @\
stwu r1,-__framesize(r1)
/*
* Macros for referencing data in stack frame.
*
* NOTE WELL: ARG's and VAR's start at 1, NOT 0. Why ??? (FIXME)
*/
#define LOCAL_VAR(n) (((n)-1)*4 + __argoutsize + 24)
#define SAVED_GRF_S(n) (__grfbase + ((grfsaved) - (n) - 2) * 4)
#define SAVED_FRF_FS(n) (__fpfbase + ((fpfsaved) - (n) - 1) * 4)
#define ARG_IN(n) (ARG(n) + __framesize)
#define ARG_OUT(n) (ARG(n) + 0)
#define SAVED_FP (__grfbase + ((grfsaved) - 1) * 4)
#define SAVED_LR (__framesize + 8)
#define SAVED_CR (__framesize + 4)
/*
* Macros for unwinding stack frame.
* NOTE: GRF's and FPF's are NOT RESTORED. User must do this before
* using this macro.
*/
#define RETURN \
.if __framesize @\
lwz32 r0,r1,SAVED_LR @\
lwz32 r12,r1,SAVED_CR @\
addic sp,r1,__framesize @\
mtlr r0 @\
mtcrf 0xff,r12 @\
blr @\
.else @\
blr @\
.endif
/*
* Macros for declaring procedures
*
* Use of these macros allows ctags to have a predictable way
* to find various types of declarations. They also simplify
* inserting appropriate symbol table information.
*
* NOTE: these simple stubs will be replaced with more
* complicated versions once we know what the linker and gdb
* will require as far as register use masks and frame declarations.
* These macros may also be ifdef'ed in the future to contain profiling
* code.
*
* FIXME: Document what makes a leaf a LEAF and a handler a HANDLER.
* (E.g. leaf's have return pc in lr, NESTED's have rpc in offset off
* sp, handlers have rpc in exception frame which is found via exception
* link, etc etc.)
*/
/*
* TEXT -- declare start of text segment
*/
#define TEXT \
.text @\
.align 2
/*
* LEAF -- declare global leaf procedure
* NOTE: Control SHOULD NOT FLOW into a LEAF! A LEAF should only
* be jumped to. (A leaf may do an align.) Use a LABEL() if you
* need control to flow into the label.
*/
#define LEAF(name) \
.align 2 @\
.globl name @\
name: @\
.set __framesize,0
/*
* X_LEAF -- declare alternate global label for leaf
*/
#define X_LEAF(name, value) \
.globl name @\
.set name,value
/*
* P_LEAF -- declare private leaf procedure
*/
#define P_LEAF(name) \
.align 2 @\
name: @\
.set __framesize,0
/*
* LABEL -- declare a global code label
* MUST be used (rather than LEAF, NESTED, etc) if control
* "flows into" the label.
*/
#define LABEL(name) \
.align 2 @\
.globl name @\
name:
/*
* NESTED -- declare procedure that invokes other procedures
*/
#define NESTED(name, localvarsize, maxargsout, grfsaved, fpfsaved)\
.align 2 @\
.globl name @\
name: @\
BUILD_FRAME(localvarsize, maxargsout, grfsaved, fpfsaved)
/*
* X_NESTED -- declare alternate global label for nested proc
*/
#define X_NESTED(name, value) \
.globl name @\
.set name,value
/*
* P_NESTED -- declare private nested procedure
*/
#define P_NESTED(name, localvarsize, maxargsout, grfsaved, fpfsaved)\
.align 2 @\
name: @\
BUILD_FRAME(locavarsize, maxargsout, grfsaved, fpfsaved)
/*
* HANDLER -- declare procedure with exception frame rather than
* standard C frame
*/
#define HANDLER(name) \
.align 2 @\
.globl name @\
name:
/*
* X_HANDLER -- declare alternate name for exception handler
* (Should appear immediately before a HANDLER declaration or
* another X_HANDLER declaration)
*/
#define X_HANDLER(name) \
.align 2 @\
.globl name @\
name:
/*
* P_HANDLER -- declare private handler
*/
#define P_HANDLER(name) \
.align 2 @\
name:
/*
* END -- mark end of procedure
* FIXME: Unimplemented for now.
*/
#define END(name)
/*
* BL -- call procedure (relative)
*/
#define BL(name) \
bl name
/*
* Storage definition macros
* The main purpose of these is to allow an easy handle for ctags
*/
/*
* IMPORT -- import symbol
*/
#define IMPORT(name) \
.reference name
/*
* ABS -- declare global absolute symbol
*/
#define ABS(name, value) \
.globl name @\
.set name,value
/*
* P_ABS -- declare private absolute symbol
*/
#define P_ABS(name, value) \
.set name,value
/*
* EXPORT -- declare global label for data
*/
#define EXPORT(name) \
.align 2 @\
.globl name @\
name:
/*
* BSS -- declare global zero'ed storage
*/
#define BSS(name,size) \
.comm name,size
/*
* P_BSS -- declare private zero'ed storage
*/
#define P_BSS(name,size) \
.lcomm name,size
/*
* dynamic/PIC macros for routines which reference external symbols
*/
#if defined(__DYNAMIC__)
#define PICIFY_REG r12
/* Assume that the lr is saved before calling any of these macros */
/* using PICIFY() */
#define PICIFY(var) \
mflr r0 @\
bl 1f @\
1: mflr PICIFY_REG @\
mtlr r0 @\
addis PICIFY_REG, PICIFY_REG, ha16(L ## var ## $non_lazy_ptr - 1b) @\
lwz PICIFY_REG, lo16(L ## var ## $non_lazy_ptr - 1b)(PICIFY_REG)
#define CALL_EXTERN_AGAIN(var) \
PICIFY(var) @\
mtctr PICIFY_REG @\
mflr r0 @\
stw r0,8(r1) @\
stwu r1,-56(r1) @\
bctrl @\
addic r1,r1,56 @\
lwz r0,8(r1) @\
mtlr r0
#define NON_LAZY_STUB(var) \
.non_lazy_symbol_pointer @\
.align 2 @\
L ## var ## $non_lazy_ptr: @\
.indirect_symbol var @\
.long 0 @\
.text @\
.align 2
#define BRANCH_EXTERN(var) \
PICIFY(var) @\
mtctr PICIFY_REG @\
bctr @\
NON_LAZY_STUB(var)
#define CALL_EXTERN(var) \
CALL_EXTERN_AGAIN(var) @\
NON_LAZY_STUB(var)
#define REG_TO_EXTERN(reg, var) \
PICIFY(var) @\
stw reg, 0(PICIFY_REG) @\
NON_LAZY_STUB(var)
#define EXTERN_TO_REG(reg, var) \
PICIFY(var) @\
lwz reg, 0(PICIFY_REG) @\
NON_LAZY_STUB(var)
#else /* ! __DYNAMIC__ */
#define TMP_REG r12
#define BRANCH_EXTERN(var) \
b var
#define CALL_EXTERN(var) \
bl var
#define CALL_EXTERN_AGAIN(var) \
CALL_EXTERN(var)
#define REG_TO_EXTERN(reg, var) \
lis TMP_REG, ha16(var) @\
stw reg, lo16(var)(TMP_REG)
#define EXTERN_TO_REG(reg, var) \
lis reg, ha16(var) @\
lwz reg, lo16(var)(reg)
#endif /* __DYNAMIC__ */
#endif /* __ASSEMBLER__ */
#endif /* _ARCH_PPC_ASM_HELP_H_ */