├── iOSAppInAssembly
├── en.lproj
│ └── InfoPlist.strings
├── Utilities_ARMv7.s
├── iOSAppInAssembly-Info.plist
├── main_ARMv7.s
├── View_ARMv7.s
└── AppDelegate_ARMv7.s
├── iOSAppInAssembly.xcodeproj
├── xcuserdata
│ └── angrybeast.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── iOSAppInAssembly.xcscheme
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── angrybeast.xcuserdatad
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── xcdebugger
│ │ └── Expressions.xcexplist
└── project.pbxproj
└── README.md
/iOSAppInAssembly/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/iOSAppInAssembly.xcodeproj/xcuserdata/angrybeast.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/iOSAppInAssembly.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/iOSAppInAssembly.xcodeproj/project.xcworkspace/xcuserdata/angrybeast.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges
6 |
7 | SnapshotAutomaticallyBeforeSignificantChanges
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/iOSAppInAssembly.xcodeproj/project.xcworkspace/xcuserdata/angrybeast.xcuserdatad/xcdebugger/Expressions.xcexplist:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/iOSAppInAssembly.xcodeproj/xcuserdata/angrybeast.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | iOSAppInAssembly.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | C33F1D171860F4A800D3EE14
16 |
17 | primary
18 |
19 |
20 | C33F1D321860F4A800D3EE14
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/iOSAppInAssembly/Utilities_ARMv7.s:
--------------------------------------------------------------------------------
1 | // Utilities_ARMv7.s
2 | // This file contains a collection of utilities used throughout the application.
3 |
4 |
5 | // Helper function to convert C-string to Objective-C string.
6 | //
7 | // Parameters:
8 | // r0: input pointer
9 | // Results:
10 | // r0: result pointer
11 | .section __TEXT,__text,regular,pure_instructions
12 | .global util_getCFString
13 | .align 4
14 | util_getCFString:
15 | push {r4-r7, lr} // save LR, R7, R4-R6
16 | add r7, sp, #12 // adjust R7 to point to saved R7
17 | push {r8, r10, r11} // save remaining GPRs (R8, R10, R11)
18 | vstmdb sp!, {d8-d15} // save VFP/Advanced SIMD registers D8
19 |
20 | // To convert our string, we are calling the function CFStringCreateWithCString.
21 | //
22 | // Parameter 1 (r0) is the allocator.
23 | // Parameter 2 (r1) is the string.
24 | // Parameter 3 (r2) is the encoding.
25 | //
26 | // Its resulting string will be stored in the r0 register.
27 | mov r1, r0
28 | mov r0, #0
29 | mov r2, #1536
30 | bl _CFStringCreateWithCString
31 |
32 | vldmia sp!, {d8-d15} // restore VFP/Advanced SIMD registers
33 | pop {r8, r10, r11} // restore R8-R11
34 | pop {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR
35 |
--------------------------------------------------------------------------------
/iOSAppInAssembly/iOSAppInAssembly-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.richardjrossiii.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations~ipad
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationPortraitUpsideDown
35 | UIInterfaceOrientationLandscapeLeft
36 | UIInterfaceOrientationLandscapeRight
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## An iOS App In Assembly
2 |
3 | It's just what it sounds like. Hand written, delicately debugged, well-commented, ARMv7 assembly. Work on this started before ARM64 devices were a thing, so support for them may come in the future.
4 |
5 | ### Goals
6 |
7 | Rather simple, make an app that compiles, runs, and draws something on the screen, using only hand written assembly. The only times I used the assembly output of clang was to determine the proper `.section`s for things, to let lldb be able to debug my functions.
8 |
9 | The basic structure of this app is based on my [iOS App In Pure C](https://github.com/richardjrossiii/CBasediOSApp), with a 'main' file which contains all the set-up code, and two supporting files, for each of the classes (AppDelegate, and View).
10 |
11 | The drawing code is all done using CoreGraphics, and displays the string 'Hello, Assembly!' in red on the screen. Here's a screenshot of the app running on my iPhone 5S:
12 |
13 | 
14 |
15 | ### Notes
16 |
17 | If running the app with any accessibility features enabled (switch control, guided access, etc.) the app crashes when the runtime tries to see if my App Delegate responds to the selector `accessibilityInitialize`, and I'm not entirely sure why. This may be fixed in the future.
18 |
19 | ### Resources
20 |
21 | - [Apple's iOS ABI Reference](https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009020-SW1)
22 | - [The ARM ABI Reference](http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html)
23 | - [The ARM Developer Suite Assembler Guide](http://infocenter.arm.com/help/topic/com.arm.doc.dui0068b/index.html)
24 |
25 | And, as always, the mighty power of Google.
26 |
27 | ### License
28 |
29 | Copyright 2014 Richard J. Ross III.
30 |
31 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
32 |
33 | http://www.apache.org/licenses/LICENSE-2.0
34 |
35 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
36 |
--------------------------------------------------------------------------------
/iOSAppInAssembly/main_ARMv7.s:
--------------------------------------------------------------------------------
1 | // main_ARMv7.s
2 | // This is the entry point of the application, in ARMv7 assembly.
3 |
4 | // Firstly, we will setup all strings that will be used for the first part of this app.
5 | // Then, we will setup an auto-release pool to manage our dangling objects,
6 | // And finally, we will jump right into UIApplicationMain.
7 |
8 | // Create a raw C string to hold the data for the App Delegate
9 | .section __TEXT,__cstring
10 | s_delegateClassNameCStr:
11 | .asciz "AppDelegate"
12 |
13 | //
14 | // Entry point of the application.
15 | //
16 | // Parameters:
17 | // None.
18 | //
19 | // Results:
20 | // r0: error code to return to OS.
21 | //
22 | //
23 | .section __TEXT,__text,regular,pure_instructions
24 | .global _main
25 | .align 4
26 | _main:
27 | // Note: This was taken from the official ARMv7 calling conventions document:
28 | // https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009022-SW5
29 | // I will assume that it is the correct way to start and finish functions throughout the project.
30 | push {r4-r7, lr} // save LR, R7, R4-R6
31 | add r7, sp, #12 // adjust R7 to point to saved R7
32 | push {r8, r10, r11} // save remaining GPRs (R8, R10, R11)
33 | vstmdb sp!, {d8-d15} // save VFP/Advanced SIMD registers D8
34 |
35 | // Setup the autorelease pool. This is done using the (non-documented) function objc_autoreleasePoolPush.
36 | //
37 | // It takes no parameters.
38 | //
39 | // It returns no results.
40 | bl _objc_autoreleasePoolPush
41 |
42 | // Setup our app delegate's class. This is done using our function AppDelegate_Setup.
43 | //
44 | // It takes no parameters.
45 | //
46 | // It returns no results.
47 | bl AppDelegate_Setup
48 |
49 | // Setup our custom view's class. This is done using our function View_Setup.
50 | //
51 | // It takes no parameters.
52 | //
53 | // It returns no results.
54 | bl View_Setup
55 |
56 | // Next, we need to actually start up the visual application. This is done in 2 steps.
57 | //
58 | // 1: Create a Objective-C string from a C-String for our App Delegate's name.
59 | // 2: Start the visual application.
60 |
61 | // Turn our C string into a NSString, using our function util_getCFString.
62 | //
63 | // Parameter 1 (r0) is the string we wish to convert.
64 | //
65 | // The newly created string object is stored in r0 after calling the function.
66 | mov r0, s_delegateClassNameCStr
67 | bl util_getCFString
68 |
69 | // The next step is to start the visual application. This is done using the function UIApplicationMain.
70 | //
71 | // Parameter 1 (r0) is the argument count passed to main. For the purposes of this demo, it is irrelevant.
72 | // Parameter 2 (r1) is the argument list passed to main. For the purposes of this demo, it is irrelevant.
73 | // Parameter 3 (r2) is the name of the principle class. This would be a subclass of UIApplication if we had one.
74 | // Parameter 4 (r3) is the name of the delegate class. This is our AppDelegate string.
75 | //
76 | // The result code of the application is stored in r0 after calling the function.
77 | mov r3, r0
78 | mov r2, #0
79 | mov r1, #0
80 | mov r0, #0
81 | bl _UIApplicationMain
82 |
83 | // Finally, we must clean up our auto-release pool. This is done using the function objc_autoreleasePoolPop.
84 | //
85 | // It takes no parameters.
86 | //
87 | // It returns no usable results. However, it clobbers r0, so we save and re-load that variable around it.
88 | push {r0}
89 | bl _objc_autoreleasePoolPop
90 | pop {r0}
91 |
92 | vldmia sp!, {d8-d15} // restore VFP/Advanced SIMD registers
93 | pop {r8, r10, r11} // restore R8-R11
94 | pop {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR
--------------------------------------------------------------------------------
/iOSAppInAssembly.xcodeproj/xcuserdata/angrybeast.xcuserdatad/xcschemes/iOSAppInAssembly.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
61 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/iOSAppInAssembly/View_ARMv7.s:
--------------------------------------------------------------------------------
1 | // View_ARMv7.s
2 | // This is the file that will contain the class for our view.
3 |
4 | // Setup all strings that will be used in this file.
5 | .section __TEXT,__cstring
6 | View_ParentClassName:
7 | .asciz "UIView"
8 |
9 | .section __TEXT,__cstring
10 | View_ClassName:
11 | .asciz "View"
12 |
13 | .section __TEXT,__cstring
14 | View_MethodName:
15 | .asciz "drawRect:"
16 |
17 | .section __TEXT,__cstring
18 | View_MethodEncoding:
19 | .asciz "v@:{CGRect={CGPoint=ff}{CGSize=ff}}"
20 |
21 | .section __TEXT,__cstring
22 | View_DrawString:
23 | .asciz "Hello, Assembly!"
24 |
25 | // Global variables for storing the class
26 | .section __DATA,regular
27 | .align 4
28 | View_Class:
29 | .long 0
30 |
31 | .section __DATA,regular
32 | .align 4
33 | View_FillRect:
34 | .float 0
35 | .float 0
36 | .float 1000
37 | .float 1000
38 |
39 | .section __DATA,regular
40 | .align 4
41 | View_FillColor:
42 | .float 1, 1, 0, 1 // RGBA
43 |
44 | .section __DATA,regular
45 | .align 4
46 | View_TextPosition:
47 | .float 100
48 | .float 100
49 |
50 | .section __DATA,regular
51 | .align 4
52 | View_TextMatrix:
53 | .float 1 // a
54 | .float 0 // b
55 | .float 0 // c
56 | .float -1 // d
57 | .float 0 // tx
58 | .float 0 // ty
59 |
60 | .section __DATA,regular
61 | .align 4
62 | View_FontName:
63 | .asciz "Helvetica"
64 |
65 | .section __DATA,regular
66 | .align 4
67 | View_FontSize:
68 | .float 20
69 |
70 | .section __DATA,regular
71 | .align 4
72 | View_DrawColor:
73 | .float 1, 0, 0, 1 // RGBA
74 |
75 | .section __DATA,regular
76 | .align 4
77 | View_DrawStringLength:
78 | .int 16
79 |
80 | //
81 | // The setup method for the view class.
82 | //
83 | // Parameters:
84 | // none.
85 | //
86 | // Results:
87 | // none.
88 | //
89 | // Registers used:
90 | //
91 | // r0-r3: Arguments
92 | // r4: Class Pointer.
93 | // r5-r6: Temporary values.
94 | // r7: Frame (stack) pointer.
95 | // r8: Temporary value.
96 | // r9: Scratch register.
97 | // r10-r11: Temporary values.
98 | //
99 | // Stack Used:
100 | //
101 | // 4 bytes, offset 0: Parameter passing.
102 | //
103 | .section __TEXT,__text,regular,pure_instructions
104 | .global View_Setup
105 | .align 4
106 | View_Setup:
107 | push {r4-r7, lr} // save LR, R7, R4-R6
108 | add r7, sp, #12 // adjust R7 to point to saved R7
109 | push {r8, r10, r11} // save remaining GPRs (R8, R10, R11)
110 | vstmdb sp!, {d8-d15} // save VFP/Advanced SIMD registers D8
111 |
112 | // Our goal here is to create a view class. We'll use the following steps to accomplish this:
113 | //
114 | // 1: Fetch the superclass of our new class. (In this case, UIView)
115 | // 2: Create our new class.
116 | // 3: Save it to our global variable in case we need to use it again. (In this case, View_Class)
117 | // 4: Setup the -drawRect: method of our class.
118 | //
119 |
120 | // Parameter 1 (r0) will be the name of the superclass.
121 | // The superclass will then be stored in r0 after calling the function.
122 | mov r0, View_ParentClassName
123 | bl _objc_getClass
124 |
125 | // Parameter 1 (r0) will be the superclass, which is already in the r0 register.
126 | // Parameter 2 (r1) will be the new class's name.
127 | // Parameter 3 (r2) will be the extra byte count of this class, in this case 0.
128 | // The new class will then be stored in the r0 register after calling the function.
129 | mov r1, View_ClassName
130 | mov r2, #0
131 | bl _objc_allocateClassPair
132 |
133 | // Now that we have our class, it's time to store it to our global variable,
134 | // and our r4 register for use inside this function..
135 | mov r1, View_Class
136 | str r0, [r1]
137 | mov r4, r0
138 |
139 | // The next step to attach the method to our class. We'll do this in two steps:
140 | //
141 | // 1: Fetch the unique selector for the method we're implementing.
142 | // 2: Add the method to the class we've created.
143 |
144 | // To fetch the selector, we will use the function sel_getUid.
145 | //
146 | // Parameter 1 (r0) will be the name of the selector to get.
147 | //
148 | // The result of this function will then be stored in the r0 register.
149 | mov r0, View_MethodName
150 | bl _sel_getUid
151 |
152 | // To actually add the method to the class, we'll use the function class_addMethod.
153 | //
154 | // Parameter 1 (r0) will be the class (which is currently in r4).
155 | // Parameter 2 (r1) will be the selector (which is currently in r0).
156 | // Parameter 3 (r2) will be the address of the implementation.
157 | // Parameter 4 (r3) will be the encoding of this method.
158 | //
159 | // The success of this function will then be stored in the r0 register upon completion.
160 | mov r1, r0
161 | mov r0, r4
162 | mov r2, View_DrawRect
163 | mov r3, View_MethodEncoding
164 | bl _class_addMethod
165 |
166 | // If we've gotten this far, our class is ready to go, we just need to actually hook it into the runtime.
167 | // This is done using the function objc_registerClassPair.
168 | //
169 | // Parameter 1 (r0) will be the class, which is currently in the r4 register.
170 | //
171 | // This function has no results.
172 | mov r0, r4
173 | bl _objc_registerClassPair
174 |
175 | // Now, everything else should be done automatically!
176 | // Our drawRect will be called, and we shouldn't have to touch the runtime again!
177 |
178 | vldmia sp!, {d8-d15} // restore VFP/Advanced SIMD registers
179 | pop {r8, r10, r11} // restore R8-R11
180 | pop {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR
181 |
182 | //
183 | // The method used for drawing the view.
184 | //
185 | // Parameters:
186 | // r0: View object.
187 | // r1: Selector passed (-drawRect:)
188 | // r2-r4,[stack-stack, offset 4]: Dirty rect.
189 | //
190 | // Results:
191 | // none.
192 | //
193 | // Registers used:
194 | //
195 | // r0-r3: Arguments
196 | // r4: CGContext Pointer.
197 | // r5-6: Temporary values.
198 | // r7: Frame (stack) pointer.
199 | // r8: Temporary value.
200 | // r9: Scratch register.
201 | // r10-r11: Temporary values.
202 | //
203 | // Stack Used:
204 | //
205 | // 4 bytes, offset 0: Parameter passing.
206 | //
207 | .section __TEXT,__text,regular,pure_instructions
208 | .align 4
209 | View_DrawRect:
210 | push {r4-r7, lr} // save LR, R7, R4-R6
211 | add r7, sp, #12 // adjust R7 to point to saved R7
212 | push {r8, r10, r11} // save remaining GPRs (R8, R10, R11)
213 | vstmdb sp!, {d8-d15} // save VFP/Advanced SIMD registers D8
214 |
215 | sub sp, sp, #12 // Allocate stack storage
216 |
217 | // Our goal in this method is to simply draw something to the screen.
218 | // We will use the QuartzCore functions for this, but we'll make things
219 | // a little bit more interesting by drawing something other than a rectangle.
220 |
221 | // First, let's fetch the current context with UIGraphcisGetCurrentContext().
222 | //
223 | // It takes no praremters.
224 | //
225 | // The context will be placed in the r0 register upon returning, and we will then store it in the r4 register.
226 | bl _UIGraphicsGetCurrentContext
227 | mov r4, r0
228 |
229 | // Now, we'll clear the screen, using CGContextSetFillColor.
230 | //
231 | // Parameter 1 (r0) will be the context, which is currently in the r0 register.
232 | // Parameter 2 (r1) will be the pointer to the first element in our color array.
233 | //
234 | // This method returns no results
235 | mov r1, View_FillColor
236 | bl _CGContextSetFillColor
237 |
238 | // To actually fill the screen, we must now use CGContextFillRect.
239 | //
240 | // Parameter 1 (r0) will be the context, which is currently in the r4 register.
241 | // Parameter 2 (r1) will be the x element of the rect to fill.
242 | // Parameter 3 (r2) will be the y element of the rect to fill.
243 | // Parameter 4 (r3) will be the width element of the rect to fill.
244 | // Parameter 5 (Stack, offset 0) will be the height element of the rect to fill.
245 | //
246 | // This method returns no results.
247 | mov r0, r4
248 |
249 | // CGRect loading
250 | mov r9, View_FillRect
251 | ldr r1, [r9]
252 | ldr r2, [r9, #4]
253 | ldr r3, [r9, #8]
254 | ldr r9, [r9, #12]
255 | str r9, [sp]
256 |
257 | bl _CGContextFillRect
258 |
259 | // Now, we'll set the font. We'll do this with CGContextSelectFont
260 | //
261 | // Parameter 1 (r0) will be the context, which is currently in the r4 register
262 | // Parameter 2 (r1) will be the font name, which is Helvetica.
263 | // Parameter 3 (r2) will be the font size as a float
264 | // Parameter 4 (r3) will be the encoding of the text, which we will set at MacRoman, 1
265 | //
266 | // This method returns no results.
267 | mov r0, r4
268 | mov r1, View_FontName
269 | mov r9, View_FontSize
270 | ldr r2, [r9]
271 | mov r3, #1
272 |
273 | bl _CGContextSelectFont
274 |
275 | // Before we can draw this text, we need to set the text color. This will be done using CGContextSetFillColor.
276 | //
277 | // Parameter 1 (r0) will be the context, which is currently in register r4.
278 | // Parameter 2 (r1) will be the pointer to the first element in our color array.
279 | //
280 | // This method returns no results.
281 | mov r0, r4
282 | mov r1, View_DrawColor
283 | bl _CGContextSetFillColor
284 |
285 | // Now, at this point there is an issue - CGContext draws everything upside down,
286 | // and we need to scale it to flip it the right-side up. This is done using CGContextSetTextMatrix.
287 | //
288 | // Parameter 1 (r0) will be the context.
289 | // Parameter 2 (r1) will be the first element in the matrix.
290 | // Parameter 3 (r2) will be the second element in the matrix.
291 | // Parameter 4 (r3) will be the third element in the matrix.
292 | // Parameter 5 (Stack, offset 0) will be the fourth element in the matrix.
293 | // Parameter 6 (Stack, offset 4) will be the fifth element in the matrix.
294 | // Parameter 7 (Stack, offset 8) will be the sixth element in the matrix.
295 | //
296 | // This method returns no results.
297 | mov r0, r4
298 | mov r9, View_TextMatrix
299 | ldr r1, [r9] // 1
300 | ldr r2, [r9, #4] // 2
301 | ldr r3, [r9, #8] // 3
302 |
303 | ldr r5, [r9, #12]
304 | str r5, [sp] // 4
305 |
306 | ldr r5, [r9, #16]
307 | str r5, [sp, #4] // 5
308 |
309 | ldr r5, [r9, #20]
310 | str r5, [sp, #8] // 6
311 |
312 | bl _CGContextSetTextMatrix
313 |
314 | // Next, we'll set the text position. We'll do this with CGContextSetTextPosition
315 | //
316 | // Parameter 1 (r0) will be the context, which is currently in the r4 register
317 | // Parameter 2 (r1) will be the x position to set
318 | // Parameter 3 (r2) will be the y position to set
319 | //
320 | // This method returns no results.
321 | mov r0, r4
322 |
323 | mov r9, View_TextPosition
324 | ldr r1, [r9]
325 | ldr r2, [r9, #4]
326 | bl _CGContextSetTextPosition
327 |
328 | // If we did this correctly, now we should be able to draw the text to the screen!
329 | // This will be done with CGContextShowText
330 | //
331 | // Parameter 1 (r0) will be the context, which is currently in register r4.
332 | // Parameter 2 (r1) will be the pointer to the string.
333 | // Parameter 3 (r2) will be the length of the string.
334 | //
335 | // This method returns no results.
336 | mov r0, r4
337 | mov r1, View_DrawString
338 | mov r2, View_DrawStringLength
339 | ldr r2, [r2]
340 | bl _CGContextShowText
341 |
342 | // That's it! Now we simply return to the calling function, and we have successfully created an iOS app in ARM assembler.
343 | add sp, sp, #12 // Deallocate stack storage.
344 |
345 | vldmia sp!, {d8-d15} // restore VFP/Advanced SIMD registers
346 | pop {r8, r10, r11} // restore R8-R11
347 | pop {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR
348 |
--------------------------------------------------------------------------------
/iOSAppInAssembly.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | C33F1D1C1860F4A800D3EE14 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33F1D1B1860F4A800D3EE14 /* Foundation.framework */; };
11 | C33F1D1E1860F4A800D3EE14 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33F1D1D1860F4A800D3EE14 /* CoreGraphics.framework */; };
12 | C33F1D201860F4A800D3EE14 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33F1D1F1860F4A800D3EE14 /* UIKit.framework */; };
13 | C33F1D261860F4A800D3EE14 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C33F1D241860F4A800D3EE14 /* InfoPlist.strings */; };
14 | C33F1D4B1860F4C400D3EE14 /* main_ARMv7.s in Sources */ = {isa = PBXBuildFile; fileRef = C33F1D4A1860F4C400D3EE14 /* main_ARMv7.s */; };
15 | C36F5B20186167E5001F75A5 /* Utilities_ARMv7.s in Sources */ = {isa = PBXBuildFile; fileRef = C36F5B1F186167E5001F75A5 /* Utilities_ARMv7.s */; };
16 | C3BFE152188B13AA00A67483 /* View_ARMv7.s in Sources */ = {isa = PBXBuildFile; fileRef = C36F5B1D1861674D001F75A5 /* View_ARMv7.s */; };
17 | C3FB5AD818D3B19500FBED82 /* AppDelegate_ARMv7.s in Sources */ = {isa = PBXBuildFile; fileRef = C36F5B1B186165F2001F75A5 /* AppDelegate_ARMv7.s */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXFileReference section */
21 | C33F1D181860F4A800D3EE14 /* iOSAppInAssembly.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSAppInAssembly.app; sourceTree = BUILT_PRODUCTS_DIR; };
22 | C33F1D1B1860F4A800D3EE14 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
23 | C33F1D1D1860F4A800D3EE14 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
24 | C33F1D1F1860F4A800D3EE14 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
25 | C33F1D231860F4A800D3EE14 /* iOSAppInAssembly-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "iOSAppInAssembly-Info.plist"; sourceTree = ""; };
26 | C33F1D251860F4A800D3EE14 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
27 | C33F1D341860F4A800D3EE14 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
28 | C33F1D4A1860F4C400D3EE14 /* main_ARMv7.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = main_ARMv7.s; sourceTree = ""; };
29 | C36F5B1B186165F2001F75A5 /* AppDelegate_ARMv7.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = AppDelegate_ARMv7.s; sourceTree = ""; };
30 | C36F5B1D1861674D001F75A5 /* View_ARMv7.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = View_ARMv7.s; sourceTree = ""; };
31 | C36F5B1F186167E5001F75A5 /* Utilities_ARMv7.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = Utilities_ARMv7.s; sourceTree = ""; };
32 | /* End PBXFileReference section */
33 |
34 | /* Begin PBXFrameworksBuildPhase section */
35 | C33F1D151860F4A800D3EE14 /* Frameworks */ = {
36 | isa = PBXFrameworksBuildPhase;
37 | buildActionMask = 2147483647;
38 | files = (
39 | C33F1D1E1860F4A800D3EE14 /* CoreGraphics.framework in Frameworks */,
40 | C33F1D201860F4A800D3EE14 /* UIKit.framework in Frameworks */,
41 | C33F1D1C1860F4A800D3EE14 /* Foundation.framework in Frameworks */,
42 | );
43 | runOnlyForDeploymentPostprocessing = 0;
44 | };
45 | /* End PBXFrameworksBuildPhase section */
46 |
47 | /* Begin PBXGroup section */
48 | C33F1D0F1860F4A800D3EE14 = {
49 | isa = PBXGroup;
50 | children = (
51 | C33F1D211860F4A800D3EE14 /* iOSAppInAssembly */,
52 | C33F1D1A1860F4A800D3EE14 /* Frameworks */,
53 | C33F1D191860F4A800D3EE14 /* Products */,
54 | );
55 | sourceTree = "";
56 | };
57 | C33F1D191860F4A800D3EE14 /* Products */ = {
58 | isa = PBXGroup;
59 | children = (
60 | C33F1D181860F4A800D3EE14 /* iOSAppInAssembly.app */,
61 | );
62 | name = Products;
63 | sourceTree = "";
64 | };
65 | C33F1D1A1860F4A800D3EE14 /* Frameworks */ = {
66 | isa = PBXGroup;
67 | children = (
68 | C33F1D1B1860F4A800D3EE14 /* Foundation.framework */,
69 | C33F1D1D1860F4A800D3EE14 /* CoreGraphics.framework */,
70 | C33F1D1F1860F4A800D3EE14 /* UIKit.framework */,
71 | C33F1D341860F4A800D3EE14 /* XCTest.framework */,
72 | );
73 | name = Frameworks;
74 | sourceTree = "";
75 | };
76 | C33F1D211860F4A800D3EE14 /* iOSAppInAssembly */ = {
77 | isa = PBXGroup;
78 | children = (
79 | C36F5B1B186165F2001F75A5 /* AppDelegate_ARMv7.s */,
80 | C36F5B1D1861674D001F75A5 /* View_ARMv7.s */,
81 | C33F1D4A1860F4C400D3EE14 /* main_ARMv7.s */,
82 | C36F5B1F186167E5001F75A5 /* Utilities_ARMv7.s */,
83 | C33F1D221860F4A800D3EE14 /* Supporting Files */,
84 | );
85 | path = iOSAppInAssembly;
86 | sourceTree = "";
87 | };
88 | C33F1D221860F4A800D3EE14 /* Supporting Files */ = {
89 | isa = PBXGroup;
90 | children = (
91 | C33F1D231860F4A800D3EE14 /* iOSAppInAssembly-Info.plist */,
92 | C33F1D241860F4A800D3EE14 /* InfoPlist.strings */,
93 | );
94 | name = "Supporting Files";
95 | sourceTree = "";
96 | };
97 | /* End PBXGroup section */
98 |
99 | /* Begin PBXNativeTarget section */
100 | C33F1D171860F4A800D3EE14 /* iOSAppInAssembly */ = {
101 | isa = PBXNativeTarget;
102 | buildConfigurationList = C33F1D441860F4A800D3EE14 /* Build configuration list for PBXNativeTarget "iOSAppInAssembly" */;
103 | buildPhases = (
104 | C33F1D141860F4A800D3EE14 /* Sources */,
105 | C33F1D151860F4A800D3EE14 /* Frameworks */,
106 | C33F1D161860F4A800D3EE14 /* Resources */,
107 | );
108 | buildRules = (
109 | );
110 | dependencies = (
111 | );
112 | name = iOSAppInAssembly;
113 | productName = iOSAppInAssembly;
114 | productReference = C33F1D181860F4A800D3EE14 /* iOSAppInAssembly.app */;
115 | productType = "com.apple.product-type.application";
116 | };
117 | /* End PBXNativeTarget section */
118 |
119 | /* Begin PBXProject section */
120 | C33F1D101860F4A800D3EE14 /* Project object */ = {
121 | isa = PBXProject;
122 | attributes = {
123 | LastUpgradeCheck = 0510;
124 | ORGANIZATIONNAME = richardjrossiii;
125 | };
126 | buildConfigurationList = C33F1D131860F4A800D3EE14 /* Build configuration list for PBXProject "iOSAppInAssembly" */;
127 | compatibilityVersion = "Xcode 3.2";
128 | developmentRegion = English;
129 | hasScannedForEncodings = 0;
130 | knownRegions = (
131 | en,
132 | );
133 | mainGroup = C33F1D0F1860F4A800D3EE14;
134 | productRefGroup = C33F1D191860F4A800D3EE14 /* Products */;
135 | projectDirPath = "";
136 | projectRoot = "";
137 | targets = (
138 | C33F1D171860F4A800D3EE14 /* iOSAppInAssembly */,
139 | );
140 | };
141 | /* End PBXProject section */
142 |
143 | /* Begin PBXResourcesBuildPhase section */
144 | C33F1D161860F4A800D3EE14 /* Resources */ = {
145 | isa = PBXResourcesBuildPhase;
146 | buildActionMask = 2147483647;
147 | files = (
148 | C33F1D261860F4A800D3EE14 /* InfoPlist.strings in Resources */,
149 | );
150 | runOnlyForDeploymentPostprocessing = 0;
151 | };
152 | /* End PBXResourcesBuildPhase section */
153 |
154 | /* Begin PBXSourcesBuildPhase section */
155 | C33F1D141860F4A800D3EE14 /* Sources */ = {
156 | isa = PBXSourcesBuildPhase;
157 | buildActionMask = 2147483647;
158 | files = (
159 | C3FB5AD818D3B19500FBED82 /* AppDelegate_ARMv7.s in Sources */,
160 | C3BFE152188B13AA00A67483 /* View_ARMv7.s in Sources */,
161 | C33F1D4B1860F4C400D3EE14 /* main_ARMv7.s in Sources */,
162 | C36F5B20186167E5001F75A5 /* Utilities_ARMv7.s in Sources */,
163 | );
164 | runOnlyForDeploymentPostprocessing = 0;
165 | };
166 | /* End PBXSourcesBuildPhase section */
167 |
168 | /* Begin PBXVariantGroup section */
169 | C33F1D241860F4A800D3EE14 /* InfoPlist.strings */ = {
170 | isa = PBXVariantGroup;
171 | children = (
172 | C33F1D251860F4A800D3EE14 /* en */,
173 | );
174 | name = InfoPlist.strings;
175 | sourceTree = "";
176 | };
177 | /* End PBXVariantGroup section */
178 |
179 | /* Begin XCBuildConfiguration section */
180 | C33F1D421860F4A800D3EE14 /* Debug */ = {
181 | isa = XCBuildConfiguration;
182 | buildSettings = {
183 | ALWAYS_SEARCH_USER_PATHS = NO;
184 | ARCHS = armv7;
185 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
186 | CLANG_CXX_LIBRARY = "libc++";
187 | CLANG_ENABLE_MODULES = YES;
188 | CLANG_ENABLE_OBJC_ARC = YES;
189 | CLANG_WARN_BOOL_CONVERSION = YES;
190 | CLANG_WARN_CONSTANT_CONVERSION = YES;
191 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
192 | CLANG_WARN_EMPTY_BODY = YES;
193 | CLANG_WARN_ENUM_CONVERSION = YES;
194 | CLANG_WARN_INT_CONVERSION = YES;
195 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
196 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
197 | CODE_SIGN_IDENTITY = "iPhone Developer";
198 | COPY_PHASE_STRIP = NO;
199 | GCC_C_LANGUAGE_STANDARD = gnu99;
200 | GCC_DYNAMIC_NO_PIC = NO;
201 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
202 | GCC_OPTIMIZATION_LEVEL = 0;
203 | GCC_PREPROCESSOR_DEFINITIONS = (
204 | "DEBUG=1",
205 | "$(inherited)",
206 | );
207 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
208 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
209 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
210 | GCC_WARN_UNDECLARED_SELECTOR = YES;
211 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
212 | GCC_WARN_UNUSED_FUNCTION = YES;
213 | GCC_WARN_UNUSED_VARIABLE = YES;
214 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
215 | ONLY_ACTIVE_ARCH = YES;
216 | SDKROOT = iphoneos;
217 | TARGETED_DEVICE_FAMILY = 2;
218 | };
219 | name = Debug;
220 | };
221 | C33F1D431860F4A800D3EE14 /* Release */ = {
222 | isa = XCBuildConfiguration;
223 | buildSettings = {
224 | ALWAYS_SEARCH_USER_PATHS = NO;
225 | ARCHS = armv7;
226 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
227 | CLANG_CXX_LIBRARY = "libc++";
228 | CLANG_ENABLE_MODULES = YES;
229 | CLANG_ENABLE_OBJC_ARC = YES;
230 | CLANG_WARN_BOOL_CONVERSION = YES;
231 | CLANG_WARN_CONSTANT_CONVERSION = YES;
232 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
233 | CLANG_WARN_EMPTY_BODY = YES;
234 | CLANG_WARN_ENUM_CONVERSION = YES;
235 | CLANG_WARN_INT_CONVERSION = YES;
236 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
238 | CODE_SIGN_IDENTITY = "iPhone Distribution";
239 | COPY_PHASE_STRIP = YES;
240 | ENABLE_NS_ASSERTIONS = NO;
241 | GCC_C_LANGUAGE_STANDARD = gnu99;
242 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
245 | GCC_WARN_UNDECLARED_SELECTOR = YES;
246 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
247 | GCC_WARN_UNUSED_FUNCTION = YES;
248 | GCC_WARN_UNUSED_VARIABLE = YES;
249 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
250 | SDKROOT = iphoneos;
251 | TARGETED_DEVICE_FAMILY = 2;
252 | VALIDATE_PRODUCT = YES;
253 | };
254 | name = Release;
255 | };
256 | C33F1D451860F4A800D3EE14 /* Debug */ = {
257 | isa = XCBuildConfiguration;
258 | buildSettings = {
259 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
260 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
261 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
262 | GCC_DYNAMIC_NO_PIC = YES;
263 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
264 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
265 | GCC_PREFIX_HEADER = "";
266 | GCC_STRICT_ALIASING = NO;
267 | INFOPLIST_FILE = "iOSAppInAssembly/iOSAppInAssembly-Info.plist";
268 | LD_NO_PIE = YES;
269 | OTHER_CFLAGS = "-mno-thumb";
270 | OTHER_LDFLAGS = "";
271 | PRODUCT_NAME = "$(TARGET_NAME)";
272 | TARGETED_DEVICE_FAMILY = 1;
273 | VALID_ARCHS = armv7;
274 | WRAPPER_EXTENSION = app;
275 | };
276 | name = Debug;
277 | };
278 | C33F1D461860F4A800D3EE14 /* Release */ = {
279 | isa = XCBuildConfiguration;
280 | buildSettings = {
281 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
282 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
284 | GCC_DYNAMIC_NO_PIC = YES;
285 | GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
286 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
287 | GCC_PREFIX_HEADER = "";
288 | GCC_STRICT_ALIASING = NO;
289 | INFOPLIST_FILE = "iOSAppInAssembly/iOSAppInAssembly-Info.plist";
290 | LD_NO_PIE = YES;
291 | OTHER_CFLAGS = "-mno-thumb";
292 | OTHER_LDFLAGS = "";
293 | PRODUCT_NAME = "$(TARGET_NAME)";
294 | TARGETED_DEVICE_FAMILY = 1;
295 | VALID_ARCHS = armv7;
296 | WRAPPER_EXTENSION = app;
297 | };
298 | name = Release;
299 | };
300 | /* End XCBuildConfiguration section */
301 |
302 | /* Begin XCConfigurationList section */
303 | C33F1D131860F4A800D3EE14 /* Build configuration list for PBXProject "iOSAppInAssembly" */ = {
304 | isa = XCConfigurationList;
305 | buildConfigurations = (
306 | C33F1D421860F4A800D3EE14 /* Debug */,
307 | C33F1D431860F4A800D3EE14 /* Release */,
308 | );
309 | defaultConfigurationIsVisible = 0;
310 | defaultConfigurationName = Release;
311 | };
312 | C33F1D441860F4A800D3EE14 /* Build configuration list for PBXNativeTarget "iOSAppInAssembly" */ = {
313 | isa = XCConfigurationList;
314 | buildConfigurations = (
315 | C33F1D451860F4A800D3EE14 /* Debug */,
316 | C33F1D461860F4A800D3EE14 /* Release */,
317 | );
318 | defaultConfigurationIsVisible = 0;
319 | defaultConfigurationName = Release;
320 | };
321 | /* End XCConfigurationList section */
322 | };
323 | rootObject = C33F1D101860F4A800D3EE14 /* Project object */;
324 | }
325 |
--------------------------------------------------------------------------------
/iOSAppInAssembly/AppDelegate_ARMv7.s:
--------------------------------------------------------------------------------
1 | // AppDelegate_ARMv7.s
2 | // This is the file that will contain the class for our application's delegate.
3 |
4 | // Setup all strings that will be used in this file.
5 | .section __TEXT,__cstring
6 | AppDelegate_ParentClassName:
7 | .asciz "NSObject"
8 |
9 | .section __TEXT,__cstring
10 | AppDelegate_ClassName:
11 | .asciz "AppDelegate"
12 |
13 | .section __TEXT,__cstring
14 | AppDelegate_IvarName:
15 | .asciz "window"
16 |
17 | .section __TEXT,__cstring
18 | AppDelegate_IvarEncoding:
19 | .asciz "@"
20 |
21 | .section __TEXT,__cstring
22 | AppDelegate_MethodName:
23 | .asciz "application:didFinishLaunchingWithOptions:"
24 |
25 | .section __TEXT,__cstring
26 | AppDelegate_MethodEncoding:
27 | .asciz "c@:@@"
28 |
29 | .section __TEXT,__cstring
30 | AppDelegate_ScreenClassName:
31 | .asciz "UIScreen"
32 |
33 | .section __TEXT,__cstring
34 | AppDelegate_ScreenSingletonMethodName:
35 | .asciz "mainScreen"
36 |
37 | .section __TEXT,__cstring
38 | AppDelegate_ScreenSizePropertyName:
39 | .asciz "bounds"
40 |
41 | .section __TEXT,__cstring
42 | AppDelegate_WindowClassName:
43 | .asciz "UIWindow"
44 |
45 | .section __TEXT,__cstring
46 | AppDelegate_WindowAllocateMethodName:
47 | .asciz "alloc"
48 |
49 | .section __TEXT,__cstring
50 | AppDelegate_WindowInitMethodName:
51 | .asciz "initWithFrame:"
52 |
53 | .section __TEXT,__cstring
54 | AppDelegate_ViewControllerClassName:
55 | .asciz "UIViewController"
56 |
57 | .section __TEXT,__cstring
58 | AppDelegate_ViewControllerAllocateMethodName:
59 | .asciz "alloc"
60 |
61 | .section __TEXT,__cstring
62 | AppDelegate_ViewControllerInitMethodName:
63 | .asciz "init"
64 |
65 | .section __TEXT,__cstring
66 | AppDelegate_ViewControllerAttachViewMethodName:
67 | .asciz "setView:"
68 |
69 | .section __TEXT,__cstring
70 | AppDelegate_ViewControllerAttachMethodName:
71 | .asciz "setRootViewController:"
72 |
73 | .section __TEXT,__cstring
74 | AppDelegate_ViewClassName:
75 | .asciz "View"
76 |
77 | .section __TEXT,__cstring
78 | AppDelegate_ViewAllocateMethodName:
79 | .asciz "alloc"
80 |
81 | .section __TEXT,__cstring
82 | AppDelegate_ViewInitMethodName:
83 | .asciz "initWithFrame:"
84 |
85 | .section __TEXT,__cstring
86 | AppDelegate_WindowMakeVisibleMethodName:
87 | .asciz "makeKeyAndVisible"
88 |
89 |
90 | // Global variable for holding the class.
91 | .section __DATA,regular
92 | .align 4
93 | AppDelegate_Class:
94 | .long 0
95 |
96 | // Global variable for holding the window
97 | .section __DATA,regular
98 | .align 4
99 | AppDelegate_Window:
100 | .long 0
101 |
102 | .section __DATA,regular
103 | .align 4
104 | AppDelegate_ScreenSize:
105 | .float 0, 0, 0, 0 // x, y, width, height
106 |
107 | //
108 | // The setup method for the app delegate class.
109 | //
110 | // Parameters:
111 | // none.
112 | //
113 | // Results:
114 | // none.
115 | //
116 | // Registers used:
117 | //
118 | // r0-r3: Arguments
119 | // r4: Class Pointer.
120 | // r5-r6: Temporary values.
121 | // r7: Frame (stack) pointer
122 | // r8: Temporary value
123 | // r9: Scratch register
124 | // r10-r11: Temporary values.
125 | //
126 | // Stack Used:
127 | //
128 | // 4 bytes, offset 0: Parameter passing.
129 | //
130 | .section __TEXT,__text,regular,pure_instructions
131 | .global AppDelegate_Setup
132 | .align 4
133 | AppDelegate_Setup:
134 | push {r4-r7, lr} // save LR, R7, R4-R6
135 | add r7, sp, #12 // adjust R7 to point to saved R7
136 | push {r8, r10, r11} // save remaining GPRs (R8, R10, R11)
137 | vstmdb sp!, {d8-d15} // save VFP/Advanced SIMD registers D8
138 | sub sp, sp, #4 // Allocate stack storage
139 |
140 | // Before we can do anything else, we must first create a class to use as the application delegate. The basic process for this is as follows:
141 | //
142 | // 1: Fetch the superclass of the desired new class. (In this case, UIResponder)
143 | // 4: Create the new class.
144 | // 5: Save it out to a global varaible so that it can easily be re-used. (In this case, AppDelegate_Class)
145 | // 6: Setup any protocols that this class will conform to. (In this case, none)
146 | // 7: Setup any ivars that this class will use. (In this case, one, called window)
147 | // 8: Setup any methods that this class will implement. (In this case, the -application:didFinishLaunchingWithOptions: method)
148 | // 9: Register the class with the runtime.
149 | //
150 |
151 | // Parameter 1 (r0) will be the name of the superclass.
152 | // The superclass will then be stored in r0 after calling the function.
153 | mov r0, AppDelegate_ParentClassName
154 | bl _objc_getClass
155 |
156 | // Parameter 1 (r0) will be the superclass, which is already in register r0.
157 | // Parameter 2 (r1) will be the new class's name.
158 | // Parameter 3 (r2) will be the extra byte count of this class, in this case 0.
159 | // The new class will then be stored in r0 after calling the function.
160 | mov r1, AppDelegate_ClassName
161 | mov r2, #0
162 | bl _objc_allocateClassPair
163 |
164 | // We now have a perfectly working class inside register r0.
165 | // Now, we save it out to the global value, and our register used throughout the function.
166 | mov r1, AppDelegate_Class
167 | str r0, [r1]
168 | mov r4, r0
169 |
170 | // Next, we need to add the iVar to the class we have. This can be done with a single method call.
171 | //
172 | // Parameter 1 (r0) will be the class
173 | // Parameter 2 (r1) will be the ivar's name
174 | // Parameter 3 (r2) will be the size of the argument, which is the size of a pointer. On ARMv7, this is 4 bytes.
175 | // Parameter 4 (r3) will be the offset of the argument, in this case it will be 0.
176 | // Parameter 5 (Stack) will be the encoding of the argument
177 | //
178 | // The success of this function will then be stored in r0 after calling the function.
179 | mov r0, r4
180 | mov r1, AppDelegate_IvarName
181 | mov r2, #4
182 | mov r3, #0
183 | mov r5, AppDelegate_IvarEncoding
184 | str r5, [sp]
185 | bl _class_addIvar
186 |
187 | // Our next step is to register the method used for launching the app. We can do this in two steps.
188 | //
189 | // 1: Fetch the unique selector for the method we are implementing. (In this case, the -application:didFinishLaunchingWithOptions: method)
190 | // 2: Add the method to the class we have created.
191 |
192 | // To fetch the selector, we will use the function sel_getUid.
193 | //
194 | // Parameter 1 (r0) will be the name of the selector to get.
195 | //
196 | // The result of this function will then be stored in the r0 register.
197 | mov r0, AppDelegate_MethodName
198 | bl _sel_getUid
199 |
200 | // To add the method to the class, we will use the function class_addMethod.
201 | //
202 | // Parameter 1 (r0) will be the class.
203 | // Parameter 2 (r1) will be the selector (which is currently in r0).
204 | // Parameter 3 (r2) will be the address of the implementation.
205 | // Parameter 4 (r3) will be the encoding of the method.
206 | //
207 | // The success of this function will then be stored in r0 after calling the function.
208 | mov r1, r0
209 | mov r0, r4
210 | mov r2, AppDelegate_DidFinishLaunchingWithOptions
211 | mov r3, AppDelegate_MethodEncoding
212 | bl _class_addMethod
213 |
214 | // At this point, our class is fully set-up, and all that is left to do is register the class with the runtime.
215 | // This is done using the function objc_reigsterClassPair.
216 | //
217 | // Parameter 1 (r0) will be the class.
218 | //
219 | // This function has no results.
220 | mov r0, r4
221 | bl _objc_registerClassPair
222 |
223 | // We did it! Now the class should be all ready to go with the runtime, and our delegate's launching method will be called shortly.
224 | add sp, sp, #4 // Deallocate stack storage.
225 | vldmia sp!, {d8-d15} // restore VFP/Advanced SIMD registers
226 | pop {r8, r10, r11} // restore R8-R11
227 | pop {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR
228 |
229 | //
230 | // This method should be called when the application finishes launching.
231 | //
232 | // Parameters:
233 | // r0: self (id)
234 | // r1: _cmd (SEL)
235 | // r2: application (UIApplication *)
236 | // r3: options (NSDictionary *)
237 | //
238 | // Results:
239 | // r0: success (BOOL)
240 | //
241 | // Registers used:
242 | //
243 | // r0-r3: Arguments
244 | // r4: Window Pointer.
245 | // r5: View Controller Pointer.
246 | // r6: View Pointer.
247 | // r7: Frame (stack) pointer
248 | // r8,r10,r11: Temporary values.
249 | // r9: Scratch register
250 | //
251 | // Stack Used: 12 bytes total.
252 | //
253 | // 4 bytes, offset 8: self.
254 | // 4 bytes, offset 4: extra parameter.
255 | // 4 bytes, offset 0: extra parameter.
256 | //
257 | .section __TEXT,__text,regular,pure_instructions
258 | .align 4
259 | AppDelegate_DidFinishLaunchingWithOptions:
260 | push {r4-r7, lr} // save LR, R7, R4-R6
261 | add r7, sp, #12 // adjust R7 to point to saved R7
262 | push {r8, r10, r11} // save remaining GPRs (R8, R10, R11)
263 | vstmdb sp!, {d8-d15} // save VFP/Advanced SIMD registers D8
264 | sub sp, sp, #12 // Allocate stack space.
265 |
266 | // Save self off to the stack.
267 | str r0, [sp, #8]
268 |
269 | //
270 | // Our goal here is to create a window, view controller, and view to show on the screen.
271 | // This will be done with the following steps:
272 | //
273 | // 1: Fetch the size of the screen, using the UIScreen singleton.
274 | // 2: Create an instance of type UIWindow, and store it in self's window variable.
275 | // 3: Create a View Controller, and set that as the window's root controller.
276 | // 4: Create an instance of our view class, and add it to the view controller's heirarchy.
277 | // 5: Make the window the key window on the screen.
278 | //
279 |
280 | // Our first step is to get the size of the screen.
281 | // This poses quite the problem, because the 'bounds' property of the screen returns a struct.
282 | // Thus, we must use objc_msgSend_stret instead of the usual objc_msgSend.
283 | //
284 | // However, first we must get the singleton instance.
285 | //
286 | // Parameter 1 (r0) will be the name of the class to fetch.
287 | //
288 | // The found class will then be placed in the r0 register upon return. We will store it in the r8 register for now.
289 | mov r0, AppDelegate_ScreenClassName
290 | bl _objc_getClass
291 | mov r8, r0
292 |
293 | // The next step is to prepare the selector for use with objc_msgSend.
294 | // This will be done via sel_getUid
295 | //
296 | // Parameter 1 (r0) will be the name of the selector to fetch.
297 | //
298 | // The results of this function will be stored in the r0 register upon return.
299 | mov r0, AppDelegate_ScreenSingletonMethodName
300 | bl _sel_getUid
301 |
302 | // Now, we take the selector, and our target object, and use objc_msgSend to fetch the singleton.
303 | //
304 | // Parameter 1 (r0) will be the target of the message, in this case the UIScreen class, which we stored in the r8 register.
305 | // Parameter 2 (r1) will be the message to pass, in this case, '-mainScreen', which is currently in the r0 register.
306 | //
307 | // The results of this function (the singleton) will be placed in the r0 register upon return. We will then store it into the r8 register, as we no longer need the class there.
308 | mov r1, r0
309 | mov r0, r8
310 | bl _objc_msgSend
311 | mov r8, r0
312 |
313 | // Now that we have our singleton, the next step is to call the bounds method. We have to be careful with this, because of the struct return, but for the most part it is the same as any other method call.
314 | //
315 | // Before we can do that, if you haven't guessed by now, we need to convert our string into a selector.
316 | mov r0, AppDelegate_ScreenSizePropertyName
317 | bl _sel_getUid
318 |
319 | // Since we now have our blessed SEL, it is time to do the objc_msgSend_stret call.
320 | //
321 | // Parameter 1 (r0) will be the address of the struct in memory, which we store in AppDelegate_ScreenSize.
322 | // Parameter 2 (r1) will be the target of this message, which is our singleton, stored in the r8 register.
323 | // Parameter 3 (r2) will be the message to pass, which we just got from sel_getUid, and is in the r0 register.
324 |
325 | // Always return YES (1) to the calling function.
326 | mov r2, r0
327 | mov r1, r8
328 | mov r0, AppDelegate_ScreenSize
329 | bl _objc_msgSend_stret
330 |
331 | // Now that we have the screen size, it is time for us to create our window.
332 | // To create our window, we will need to fetch the class first, however.
333 | //
334 | // Parameter 1 (r0) will be the name of the class to fetch.
335 | //
336 | // The results of this function will be placed in the r0 register upon return. However, we will store it in the r8 register for now.
337 | mov r0, AppDelegate_WindowClassName
338 | bl _objc_getClass
339 | mov r8, r0
340 |
341 | // Next, we need to fetch the sel wthat we will use to allocate our window, using the sel_getUid function.
342 | //
343 | // Parameter 1 (r0) will be the name of the selector to fetch.
344 | //
345 | // The resutls of this function will be stored in the r0 register upon return.
346 | mov r0, AppDelegate_WindowAllocateMethodName
347 | bl _sel_getUid
348 |
349 | // Our next move is to actually allocate our class, using the objc_msgSend function.
350 | //
351 | // Parameter 1 (r0) will be the target of this message, in this case the class which is currently stored in r8.
352 | // Parameter 2 (r1) will be the message to pass to the target, which is currently in r0.
353 | //
354 | // The results of this function will be stored in the r0 register upon return, and we will move it into the r4 register.
355 | mov r1, r0
356 | mov r0, r8
357 | bl _objc_msgSend
358 | mov r4, r0
359 |
360 | // Now that we have our window, it's time to initialize it, but first we need to get our selector.
361 | //
362 | // Parameter 1 (r0) will be the name of the selector to fetch.
363 | //
364 | // The results of this function will be stored in the r0 register upon return.
365 | mov r0, AppDelegate_WindowInitMethodName
366 | bl _sel_getUid
367 |
368 | // To fully initialize the window, we need to pass our struct to the function.
369 | // This can simply be done by pushing the entire contents of the struct onto the stack. We will use objc_msgSend for this.
370 | //
371 | // Parameter 1 (r0) will be the target of this message, which is currently in r4.
372 | // Parameter 2 (r1) will be the message to send, which is currently in r0.
373 | // Parameter 3 (r2) will be the x element of the CGRect.
374 | // Parameter 4 (r3) will be the y element of the CGRect.
375 | // Parameter 5 (Stack, offset 0) will be the width element of the CGRect.
376 | // Parameter 6 (Stack, offset 4) will be the height element of the CGRect.
377 | //
378 | // The results of this function will be placed in the r0 register upon return. We will then retain it, and put it in our global variable.
379 | mov r1, r0
380 | mov r0, r4
381 |
382 | // CGRect Passing
383 | mov r8, AppDelegate_ScreenSize
384 | ldr r2, [r8] // load x element
385 | ldr r3, [r8, #4] // load y element
386 | ldr r10, [r8, #8] // load width element
387 | str r10, [sp] // store width to stack
388 | ldr r10, [r8, #12] // load height element
389 | str r10, [sp, #4] // store height to stack
390 |
391 | bl _objc_msgSend
392 | bl _objc_retain
393 |
394 | mov r1, AppDelegate_Window
395 | str r0, [r1]
396 |
397 | // Our window is now fully initialized. We need to then save it to self, which is currently on the stack.
398 | // The offset of the variable should be 4 bytes, as there is the sole 'isa' field that is store alongside our variable as well.
399 | ldr r0, [sp, #8]
400 | ldr r0, [r0]
401 | str r4, [r0, #4]
402 |
403 | // Now that we have set the ivar properly, it is time to allocate our view controller.
404 | // To do this, we will need to fetch the class and selector that we will use.
405 | // Obviously, we will start with objc_getClass.
406 | //
407 | // Parameter 1 (r0) will be the name of the class to fetch.
408 | //
409 | // The results of this function will be placed in the r0 register,
410 | // but we will move it to the r8 register for now.
411 | mov r0, AppDelegate_ViewControllerClassName
412 | bl _objc_getClass
413 | mov r8, r0
414 |
415 | // Before we can allocate our class, we need to fetch our selector (surprise surprise).
416 | //
417 | // Parameter 1 (r0) will be the name of the selector to fetch.
418 | //
419 | // The results of this function will be placed in the r0 register.
420 | mov r0, AppDelegate_ViewControllerAllocateMethodName
421 | bl _sel_getUid
422 |
423 | // Now we can finally allocate our class. Just like we've done before, we will use objc_msgSend for this.
424 | //
425 | // Parameter 1 (r0) will be the target of the message, which is in the r8 register.
426 | // Parameter 2 (r1) will be the message to pass, which is currently in the r0 register.
427 | //
428 | // The results of this function will be placed in the r0 register. We will store it in the r8 register for now.
429 | mov r1, r0
430 | mov r0, r8
431 | bl _objc_msgSend
432 | mov r8, r0
433 |
434 | // Next up is to get our selector for initializing the class.
435 | //
436 | // Parameter 1 (r0) will be the name of the selector to fetch.
437 | //
438 | // The results of this function will be placed in the r0 register.
439 | mov r0, AppDelegate_ViewControllerInitMethodName
440 | bl _sel_getUid
441 |
442 | // Finally, we can initialize our view controller. There's nothing really special about this, as we don't need to pass any fancy arguments to the method.
443 | //
444 | // Parameter 1 (r0) will be the target of the message, which is currently stored in the r8 register.
445 | // Parameter 2 (r1) will be the message to pass, which is currently stored in the r0 register.
446 | //
447 | // The results of this function will be placed in the r0 register, which we will then move to the r5 register.
448 | mov r1, r0
449 | mov r0, r8
450 | bl _objc_msgSend
451 | mov r5, r0
452 |
453 | // Now that we (finally) have our view controller. We should attach it to our window.
454 | //
455 | // Firstly, we should get our next selector through sel_getUid. You should know the drill by now.
456 | //
457 | // Parameter 1 (r0) will be the name of the selector to fetch.
458 | //
459 | // The results of this function will be placed in the r0 register.
460 | mov r0, AppDelegate_ViewControllerAttachMethodName
461 | bl _sel_getUid
462 |
463 | //
464 | // Next, we attach the view controller through the window via our best friend, objc_msgSend.
465 | //
466 | // Parameter 1 (r0) will be the target of the method, which is our window in the r4 register.
467 | // Parameter 2 (r1) will be the message to send, which is in the r0 register.
468 | // Parameter 3 (r2) will be the new view controller to attach, which is in the r5 register.
469 | //
470 | // This method has no results.
471 | mov r1, r0
472 | mov r0, r4
473 | mov r2, r5
474 | bl _objc_msgSend
475 |
476 | // Creating the view will be done in several steps:
477 | //
478 | // 1: Fetch our view class
479 | // 2: Allocate a new instance of our view class
480 | // 3: Set our new view instance as the view controller's view
481 |
482 | // It's time for us to get the view's class object. This will be done with objc_getClass
483 | //
484 | // Parameter 1 (r0) will be the name of the class to fetch.
485 | //
486 | // The found class will then be placed in the r0 register upon return. We will store it in the r8 register for now.
487 | mov r0, AppDelegate_ViewClassName
488 | bl _objc_getClass
489 | mov r8, r0
490 |
491 | // Next we need to get the selector for allocating our new view, using sel_getUid.
492 | //
493 | // Parameter 1 (r0) will be the name of the selector to fetch.
494 | //
495 | // The results of this function will be placed in the r0 register.
496 | mov r0, AppDelegate_ViewAllocateMethodName
497 | bl _sel_getUid
498 |
499 | // Now, we can allocate our class, using objc_msgSend.
500 | //
501 | // Parameter 1 (r0) will be the class to allocate an instance of, which is our class in the r8 register.
502 | // Parameter 2 (r1) will be the message to send, in this case the selector which is in the r0 register.
503 | //
504 | // The created instance will then be stored in the r0 function after completion, we will however store it in the r6 register.
505 | mov r1, r0
506 | mov r0, r8
507 | bl _objc_msgSend
508 | mov r6, r0
509 |
510 | // Next up is to initialize our class, once again done using our two favorite methods in the world, sel_getUid and objc_msgSend.
511 | //
512 | // Parameter 1 (r0) will be the name of the selector to fetch.
513 | //
514 | // The results of this function will be placed in the r0 register.
515 | mov r0, AppDelegate_ViewInitMethodName
516 | bl _sel_getUid
517 |
518 | // Now we fcan actually pass the message, using objc_msgSend
519 | //
520 | // Parameter 1 (r0) will be the object to pass the method to, in this case our view in the r6 register.
521 | // Parameter 2 (r1) will be the message to pass, which is currently in the r0 register.
522 | // Parameter 3 (r2) will be the x element of the CGRect.
523 | // Parameter 4 (r3) will be the y element of the CGRect.
524 | // Parameter 5 (Stack, offset 0) will be the width element of the CGRect.
525 | // Parameter 6 (Stack, offset 4) will be the height element of the CGRect.
526 | mov r1, r0
527 | mov r0, r6
528 |
529 | // CGRect Passing
530 | mov r8, AppDelegate_ScreenSize
531 | ldr r2, [r8] // load x element
532 | ldr r3, [r8, #4] // load y element
533 | ldr r10, [r8, #8] // load width element
534 | str r10, [sp] // store width to stack
535 | ldr r10, [r8, #12] // load height element
536 | str r10, [sp, #4] // store height to stack
537 |
538 | bl _objc_msgSend
539 |
540 | // We're just about done, there's only one thing really left to go, and that's attaching the view to our view controller.
541 | // Before we can do that, we must first fetch our selector.
542 | //
543 | // Parameter 1 (r0) will be the name of the selector to fetch.
544 | //
545 | // The results of this function will be placed in the r0 register.
546 | mov r0, AppDelegate_ViewControllerAttachViewMethodName
547 | bl _sel_getUid
548 |
549 | // Next, we can send the message to our view controller, using objc_msgSend
550 | //
551 | // Parameter 1 (r0) will be the target of this message, which is our view controller in register r5.
552 | // Parameter 2 (r1) will be the message to pass, which is currently in r0.
553 | // Parameter 3 (r2) will be the view to set, which is currently in the r6 register.
554 | //
555 | // This method returns no results.
556 | mov r1, r0
557 | mov r0, r5
558 | mov r2, r6
559 | bl _objc_msgSend
560 |
561 | // Now, make the window visible on-screen! To do this, we use (you guessed it!) sel_getUid and objc_msgSend.
562 | //
563 | // Parameter 1 (r0) will be the name of the selector to fetch.
564 | //
565 | // The results of this function will be placed in the r0 register.
566 | mov r0, AppDelegate_WindowMakeVisibleMethodName
567 | bl _sel_getUid
568 |
569 | //
570 | // Next up is to simply pass the message along with objc_msgSend.
571 | //
572 | // Parameter 1 (r0) will be the target of the message, which is our window in the r4 register.
573 | // Parameter 2 (r1) will be the message we're sending, which is currently in the r0 register.
574 | //
575 | // This method has no results.
576 | mov r1, r0
577 | mov r0, r4
578 | bl _objc_msgSend
579 |
580 | // WE DID IT! If done properly, we should now have stuff happening on the screen!
581 | // Next, we just release the various objects we have allocated.
582 | // Over the course of the method, we allocated the following objects:
583 | // Window (r4)
584 | // View Controller (r5)
585 | // View (r6)
586 | mov r0, r4
587 | bl _objc_release
588 |
589 | mov r0, r5
590 | bl _objc_release
591 |
592 | mov r0, r6
593 | bl _objc_release
594 |
595 | // Always return YES to the caller.
596 | mov r0, #1
597 |
598 | add sp, sp, #12 // Deallocate stack space.
599 | vldmia sp!, {d8-d15} // restore VFP/Advanced SIMD registers
600 | pop {r8, r10, r11} // restore R8-R11
601 | pop {r4-r7, pc} // restore R4-R6, saved R7, return to saved LR
--------------------------------------------------------------------------------