aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code/ssxcpp.s
blob: 07159c42cac664de376db5c34d9dc584f26a99c8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# ssxcpp.s: STACK SCANNING FOR MAC OS X / POWERPC
#
# .quote.why: The following is in quotes because otherwise the
# preprocessor seems to barf.
# "$Header$"
#
# Copyright (c) 2005 Ravenbrook Limited.  See end of file for license.
#
# .readership: Any MPS developer that is prepared to read PowerPC
# assembly code in GNU 'as' syntax.
#
#
# It's possible that since this is mostly PowerPC and GNU 'as' that we
# could use the same code for lippgc.  See .future.abi
#
# 
# REFERENCES
# 
# [OSXAG] "Introduction to Mac OS X Assembler Guide", 
# http://developer.apple.com/documentation/DeveloperTools/Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
# http://developer.apple.com/documentation/DeveloperTools/Reference/Assembler/Assembler.pdf
#
# [PEM] "PowerPC Microprocessor Family: The Programming Environments for
# 32-bit Microprocessors", Motorola, 1997-01.  MPCFPE32B/AD REV.1
#
# [MORT] "Introduction to Mach-O Runtime Architecture",
# http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/index.html
# http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/MachORuntime.pdf
#
# [MORT] Chapter 2 is the place to go for the stack layout.  But it is
# still a bit vague.  For example, what is the exact format of the
# Linkage Area?
#
#
# Stack Layout and Register Usage
#
# Let SPEP be the value of the stack pointer (r1) on entry to the
# function.  r1 is the Stack Pointer, descending full stack (that is
# -4(r1) is the address of the next available free slot on the stack).
#
# On entry, stack looks like (numerically higher addresses appear higher
# up the page, stack grows down (towards address 0) in memory and on
# paper):
#
# |                                   |
# +-----------------------------------+
# | -- Parameter area --              |
# | Lowest addresses have leftmost    |
# | actual arguments.                 |
# | Note that some actual arguments   |
# | may be in registers.  They        |
# | still have a slot reserved in     |
# | this area, even if the value is   |
# | not written in.                   |
# +-----------------------------------+
# | -- Linkage area --                |
# | Apparently this is 24 bytes long. |
# | (See [MORT] Listing 2-1)          |
# | 12(SPEP)-23(SPEP) unknown         |
# | 8(SPEP) - optional lr             |
# | 4(SPEP) - optional cr             |
# | 0(SPEP) - previous SPEP           |
# +-----------------------------------+
# 8(SPEP) - available to store the callee's lr if desired.
# 4(SPEP) - available to store the callee's cr if desired.
# 0(SPEP) - not available.  The caller saves their SPEP here.  In other
# words, this points to the highest address of the caller's frame.  The
# callee will decrement sp and store SPEP at the new sp, thus creating a
# new linkage area in preparation for calling another function.
#
# Note that the callee can access locations -1(SPEP) to -224(SPEP)
# without changing the stack pointer.  This is called a Red Zone (see
# [MORT] Chapter 2, section "The Red Zone").  This means that we must
# overscan when scanning the stacks of other threads.
#
# [MORT] Table 2-4 specifies which registers are saved (required to be
# preserved by a callee when called, aka nonvolatile).  They are: r1,
# r13-r31, fr14-fr31, v20-v31, VRSAVE, cr2-cr4.
#
# Stack Scanner Design
#
# All we have to do is create a stack frame, push the saved registers
# onto it, and call TraceScanArea with appropriate arguments.
# We assume that of the saved registers, only the general purpose ones
# can contain roots (in other words the client doesn't store pointers in
# floating pointer registers, and other silliness).  So we'll only store
# r13 through to r31.  r1 will be stored in the callee's new linkage
# area, as per convention.  lr will be stored in the caller's linkage
# area, as per convention.  CTR (a future PC value, so a potential root)
# is volatile so cannot be a root.
#
# Future Directions
#
# .future.clear: We could poke all the stack locations that we have
# access to and set them to 0 (the ones that we are not using), just
# in case any false references are hiding there.
#
# .future.abi:
# One can imagine a sort of minimal ABI version that pushed
# all registers and only used stack space that it had reserved itself.
# We would, alas, still have to assume that r1 was SP though.
#
# To do this we would need to:
# - save more registers
# - possibly not use the caller's stack

# Exported symbols
.globl _StackScan

# Imported symbols
.globl _TraceScanArea

linkageArea = 24 ; size of linkage area to create
paramArea = 12 ; size of param area to create
# .local.size: this size is directly related to what registers we save.
localArea = 76 ; size of local workspace (for 19 registers, r13-r31)
# A throwaway comment in [MORT] p32 "The called routine is responsible
# for allocating its own stack frame, making sure to preserve 16-byte
# alignment on the stack" implies that the stack must always be 16-byte
# aligned.  Thus, this sum, frameSize, must be a multiple of 16.  24 +
# 12 + 76 = 112 = 7*16, so much for the abstraction.
frameSize = linkageArea + paramArea + localArea

_StackScan:
# r1 is SPEP
    mflr r0
# value of localArea depends on r13, see .local.size
    stmw r13, -localArea(r1)
    stw r0, 8(r1)
    stwu r1, -frameSize(r1)
# r1 + frameSize is SPEP

# setup arguments for call to TraceScanArea, and call it
# First Argument, ScanState, is our first argument, already in r3.
# Arguments are processed out of order because of the dependency on r4
# Third Argument: highest stack address.
    mr r5, r4
# Second Argument: lowest stack address.
    mr r4, r1
    bl _TraceScanArea

    lwz r1, 0(r1)
# r1 is SPEP again
    lwz r0, 8(r1)
    mtlr r0
# See .local.size
    lmw r13, -localArea(r1)
    li r3, 0
    blr