| Server IP : 209.209.40.120 / Your IP : 216.73.217.112 Web Server : Microsoft-IIS/10.0 System : Windows NT NEWWWW 10.0 build 17763 (Windows Server 2019) i586 User : NEWWWW$ ( 0) PHP Version : 8.3.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/Program Files (x86)/Windows Kits/10/Include/10.0.19041.0/shared/ |
Upload File : |
;++
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;
; Module:
;
; kxarmunw.w
;
; Abstract:
;
; Contains ARM unwind code helper macros
;
; This file is not really useful on its own without the support from
; kxarm.h.
;
;--
;
; The following macros are defined here:
;
; PROLOG_PUSH {reglist}
; PROLOG_VPUSH {reglist}
; PROLOG_PUSH_TRAP_FRAME
; PROLOG_PUSH_MACHINE_FRAME
; PROLOG_PUSH_CONTEXT
; PROLOG_REDZONE_RESTORE_LR
; PROLOG_DECLARE_PROLOG_HELPER
; PROLOG_STACK_ALLOC <amount>
; PROLOG_STACK_SAVE <reg>
; PROLOG_NOP <operation>
;
; EPILOG_NOP <operation>
; EPILOG_STACK_RESTORE <reg>
; EPILOG_STACK_FREE <amount>
; EPILOG_VPOP {reglist}
; EPILOG_POP {reglist}
; EPILOG_BRANCH <target>
; EPILOG_BRANCH_REG <target>
; EPILOG_LDRPC_POSTINC <postinc>
; EPILOG_RETURN
; EPILOG_REDZONE_RESTORE_LR
;
;
; Global variables
;
; results from __ParseIntRegister[List], __ParseVfpRegister[List]
GBLS __ParsedRegisterString
GBLA __ParsedRegisterMask
GBLA __VfpParsedRegisterMaskBase
; results from __ComputeCodes[...]
GBLS __ComputedCodes
; input and result from __MinMaxRegFromMask
GBLA __RegInputMask
GBLA __MinRegNum
GBLA __MaxRegNum
; result from __CountBitsInMask
GBLA __MaskBitCount
; global state and accumulators
GBLS __PrologUnwindString
GBLS __PrologLastLabel
GBLA __EpilogUnwindCount
GBLS __Epilog1UnwindString
GBLS __Epilog2UnwindString
GBLS __Epilog3UnwindString
GBLS __Epilog4UnwindString
GBLL __EpilogStartNotDefined
GBLA __RunningIndex
GBLS __RunningLabel
;
; Helper macro: compute minimum/maximum register indexes from a mask
;
; Input goes into __RegInputMask
; Output is placed in __MinRegNum and __MaxRegNum
;
MACRO
__MinMaxRegFromMask
LCLA CurMask
CurMask SETA __RegInputMask
__MinRegNum SETA -1
__MaxRegNum SETA -1
WHILE CurMask != 0
IF ((CurMask:AND:1) != 0) && (__MinRegNum == -1)
__MinRegNum SETA __MaxRegNum + 1
ENDIF
CurMask SETA CurMask:SHR:1
__MaxRegNum SETA __MaxRegNum + 1
WEND
MEND
;
; Helper macro: compute number of bits in a mask
;
; Input goes into __RegInputMask
; Output is placed in __MaskBitCount
;
MACRO
__CountBitsInMask
LCLA CurMask
CurMask SETA __RegInputMask
__MaskBitCount SETA 0
WHILE CurMask != 0
IF (CurMask:AND:1) != 0
__MaskBitCount SETA __MaskBitCount + 1
ENDIF
CurMask SETA CurMask:SHR:1
WEND
MEND
;
; Helper macro: emit an opcode with a generated label
;
; Output: Name of label is in $__RunningLabel
;
MACRO
__EmitRunningLabelAndOpcode $O1,$O2,$O3,$O4,$O5,$O6
__RunningLabel SETS "|Temp.$__RunningIndex|"
__RunningIndex SETA __RunningIndex + 1
IF "$O6" != ""
$__RunningLabel $O1,$O2,$O3,$O4,$O5,$O6
ELIF "$O5" != ""
$__RunningLabel $O1,$O2,$O3,$O4,$O5
ELIF "$O4" != ""
$__RunningLabel $O1,$O2,$O3,$O4
ELIF "$O3" != ""
$__RunningLabel $O1,$O2,$O3
ELIF "$O2" != ""
$__RunningLabel $O1,$O2
ELIF "$O1" != ""
$__RunningLabel $O1
ELSE
$__RunningLabel
ENDIF
MEND
;
; Helper macro: append unwind codes to the prolog string
;
; Input is in __ComputedCodes
;
MACRO
__AppendPrologCodes
__PrologUnwindString SETS "$__ComputedCodes,$__PrologUnwindString"
MEND
;
; Helper macro: append unwind codes to the epilog string
;
; Input is in __ComputedCodes
;
MACRO
__AppendEpilogCodes
IF __EpilogUnwindCount == 1
__Epilog1UnwindString SETS "$__Epilog1UnwindString,$__ComputedCodes"
ELIF __EpilogUnwindCount == 2
__Epilog2UnwindString SETS "$__Epilog2UnwindString,$__ComputedCodes"
ELIF __EpilogUnwindCount == 3
__Epilog3UnwindString SETS "$__Epilog3UnwindString,$__ComputedCodes"
ELIF __EpilogUnwindCount == 4
__Epilog4UnwindString SETS "$__Epilog4UnwindString,$__ComputedCodes"
ENDIF
MEND
;
; Helper macro: detect prolog end
;
MACRO
__DeclarePrologEnd
__PrologLastLabel SETS "$__RunningLabel"
MEND
;
; Helper macro: detect epilog start
;
MACRO
__DeclareEpilogStart
IF __EpilogStartNotDefined
__EpilogStartNotDefined SETL {false}
__EpilogUnwindCount SETA __EpilogUnwindCount + 1
IF __EpilogUnwindCount == 1
$__FuncEpilog1StartLabel
ELIF __EpilogUnwindCount == 2
$__FuncEpilog2StartLabel
ELIF __EpilogUnwindCount == 3
$__FuncEpilog3StartLabel
ELIF __EpilogUnwindCount == 4
$__FuncEpilog4StartLabel
ELSE
INFO 1, "Too many epilogues!"
ENDIF
ENDIF
MEND
;
; Helper macro: specify epilog end
;
MACRO
__DeclareEpilogEnd
__EpilogStartNotDefined SETL {true}
MEND
;
; Convoluted macro to parse a parameter that should be an integer register
; or register range, and return the string and mask
;
; Output is placed in __ParsedRegisterString and __ParsedRegisterMask
;
MACRO
__ParseIntRegister $Text
LCLS CurText
LCLS LReg
LCLA LRegNum
LCLA LRegMask
LCLS RReg
LCLA RRegNum
LCLA RRegMask
CurText SETS "$Text"
LReg SETS ""
LRegMask SETA 0
RReg SETS ""
RRegMask SETA 0
; start with everything empty
__ParsedRegisterString SETS ""
__ParsedRegisterMask SETA 0
; strip leading open brace
IF :LEN:CurText >= 1 && CurText:LEFT:1 == "{"
CurText SETS CurText:RIGHT:(:LEN:CurText - 1)
ENDIF
; strip trailing close brace
IF :LEN:CurText >= 1 && CurText:RIGHT:1 == "}"
CurText SETS CurText:LEFT:(:LEN:CurText - 1)
ENDIF
; parse into register pair if 5 or more characters
IF (:LEN:CurText) >= 5
IF (CurText:LEFT:3):RIGHT:1 == "-"
LReg SETS CurText:LEFT:2
RReg SETS CurText:RIGHT:(:LEN:CurText - 3)
ENDIF
IF (CurText:LEFT:4):RIGHT:1 == "-"
LReg SETS CurText:LEFT:3
RReg SETS CurText:RIGHT:(:LEN:CurText - 4)
ENDIF
; otherwise, parse as a single register
ELSE
LReg SETS CurText
RReg SETS ""
ENDIF
; fail if the registers aren't integer registers
IF LReg != "lr" && LReg != "sp" && LReg != "pc" && LReg:LEFT:1 != "r"
MEXIT
ENDIF
; determine register masks
LRegNum SETA :RCONST:$LReg
LRegMask SETA 1:SHL:LRegNum
; if no right register, assign the single register
IF RReg == ""
__ParsedRegisterString SETS LReg
__ParsedRegisterMask SETA LRegMask
; otherwise, validate the right register and generate the range
ELSE
IF RReg != "lr" && RReg != "sp" && RReg != "pc" && RReg:LEFT:1 != "r"
MEXIT
ENDIF
RRegNum SETA :RCONST:$RReg
RRegMask SETA 1:SHL:RRegNum
__ParsedRegisterString SETS LReg:CC:"-":CC:RReg
__ParsedRegisterMask SETA (RRegMask + RRegMask - 1) - (LRegMask - 1)
ENDIF
MEND
;
; Macro to parse a list of integer registers into a string and a mask
;
; Output is placed in __ParsedRegisterString and __ParsedRegisterMask
;
MACRO
__ParseIntRegisterList $Func,$R1,$R2,$R3,$R4,$R5
LCLS OverallString
LCLA OverallMask
__ParseIntRegister $R1
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R1"
ENDIF
OverallMask SETA __ParsedRegisterMask
OverallString SETS __ParsedRegisterString
IF "$R2" != ""
__ParseIntRegister $R2
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R2"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
IF "$R3" != ""
__ParseIntRegister $R3
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R3"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
IF "$R4" != ""
__ParseIntRegister $R4
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R4"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
IF "$R5" != ""
__ParseIntRegister $R5
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R5"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
__ParsedRegisterMask SETA OverallMask
__ParsedRegisterString SETS OverallString
MEND
;
; Convoluted macro to parse a parameter that should be a VFP register
; or register range, and return the string and mask
;
; Output is placed in __ParsedRegisterString and __ParsedRegisterMask
;
MACRO
__ParseVfpRegister $Text
LCLS CurText
LCLS LReg
LCLA LRegNum
LCLA LRegMask
LCLS RReg
LCLA RRegNum
LCLA RRegMask
CurText SETS "$Text"
LReg SETS ""
LRegMask SETA 0
RReg SETS ""
RRegMask SETA 0
; start with everything empty
__ParsedRegisterString SETS ""
__ParsedRegisterMask SETA 0
; strip leading open brace
IF :LEN:CurText >= 1 && CurText:LEFT:1 == "{"
CurText SETS CurText:RIGHT:(:LEN:CurText - 1)
ENDIF
; strip trailing close brace
IF :LEN:CurText >= 1 && CurText:RIGHT:1 == "}"
CurText SETS CurText:LEFT:(:LEN:CurText - 1)
ENDIF
; parse into register pair if 5 or more characters
IF (:LEN:CurText) >= 5
IF (CurText:LEFT:3):RIGHT:1 == "-"
LReg SETS CurText:LEFT:2
RReg SETS CurText:RIGHT:(:LEN:CurText - 3)
ENDIF
IF (CurText:LEFT:4):RIGHT:1 == "-"
LReg SETS CurText:LEFT:3
RReg SETS CurText:RIGHT:(:LEN:CurText - 4)
ENDIF
; otherwise, parse as a single register
ELSE
LReg SETS CurText
RReg SETS ""
ENDIF
; fail if the registers aren't VFP registers
IF LReg:LEFT:1 != "d"
MEXIT
ENDIF
; determine register masks
LReg SETS LReg:RIGHT:(:LEN:LReg - 1)
LRegNum SETA $LReg
; set the base to 0 or 16 if not yet determined
IF __VfpParsedRegisterMaskBase == 1
IF LRegNum >= 16
__VfpParsedRegisterMaskBase SETA 16
ELSE
__VfpParsedRegisterMaskBase SETA 0
ENDIF
ENDIF
IF (LRegNum >= __VfpParsedRegisterMaskBase) && (LRegNum - __VfpParsedRegisterMaskBase < 16)
LRegMask SETA 1:SHL:(LRegNum - __VfpParsedRegisterMaskBase)
ELSE
LRegMask SETA 0
ENDIF
; if no right register, assign the single register
IF RReg == ""
__ParsedRegisterString SETS "d":CC:LReg
__ParsedRegisterMask SETA LRegMask
; otherwise, validate the right register and generate the range
ELSE
IF RReg:LEFT:1 != "d"
MEXIT
ENDIF
RReg SETS RReg:RIGHT:(:LEN:RReg - 1)
RRegNum SETA $RReg
IF (RRegNum >= __VfpParsedRegisterMaskBase) && (RRegNum - __VfpParsedRegisterMaskBase < 16)
RRegMask SETA 1:SHL:(RRegNum - __VfpParsedRegisterMaskBase)
ELSE
RRegMask SETA 0
ENDIF
__ParsedRegisterString SETS "d":CC:LReg:CC:"-d":CC:RReg
__ParsedRegisterMask SETA (RRegMask + RRegMask - 1) - (LRegMask - 1)
ENDIF
MEND
;
; Macro to parse a list of VFP registers into a string and a mask
;
; Output is placed in __ParsedRegisterString and __ParsedRegisterMask
;
MACRO
__ParseVfpRegisterList $Func,$R1,$R2,$R3,$R4,$R5
LCLS OverallString
LCLA OverallMask
__VfpParsedRegisterMaskBase SETA 1
__ParseVfpRegister $R1
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R1"
ENDIF
OverallMask SETA __ParsedRegisterMask
OverallString SETS __ParsedRegisterString
IF "$R2" != ""
__ParseVfpRegister $R2
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R2"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
IF "$R3" != ""
__ParseVfpRegister $R3
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R3"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
IF "$R4" != ""
__ParseVfpRegister $R4
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R4"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
IF "$R5" != ""
__ParseVfpRegister $R5
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Func: $R5"
ENDIF
OverallMask SETA OverallMask:OR:__ParsedRegisterMask
OverallString SETS OverallString:CC:",":CC:__ParsedRegisterString
ENDIF
__ParsedRegisterMask SETA OverallMask
__ParsedRegisterString SETS OverallString
MEND
;
; Compute unwind codes for a PUSH or POP operation
;
; Input is in __ParsedRegisterMask
; Output is placed in __ComputedCodes
;
MACRO
__ComputePushPopCodes $Name,$FreeMask
LCLA MaskMinusFree
LCLA ByteVal
LCLA ByteVal2
LCLA PcLrVal
; See if LR/PC was included in the mask
PcLrVal SETA 0
IF (__ParsedRegisterMask:AND:0xc000) != 0
PcLrVal SETA 1
ENDIF
; Compute a mask without LR/PC
MaskMinusFree SETA __ParsedRegisterMask:AND:(:NOT:$FreeMask)
; Determine minimum/maximum registers
__RegInputMask SETA MaskMinusFree
__MinMaxRegFromMask
; single byte, 16-bit push r4-r[4-7]
IF ((MaskMinusFree:AND:0xff1f) == 0x0010) && (((MaskMinusFree + 0x10):AND:MaskMinusFree) == 0)
ByteVal SETA 0xd0 :OR: (PcLrVal:SHL:2) :OR: (__MaxRegNum:AND:3)
__ComputedCodes SETS "0x":CC:((:STR:ByteVal):RIGHT:2)
; single byte, 16-bit push r4-r[8-11]
ELIF ((MaskMinusFree:AND:0xf01f) == 0x0010) && (((MaskMinusFree + 0x10):AND:MaskMinusFree) == 0)
ByteVal SETA 0xd8 :OR: (PcLrVal:SHL:2) :OR: (__MaxRegNum:AND:3)
__ComputedCodes SETS "0x":CC:((:STR:ByteVal):RIGHT:2)
; double byte, 16-bit push r0-r7 via bitmask
ELIF ((MaskMinusFree:AND:0xff00) == 0x0000)
ByteVal SETA 0xec :OR: PcLrVal
__ComputedCodes SETS "0x":CC:((:STR:ByteVal):RIGHT:2):CC:",0x":CC:((:STR:MaskMinusFree):RIGHT:2)
; double byte, 32-bit push r0-r12,lr via bitmask
ELIF ((MaskMinusFree:AND:0xa000) == 0x0000)
ByteVal SETA 0x80 :OR: (PcLrVal:SHL:5) :OR: ((__ParsedRegisterMask:SHR:8):AND:0x1f)
ByteVal2 SETA __ParsedRegisterMask:AND:0xff
__ComputedCodes SETS "0x":CC:((:STR:ByteVal):RIGHT:2):CC:",0x":CC:((:STR:ByteVal2):RIGHT:2)
; unsupported case
ELSE
INFO 1, "Invalid register sequence specified in $Name"
ENDIF
MEND
;
; Compute unwind codes for a VPUSH or VPOP operation
;
; Input is in __ParsedRegisterMask
; Output is placed in __ComputedCodes
;
MACRO
__ComputeVpushVpopCodes $Name
LCLA ByteVal
LCLA MinRegNum
LCLA MaxRegNum
; Determine minimum/maximum registers
__RegInputMask SETA __ParsedRegisterMask
__MinMaxRegFromMask
MinRegNum SETA __MinRegNum + __VfpParsedRegisterMaskBase
MaxRegNum SETA __MaxRegNum + __VfpParsedRegisterMaskBase
; Only contiguous sequences are supported
IF ((__ParsedRegisterMask + (1:SHL:__MinRegNum)):AND:__ParsedRegisterMask) != 0
INFO 1, "Discontiguous register sequence specified in PROLOG_VPUSH"
; single byte, 32-bit vpush d8-d[8-15]
ELIF (MinRegNum == 8) && (MaxRegNum <= 15)
ByteVal SETA 0xe0 :OR: (MaxRegNum:AND:7)
__ComputedCodes SETS "0x":CC:((:STR:ByteVal):RIGHT:2)
; double byte, 32-bit vpush d0-d15 via start/end values
ELIF (MinRegNum >= 0) && (MaxRegNum <= 15)
ByteVal SETA ((MinRegNum:AND:15):SHL:4) :OR: (MaxRegNum:AND:15)
__ComputedCodes SETS "0xF5,0x":CC:((:STR:ByteVal):RIGHT:2)
; double byte, 32-bit vpush d16-d31 via start/end values
ELIF (MinRegNum >= 16) && (MaxRegNum <= 31)
ByteVal SETA ((MinRegNum:AND:15):SHL:4) :OR: (MaxRegNum:AND:15)
__ComputedCodes SETS "0xF6,0x":CC:((:STR:ByteVal):RIGHT:2)
; unsupported case
ELSE
INFO 1, "Invalid register sequence specified in $Name"
ENDIF
MEND
;
; Compute unwind codes for a stack alloc/dealloc operation
;
; Output is placed in __ComputedCodes
;
MACRO
__ComputeStackAllocCodes $Name, $Amount
LCLA BytesDiv4
LCLA BytesHigh
LCLA BytesLow
BytesDiv4 SETA ($Amount) / 4
; single byte, 16-bit add sp, sp, #x
IF BytesDiv4 <= 0x7f
__ComputedCodes SETS "0x":CC:((:STR:BytesDiv4):RIGHT:2)
; double byte, 32-bit addw sp, sp, #x
ELIF BytesDiv4 <= 0x3ff
BytesHigh SETA (BytesDiv4:SHR:8):OR:0xe8
BytesLow SETA BytesDiv4:AND:0xff
__ComputedCodes SETS "0x":CC:((:STR:BytesHigh):RIGHT:2):CC:",0x":CC:((:STR:BytesLow):RIGHT:2)
; don't support anything bigger
ELSE
INFO 1, "$Name too large for unwind code encoding"
ENDIF
MEND
;
; Compute unwind codes for a stack save/restore operation
;
; Output is placed in __ComputedCodes
;
MACRO
__ComputeStackSaveRestoreCodes $Name, $Register
LCLA ByteVal
__ParseIntRegister $Register
; error if no valid register
IF __ParsedRegisterMask == 0
INFO 1, "Invalid register in $Name: $Register"
; determine min/max registers in mask
ELSE
__RegInputMask SETA __ParsedRegisterMask
__MinMaxRegFromMask
; error if we were passed a range
IF __MinRegNum != __MaxRegNum
INFO 1, "Register range not allowed in $Name: $Register"
; single byte, 16-bit mov rN, sp
ELSE
ByteVal SETA 0xc0 :OR: __MinRegNum
__ComputedCodes SETS "0x":CC:((:STR:ByteVal):RIGHT:2)
ENDIF
ENDIF
MEND
;
; Macro for including an arbitrary operation in the prolog
;
MACRO
PROLOG_NOP $O1,$O2,$O3,$O4
__EmitRunningLabelAndOpcode $O1,$O2,$O3,$O4
__DeclarePrologEnd
IF ?$__RunningLabel == 2
__ComputedCodes SETS "0xFB"
ELSE
__ComputedCodes SETS "0xFC"
ENDIF
__AppendPrologCodes
MEND
;
; Macro for an integer register PUSH operation in a prologue
;
MACRO
PROLOG_PUSH $R1,$R2,$R3,$R4,$R5
__ParseIntRegisterList "PROLOG_PUSH",$R1,$R2,$R3,$R4,$R5
__EmitRunningLabelAndOpcode push {$__ParsedRegisterString}
__DeclarePrologEnd
__ComputePushPopCodes "PROLOG_PUSH",0x4000
__AppendPrologCodes
#if ENABLE_FRAME_POINTER
IF (__ParsedRegisterMask:AND:0x0800) != 0
__RegInputMask SETA __ParsedRegisterMask:AND:0x07ff
__CountBitsInMask
IF __MaskBitCount == 0
PROLOG_NOP mov r11, sp
ELSE
PROLOG_NOP add r11, sp, #(__MaskBitCount * 4)
ENDIF
ENDIF
#endif
MEND
;
; Macro for a floating-point register VPUSH operation in a prologue
;
MACRO
PROLOG_VPUSH $R1,$R2,$R3,$R4,$R5
LCLA ByteVal
__ParseVfpRegisterList "PROLOG_VPUSH",$R1,$R2,$R3,$R4,$R5
__EmitRunningLabelAndOpcode vpush {$__ParsedRegisterString}
__DeclarePrologEnd
__ComputeVpushVpopCodes "PROLOG_VPUSH"
__AppendPrologCodes
MEND
;
; Macro for indicating a trap frame lives above us
;
MACRO
PROLOG_PUSH_TRAP_FRAME
__ComputedCodes SETS "0xEE,0x03"
__AppendPrologCodes
MEND
;
; Macro for indicating a machine frame lives above us
;
MACRO
PROLOG_PUSH_MACHINE_FRAME
__ComputedCodes SETS "0xEE,0x01"
__AppendPrologCodes
MEND
;
; Macro for indicating a context lives above us
;
MACRO
PROLOG_PUSH_CONTEXT
__ComputedCodes SETS "0xEE,0x02"
__AppendPrologCodes
MEND
;
; Macro for indicating a save LR was saved in the
; red zone at [sp-8]
;
MACRO
PROLOG_REDZONE_RESTORE_LR
__ComputedCodes SETS "0xEE,0x04"
__AppendPrologCodes
MEND
MACRO
EPILOG_REDZONE_RESTORE_LR
__ComputedCodes SETS "0xEE,0x04"
__AppendEpilogCodes
MEND
;
; Macro for allocating space on the stack in the prolog
;
MACRO
PROLOG_STACK_ALLOC $Amount
__EmitRunningLabelAndOpcode sub sp, sp, #$Amount
__DeclarePrologEnd
__ComputeStackAllocCodes "PROLOG_STACK_ALLOC", $Amount
__AppendPrologCodes
MEND
;
; Macro for saving the stack pointer in another register
;
MACRO
PROLOG_STACK_SAVE $Register
__EmitRunningLabelAndOpcode mov $Register, sp
__DeclarePrologEnd
__ComputeStackSaveRestoreCodes "PROLOG_STACK_SAVE", $Register
__AppendPrologCodes
MEND
;
; Macro for including an arbitrary operation in the epilog
;
MACRO
EPILOG_NOP $O1,$O2,$O3,$O4
__DeclareEpilogStart
__EmitRunningLabelAndOpcode $O1,$O2,$O3,$O4
IF ?$__RunningLabel == 2
__ComputedCodes SETS "0xFB"
ELSE
__ComputedCodes SETS "0xFC"
ENDIF
__AppendEpilogCodes
MEND
;
; Macro for saving the stack pointer in another register
;
MACRO
EPILOG_STACK_RESTORE $Register
__DeclareEpilogStart
__EmitRunningLabelAndOpcode mov sp, $Register
__ComputeStackSaveRestoreCodes "EPILOG_STACK_RESTORE", $Register
__AppendEpilogCodes
MEND
;
; Macro for deallocating space on the stack in the prolog
;
MACRO
EPILOG_STACK_FREE $Amount
__DeclareEpilogStart
__EmitRunningLabelAndOpcode add sp, sp, #$Amount
__ComputeStackAllocCodes "EPILOG_STACK_FREE", $Amount
__AppendEpilogCodes
MEND
;
; Macro for an integer register POP operation in an epilogue
;
MACRO
EPILOG_POP $R1,$R2,$R3,$R4,$R5
__ParseIntRegisterList "EPILOG_POP",$R1,$R2,$R3,$R4,$R5
__DeclareEpilogStart
__EmitRunningLabelAndOpcode pop {$__ParsedRegisterString}
__ComputePushPopCodes "EPILOG_POP",0x8000
__AppendEpilogCodes
IF (__ParsedRegisterMask:AND:0x8000) != 0
__DeclareEpilogEnd
ENDIF
MEND
;
; Macro for a floating-point register VPOP operation in a prologue
;
MACRO
EPILOG_VPOP $R1,$R2,$R3,$R4,$R5
LCLA ByteVal
__ParseVfpRegisterList "EPILOG_VPOP",$R1,$R2,$R3,$R4,$R5
__DeclareEpilogStart
__EmitRunningLabelAndOpcode vpop {$__ParsedRegisterString}
__ComputeVpushVpopCodes "EPILOG_VPOP"
__AppendEpilogCodes
MEND
;
; Macro for a b <target> end to the epilog (tail-call)
;
MACRO
EPILOG_BRANCH $Target
__DeclareEpilogStart
__EmitRunningLabelAndOpcode b $Target
IF ?$__RunningLabel == 2
__ComputedCodes SETS "0xFD"
ELSE
__ComputedCodes SETS "0xFE"
ENDIF
__AppendEpilogCodes
__DeclareEpilogEnd
MEND
;
; Macro for a bx register-style return in the epilog
;
MACRO
EPILOG_BRANCH_REG $Register
__DeclareEpilogStart
__EmitRunningLabelAndOpcode bx $Register
__ComputedCodes SETS "0xFD"
__AppendEpilogCodes
__DeclareEpilogEnd
MEND
;
; Macro for a ldr pc, [sp], #x style return in the epilog
;
MACRO
EPILOG_LDRPC_POSTINC $Amount
LCLA ByteVal
__DeclareEpilogStart
__EmitRunningLabelAndOpcode ldr pc, [sp], #$Amount
ByteVal SETA 0x00 :OR: ($Amount/4)
__ComputedCodes SETS "0xEF,0x":CC:((:STR:ByteVal):RIGHT:2)
__AppendEpilogCodes
__DeclareEpilogEnd
MEND
;
; Macro for a bx lr-style return in the epilog
;
MACRO
EPILOG_RETURN
EPILOG_BRANCH_REG lr
MEND
;
; Macro to reset the internal uwninding states
;
MACRO
__ResetUnwindState
__PrologUnwindString SETS ""
__EpilogUnwindCount SETA 0
__Epilog1UnwindString SETS ""
__Epilog2UnwindString SETS ""
__Epilog3UnwindString SETS ""
__Epilog4UnwindString SETS ""
__EpilogStartNotDefined SETL {true}
MEND
;
; Macro to emit the xdata for unwinding
;
MACRO
__EmitUnwindXData
LCLA XBit
LCLA FBit
; determine
FBit SETA 0
IF "$__PrologUnwindString" == ""
FBit SETA 1:SHL:22
ENDIF
XBit SETA 0
IF "$__FuncExceptionHandler" != ""
XBit SETA 1:SHL:20
ENDIF
;
; Append terminators where necessary
;
IF __EpilogUnwindCount >= 1
__Epilog1UnwindString SETS __Epilog1UnwindString:RIGHT:(:LEN:__Epilog1UnwindString - 1)
IF (:LEN:__Epilog1UnwindString) >= 5
IF __Epilog1UnwindString:RIGHT:4 < "0xFD"
__Epilog1UnwindString SETS __Epilog1UnwindString:CC:",0xFF"
ENDIF
ENDIF
ENDIF
IF __EpilogUnwindCount >= 2
__Epilog2UnwindString SETS __Epilog2UnwindString:RIGHT:(:LEN:__Epilog2UnwindString - 1)
IF (:LEN:__Epilog2UnwindString) >= 5
IF __Epilog2UnwindString:RIGHT:4 < "0xFD"
__Epilog2UnwindString SETS __Epilog2UnwindString:CC:",0xFF"
ENDIF
ENDIF
ENDIF
IF __EpilogUnwindCount >= 3
__Epilog3UnwindString SETS __Epilog3UnwindString:RIGHT:(:LEN:__Epilog3UnwindString - 1)
IF (:LEN:__Epilog3UnwindString) >= 5
IF __Epilog3UnwindString:RIGHT:4 < "0xFD"
__Epilog3UnwindString SETS __Epilog3UnwindString:CC:",0xFF"
ENDIF
ENDIF
ENDIF
IF __EpilogUnwindCount >= 4
__Epilog4UnwindString SETS __Epilog4UnwindString:RIGHT:(:LEN:__Epilog4UnwindString - 1)
IF (:LEN:__Epilog4UnwindString) >= 5
IF __Epilog4UnwindString:RIGHT:4 < "0xFD"
__Epilog4UnwindString SETS __Epilog4UnwindString:CC:",0xFF"
ENDIF
ENDIF
ENDIF
; optimize out the prolog string if it matches
IF (:LEN:__Epilog1UnwindString) >= 6
IF __Epilog1UnwindString:LEFT:(:LEN:__Epilog1UnwindString - 4) == __PrologUnwindString
__PrologUnwindString SETS ""
ENDIF
ENDIF
IF "$__PrologUnwindString" != ""
__PrologUnwindString SETS __PrologUnwindString:CC:"0xFF"
ENDIF
;
; Switch to the .xdata section, aligned to a DWORD
;
AREA |.xdata|,ALIGN=2,READONLY
ALIGN 4
; declare the xdata header with unwind code size, epilog count,
; exception bit, and function length
$__FuncXDataLabel
DCD ((($__FuncXDataEndLabel - $__FuncXDataPrologLabel)/4):SHL:28) :OR: (__EpilogUnwindCount:SHL:23) :OR: FBit :OR: XBit :OR: (($__FuncEndLabel - $__FuncStartLabel)/2)
; if we have an epilogue, output a single scope record
IF __EpilogUnwindCount >= 1
DCD (($__FuncXDataEpilog1Label - $__FuncXDataPrologLabel):SHL:24) :OR: (14:SHL:20) :OR: (($__FuncEpilog1StartLabel - $__FuncStartLabel)/2)
ENDIF
IF __EpilogUnwindCount >= 2
DCD (($__FuncXDataEpilog2Label - $__FuncXDataPrologLabel):SHL:24) :OR: (14:SHL:20) :OR: (($__FuncEpilog2StartLabel - $__FuncStartLabel)/2)
ENDIF
IF __EpilogUnwindCount >= 3
DCD (($__FuncXDataEpilog3Label - $__FuncXDataPrologLabel):SHL:24) :OR: (14:SHL:20) :OR: (($__FuncEpilog3StartLabel - $__FuncStartLabel)/2)
ENDIF
IF __EpilogUnwindCount >= 4
DCD (($__FuncXDataEpilog4Label - $__FuncXDataPrologLabel):SHL:24) :OR: (14:SHL:20) :OR: (($__FuncEpilog4StartLabel - $__FuncStartLabel)/2)
ENDIF
; output the prolog unwind string
$__FuncXDataPrologLabel
IF "$__PrologUnwindString" != ""
DCB $__PrologUnwindString
ENDIF
; if we have an epilogue, output the epilog unwind codes
IF __EpilogUnwindCount >= 1
$__FuncXDataEpilog1Label
DCB $__Epilog1UnwindString,0xff
ENDIF
IF __EpilogUnwindCount >= 2
$__FuncXDataEpilog2Label
DCB $__Epilog2UnwindString,0xff
ENDIF
IF __EpilogUnwindCount >= 3
$__FuncXDataEpilog3Label
DCB $__Epilog3UnwindString,0xff
ENDIF
IF __EpilogUnwindCount >= 4
$__FuncXDataEpilog4Label
DCB $__Epilog4UnwindString,0xff
ENDIF
; watch out for 0 epilogs and empty prolog -- that will create a problem
; due to special encoding meaning look for a second header word
IF __EpilogUnwindCount == 0
IF "$__PrologUnwindString" == ""
DCB 0xff
ENDIF
ENDIF
ALIGN 4
$__FuncXDataEndLabel
; output the exception handler information
IF "$__FuncExceptionHandler" != ""
DCD $__FuncExceptionHandler
RELOC 2 ; make this relative to image base
DCD 0 ; append a 0 for the data (keeps Vulcan happy)
ENDIF
; switch back to the original area
AREA $__FuncArea,CODE,READONLY
MEND