├── .gitignore ├── Chapter 01 ├── .gitignore ├── HelloWorld.s └── makefile ├── Chapter 02 ├── .gitignore ├── addexamp1.s ├── addexamp2.s ├── addexamps.s ├── codesnippets.s ├── makefile └── movexamps.s ├── Chapter 03 ├── .gitignore ├── HelloWorld.s ├── makefile ├── makefile2 └── testasm │ ├── testasm.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── testasm.xcscheme │ └── testasm │ └── main.c ├── Chapter 04 ├── .gitignore ├── case.s ├── codesnippets.s ├── makefile └── printdword.s ├── Chapter 05 ├── .gitignore ├── codesnippets.s ├── makefile └── upper.s ├── Chapter 06 ├── .gitignore ├── codesnippets.s ├── main.s ├── mainmacro.s ├── makefile ├── upper.s └── uppermacro.s ├── Chapter 07 ├── .gitignore ├── fileio.S ├── main.S ├── makefile └── upper.s ├── Chapter 09 ├── .gitignore ├── addexamp2.s ├── build ├── debug.s ├── makefile ├── test.s ├── upper.s ├── uppertst.c ├── uppertst4.c └── uppertst5.py ├── Chapter 10 └── ToUpper │ ├── Shared │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── ContentView.swift │ ├── ToUpper-Bridging-Header.h │ ├── ToUpperApp.swift │ ├── upper.h │ └── upper.s │ ├── ToUpper WatchKit App │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ └── Info.plist │ ├── ToUpper WatchKit Extension │ ├── Info.plist │ └── Preview Content │ │ └── Preview Assets.xcassets │ │ └── Contents.json │ ├── ToUpper.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ ├── ToUpper (iOS).xcscheme │ │ ├── ToUpper (macOS).xcscheme │ │ ├── ToUpper (tvOS).xcscheme │ │ └── ToUpper (watchOS).xcscheme │ ├── iOS │ └── Info.plist │ ├── macOS │ ├── Info.plist │ └── macOS.entitlements │ └── tvOS │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── App Icon & Top Shelf Image.brandassets │ │ ├── App Icon - App Store.imagestack │ │ │ ├── Back.imagestacklayer │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Front.imagestacklayer │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ └── Middle.imagestacklayer │ │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ ├── App Icon.imagestack │ │ │ ├── Back.imagestacklayer │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── Front.imagestacklayer │ │ │ │ ├── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ └── Middle.imagestacklayer │ │ │ │ ├── Content.imageset │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Top Shelf Image Wide.imageset │ │ │ └── Contents.json │ │ └── Top Shelf Image.imageset │ │ │ └── Contents.json │ └── Contents.json │ ├── Info.plist │ └── Preview Content │ └── Preview Assets.xcassets │ └── Contents.json ├── Chapter 11 ├── .gitignore ├── ans ├── debug.s ├── divexamp.s ├── makefile ├── matrixmult.s └── mulexamp.s ├── Chapter 12 ├── .gitignore ├── codesnippets.s ├── debug.s ├── distance.s ├── fpcomp.s ├── main.s ├── maincomp.s └── makefile ├── Chapter 13 ├── .gitignore ├── ans ├── distance.s ├── main.s ├── makefile └── matrixmultneon.s ├── Chapter 14 ├── .gitignore ├── main.s ├── makefile ├── upper.s ├── upper2.s ├── upper3.s └── upper4.s ├── Chapter 15 ├── .gitignore ├── makefile ├── makeods ├── upper.c └── upperghidra.c ├── Chapter 16 ├── .gitignore ├── main.s ├── mainpie.s ├── makefile ├── odcanary.txt ├── upper.c └── upper.s ├── LICENSE ├── README.md └── images └── Figure_9-1.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata 3 | *.o 4 | codesnippets 5 | *.dsym 6 | -------------------------------------------------------------------------------- /Chapter 01/.gitignore: -------------------------------------------------------------------------------- 1 | HelloWorld 2 | -------------------------------------------------------------------------------- /Chapter 01/HelloWorld.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to print "Hello World!" 3 | // to stdout. 4 | // 5 | // X0-X2 - parameters to Unix system calls 6 | // X16 - Mach System Call function number 7 | // 8 | 9 | .global _start // Provide program starting address to linker 10 | .align 4 // Make sure everything is aligned properly 11 | 12 | // Setup the parameters to print hello world 13 | // and then call the Kernel to do it. 14 | _start: mov X0, #1 // 1 = StdOut 15 | adr X1, helloworld // string to print 16 | mov X2, #13 // length of our string 17 | mov X16, #4 // Unix write system call 18 | svc #0x80 // Call kernel to output the string 19 | 20 | // Setup the parameters to exit the program 21 | // and then call the kernel to do it. 22 | mov X0, #0 // Use 0 return code 23 | mov X16, #1 // System call number 1 terminates this program 24 | svc #0x80 // Call kernel to terminate the program 25 | 26 | helloworld: .ascii "Hello World!\n" 27 | 28 | -------------------------------------------------------------------------------- /Chapter 01/makefile: -------------------------------------------------------------------------------- 1 | HelloWorld: HelloWorld.o 2 | ld -o HelloWorld HelloWorld.o -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 3 | 4 | HelloWorld.o: HelloWorld.s 5 | as -arch arm64 -o HelloWorld.o HelloWorld.s 6 | -------------------------------------------------------------------------------- /Chapter 02/.gitignore: -------------------------------------------------------------------------------- 1 | movexamps 2 | addexamp1 3 | addexamp2 4 | -------------------------------------------------------------------------------- /Chapter 02/addexamp1.s: -------------------------------------------------------------------------------- 1 | // 2 | // Examples of the ADD/MOVN instructions. 3 | // 4 | .global _start // Provide program starting address to linker 5 | .align 4 6 | 7 | // Multiply 2 by -1 by using MOVN and then adding 1 8 | _start: MOVN W0, #2 9 | ADD W0, W0, #1 10 | 11 | // Setup the parameters to exit the program 12 | // and then call the kernel to do it. 13 | // W0 is the return code and will be what we 14 | // calculated above. 15 | MOV X16, #1 // System call number 1 terminates this program 16 | SVC #0x80 // Call kernel to terminate the program 17 | -------------------------------------------------------------------------------- /Chapter 02/addexamp2.s: -------------------------------------------------------------------------------- 1 | // 2 | // Example of 128-Bit addition with the ADD/ADC instructions. 3 | // 4 | .global _start // Provide program starting address to linker 5 | .align 4 6 | 7 | // Load the registers with some data 8 | // First 64-bit number is 0x0000000000000003FFFFFFFFFFFFFFFF 9 | _start: MOV X2, #0x0000000000000003 10 | MOV X3, #0xFFFFFFFFFFFFFFFF //Assembler will change to MOVN 11 | // Second 64-bit number is 0x00000000000000050000000000000001 12 | MOV X4, #0x0000000000000005 13 | MOV X5, #0x0000000000000001 14 | 15 | ADDS X1, X3, X5 // Lower order word 16 | ADC X0, X2, X4 // Higher order word 17 | 18 | // Setup the parameters to exit the programc 19 | // and then call the kernel to do it. 20 | // X0 is the return code and will be what we 21 | // calculated above. 22 | MOV X16, #1 // System call number 1 terminates this program 23 | SVC #0x80 // Call kernel to terminate the program 24 | 25 | -------------------------------------------------------------------------------- /Chapter 02/addexamps.s: -------------------------------------------------------------------------------- 1 | 2 | @ 3 | @ Examples of the ADD/ADC instructions. 4 | @ 5 | .global _start @ Provide program starting address to linker 6 | 7 | @ Multiply 2 by -1 by using MVN and then adding 1 8 | _start: MVN R0, #2 9 | ADD R0, #1 10 | 11 | 12 | @ Setup the parameters to exit the program 13 | @ and then call Linux to do it. 14 | @ MOV R0, #0 @ Use 0 return code 15 | mov R7, #1 @ Service command code 1 terminates this program 16 | svc 0 @ Call linux to terminate the program 17 | 18 | 19 | -------------------------------------------------------------------------------- /Chapter 02/codesnippets.s: -------------------------------------------------------------------------------- 1 | // 2 | // This file contains the various code 3 | // snippets from Chapter 2. This ensures 4 | // they compile and gives you a chance 5 | // to single step through them. 6 | // They are labeled, so you can set a 7 | // breakpoint at the one you are interested in. 8 | 9 | .global _start 10 | .align 4 11 | 12 | _start: 13 | l1: ADD X0, XZR, X1 14 | MOV X0, X1 15 | ORR X0, XZR, X1 16 | // Load X2 with 0x1234FEDC4F5D6E3A first using MOV and MOVK 17 | l2: MOV X2, #0x6E3A 18 | MOVK X2, #0x4F5D, LSL #16 19 | MOVK X2, #0xFEDC, LSL #32 20 | MOVK X2, #0x1234, LSL #48 21 | l3: LSL X1, X2, #1 // Logical shift left 22 | LSR X1, X2, #1 // Logical shift right 23 | ASR X1, X2, #1 // Arithmetic shift right 24 | ROR X1, X2, #1 // Rotate right 25 | 26 | l4: LSL X1, X2, #1 // Logical shift left 27 | LSR X1, X2, #1 // Logical shift right 28 | ASR X1, X2, #1 // Arithmetic shift right 29 | ROR X1, X2, #1 // Rotate right 30 | 31 | l5: // Too big for #imm16 32 | MOV X1, #0xAB000000 33 | 34 | // Uncomment the next line if you want to see the 35 | // Assembler error for a constant that can't be 36 | // represented. 37 | // MOV X1, #0xABCDEF11 // Too big for #imm16 and can’t be represented. 38 | 39 | l6: // the immediate value can be 12-bits, so 0-4095 40 | // X2 = X1 + 4000 41 | ADD X2, X1, #4000 42 | // the shift on an immediate can be 0 or 12 43 | // X2 = X1 + 0x20000 44 | ADD X2, X1, #0x20, LSL 12 45 | // simple addition of two registers 46 | // X2 = X1 + X0 47 | ADD X2, X1, X0 48 | // addition of a register with a shifted register 49 | // X2 = X1 + (X0 * 4) 50 | ADD X2, X1, X0, LSL 2 51 | // With register extension options 52 | // X2 = X1 + signed extended byte(X0) 53 | ADD X2, X1, W0, SXTB 54 | // X2 = X1 + zero extended halfword(X0) * 4 55 | ADD X2, X1, W0, UXTH 2 56 | 57 | 58 | l8: ADDS X0, X0, #1 59 | 60 | l9: ADDS X1, X3, X5 // Lower order 64-bits 61 | ADC X0, X2, X4 // Higher order 64-bits 62 | 63 | // Setup the parameters to exit the program 64 | // and then call the kernel to do it. 65 | MOV X0, #0 // Use 0 return code 66 | MOV X16, #1 // System call number 1 terminates this program 67 | SVC #0x80 // Call kernel to terminate the program 68 | 69 | .data 70 | helloworld: .ascii "Hello World!" 71 | -------------------------------------------------------------------------------- /Chapter 02/makefile: -------------------------------------------------------------------------------- 1 | MEOBJS = movexamps.o 2 | AE1OBJS = addexamp1.o 3 | AE2OBJS = addexamp2.o 4 | CSOBJS = codesnippets.o 5 | 6 | ifdef DEBUG 7 | DEBUGFLGS = -g 8 | else 9 | DEBUGFLGS = 10 | endif 11 | 12 | LDFLAGS = -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 13 | 14 | %.o : %.s 15 | as $(DEBUGFLGS) $< -o $@ 16 | 17 | all: movexamps addexamp1 addexamp2 codesnippets 18 | 19 | movexamps: $(MEOBJS) 20 | ld -o movexamps $(LDFLAGS) $(MEOBJS) 21 | 22 | addexamp1: $(AE1OBJS) 23 | ld -o addexamp1 $(LDFLAGS) $(AE1OBJS) 24 | 25 | addexamp2: $(AE2OBJS) 26 | ld -o addexamp2 $(LDFLAGS) $(AE2OBJS) 27 | 28 | codesnippets: $(CSOBJS) 29 | ld -o codesnippets $(LDFLAGS) $(CSOBJS) 30 | 31 | clean: 32 | rm *.o movexamps addexamp1 addexamp2 33 | -------------------------------------------------------------------------------- /Chapter 02/movexamps.s: -------------------------------------------------------------------------------- 1 | // 2 | // Examples of the MOV instruction. 3 | // 4 | .global _start // Provide program starting address to linker 5 | .align 4 6 | 7 | // Load X2 with 0x1234FEDC4F5D6E3A first using MOV and MOVK 8 | _start: MOV X2, #0x6E3A 9 | MOVK X2, #0x4F5D, LSL #16 10 | MOVK X2, #0xFEDC, LSL #32 11 | MOVK X2, #0x1234, LSL #48 12 | 13 | // Just move W2 into W1 14 | MOV W1, W2 15 | 16 | // Now lets see all the shift versions of MOV 17 | // This does not appear to work with the clang assembler 18 | // MOV X1, X2, LSL #1 // Logical shift left 19 | // MOV X1, X2, LSR #1 // Logical shift right 20 | // MOV X1, X2, ASR #1 // Arithmetic shift right 21 | // MOV X1, X2, ROR #1 // Rotate right 22 | 23 | // Repeat the above shifts using the Assembler mnemonics. 24 | 25 | LSL X1, X2, #1 // Logical shift left 26 | LSR X1, X2, #1 // Logical shift right 27 | ASR X1, X2, #1 // Arithmetic shift right 28 | ROR X1, X2, #1 // Rotate right 29 | 30 | // Example that works with 8 bit immediate and shift 31 | MOV X1, #0xAB000000 // Too big for #imm16 32 | 33 | // Example that can't be represented and results in an error 34 | // Uncomment the instruction if you want to see the error 35 | // MOV X1, #0xABCDEF11 // Too big for #imm16 and can’t be represented. 36 | 37 | // Example of MVN 38 | MOVN W1, #45 39 | 40 | // Example of a MOV that the Assembler will change to MVN 41 | MOV W1, #0xFFFFFFFE // (-2) 42 | 43 | // Setup the parameters to exit the program 44 | // and then call the kernel to do it. 45 | MOV X0, #0 // Use 0 return code 46 | MOV X16, #1 // System call number 1 terminates this program 47 | SVC #0x80 // Call kernel to terminate the program 48 | -------------------------------------------------------------------------------- /Chapter 03/.gitignore: -------------------------------------------------------------------------------- 1 | HelloWorld 2 | -------------------------------------------------------------------------------- /Chapter 03/HelloWorld.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to print "Hello World!" 3 | // to stdout. 4 | // 5 | // X0-X2 - parameters to Unix system calls 6 | // X16 - Mach System Call function number 7 | // 8 | 9 | .global _start // Provide program starting address to linker 10 | .align 4 // Make sure everything is aligned properly 11 | 12 | // Setup the parameters to print hello world 13 | // and then call the Kernel to do it. 14 | _start: mov X0, #1 // 1 = StdOut 15 | adr X1, helloworld // string to print 16 | mov X2, #13 // length of our string 17 | mov X16, #4 // Unix write system call 18 | svc #0x80 // Call kernel to output the string 19 | 20 | // Setup the parameters to exit the program 21 | // and then call the kernel to do it. 22 | mov X0, #0 // Use 0 return code 23 | mov X16, #1 // System call number 1 terminates this program 24 | svc #0x80 // Call kernel to terminate the program 25 | 26 | helloworld: .ascii "Hello World!\n" 27 | 28 | -------------------------------------------------------------------------------- /Chapter 03/makefile: -------------------------------------------------------------------------------- 1 | TOOLPATH = $(shell dirname $(shell xcodebuild -find clang)) 2 | 3 | HelloWorld: HelloWorld.o 4 | $(TOOLPATH)/ld -o HelloWorld HelloWorld.o -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 5 | 6 | HelloWorld.o: HelloWorld.s 7 | $(TOOLPATH)/as -o HelloWorld.o HelloWorld.s 8 | -------------------------------------------------------------------------------- /Chapter 03/makefile2: -------------------------------------------------------------------------------- 1 | 2 | ifdef ANDROID 3 | AS = aarch64-linux-android-as 4 | LD = aarch64-linux-android-ld 5 | else 6 | AS = as 7 | LD = ld 8 | endif 9 | 10 | OBJS = HelloWorld.o 11 | 12 | %.o : %.s 13 | $(AS) $< -o $@ 14 | HelloWorld: $(OBJS) 15 | $(LD) -o HelloWorld $(OBJS) 16 | -------------------------------------------------------------------------------- /Chapter 03/testasm/testasm.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | CB32CA0A24AF83F100BF9B43 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = CB32CA0924AF83F100BF9B43 /* main.c */; }; 11 | CB32CA1124AF83FB00BF9B43 /* HelloWorld.s in Sources */ = {isa = PBXBuildFile; fileRef = CB32CA1024AF83FB00BF9B43 /* HelloWorld.s */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | CB32CA0424AF83F100BF9B43 /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = /usr/share/man/man1/; 19 | dstSubfolderSpec = 0; 20 | files = ( 21 | ); 22 | runOnlyForDeploymentPostprocessing = 1; 23 | }; 24 | /* End PBXCopyFilesBuildPhase section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | CB32CA0624AF83F100BF9B43 /* testasm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testasm; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | CB32CA0924AF83F100BF9B43 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 29 | CB32CA1024AF83FB00BF9B43 /* HelloWorld.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; name = HelloWorld.s; path = ../../HelloWorld.s; sourceTree = ""; }; 30 | /* End PBXFileReference section */ 31 | 32 | /* Begin PBXFrameworksBuildPhase section */ 33 | CB32CA0324AF83F100BF9B43 /* Frameworks */ = { 34 | isa = PBXFrameworksBuildPhase; 35 | buildActionMask = 2147483647; 36 | files = ( 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | CB32C9FD24AF83F100BF9B43 = { 44 | isa = PBXGroup; 45 | children = ( 46 | CB32CA0824AF83F100BF9B43 /* testasm */, 47 | CB32CA0724AF83F100BF9B43 /* Products */, 48 | ); 49 | sourceTree = ""; 50 | }; 51 | CB32CA0724AF83F100BF9B43 /* Products */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | CB32CA0624AF83F100BF9B43 /* testasm */, 55 | ); 56 | name = Products; 57 | sourceTree = ""; 58 | }; 59 | CB32CA0824AF83F100BF9B43 /* testasm */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | CB32CA1024AF83FB00BF9B43 /* HelloWorld.s */, 63 | CB32CA0924AF83F100BF9B43 /* main.c */, 64 | ); 65 | path = testasm; 66 | sourceTree = ""; 67 | }; 68 | /* End PBXGroup section */ 69 | 70 | /* Begin PBXNativeTarget section */ 71 | CB32CA0524AF83F100BF9B43 /* testasm */ = { 72 | isa = PBXNativeTarget; 73 | buildConfigurationList = CB32CA0D24AF83F100BF9B43 /* Build configuration list for PBXNativeTarget "testasm" */; 74 | buildPhases = ( 75 | CB32CA0224AF83F100BF9B43 /* Sources */, 76 | CB32CA0324AF83F100BF9B43 /* Frameworks */, 77 | CB32CA0424AF83F100BF9B43 /* CopyFiles */, 78 | ); 79 | buildRules = ( 80 | ); 81 | dependencies = ( 82 | ); 83 | name = testasm; 84 | productName = MacAs; 85 | productReference = CB32CA0624AF83F100BF9B43 /* testasm */; 86 | productType = "com.apple.product-type.tool"; 87 | }; 88 | /* End PBXNativeTarget section */ 89 | 90 | /* Begin PBXProject section */ 91 | CB32C9FE24AF83F100BF9B43 /* Project object */ = { 92 | isa = PBXProject; 93 | attributes = { 94 | LastUpgradeCheck = 1200; 95 | TargetAttributes = { 96 | CB32CA0524AF83F100BF9B43 = { 97 | CreatedOnToolsVersion = 12.0; 98 | }; 99 | }; 100 | }; 101 | buildConfigurationList = CB32CA0124AF83F100BF9B43 /* Build configuration list for PBXProject "testasm" */; 102 | compatibilityVersion = "Xcode 9.3"; 103 | developmentRegion = en; 104 | hasScannedForEncodings = 0; 105 | knownRegions = ( 106 | en, 107 | Base, 108 | ); 109 | mainGroup = CB32C9FD24AF83F100BF9B43; 110 | productRefGroup = CB32CA0724AF83F100BF9B43 /* Products */; 111 | projectDirPath = ""; 112 | projectRoot = ""; 113 | targets = ( 114 | CB32CA0524AF83F100BF9B43 /* testasm */, 115 | ); 116 | }; 117 | /* End PBXProject section */ 118 | 119 | /* Begin PBXSourcesBuildPhase section */ 120 | CB32CA0224AF83F100BF9B43 /* Sources */ = { 121 | isa = PBXSourcesBuildPhase; 122 | buildActionMask = 2147483647; 123 | files = ( 124 | CB32CA0A24AF83F100BF9B43 /* main.c in Sources */, 125 | CB32CA1124AF83FB00BF9B43 /* HelloWorld.s in Sources */, 126 | ); 127 | runOnlyForDeploymentPostprocessing = 0; 128 | }; 129 | /* End PBXSourcesBuildPhase section */ 130 | 131 | /* Begin XCBuildConfiguration section */ 132 | CB32CA0B24AF83F100BF9B43 /* Debug */ = { 133 | isa = XCBuildConfiguration; 134 | buildSettings = { 135 | ALWAYS_SEARCH_USER_PATHS = NO; 136 | CLANG_ANALYZER_NONNULL = YES; 137 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 138 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 139 | CLANG_CXX_LIBRARY = "libc++"; 140 | CLANG_ENABLE_MODULES = YES; 141 | CLANG_ENABLE_OBJC_ARC = YES; 142 | CLANG_ENABLE_OBJC_WEAK = YES; 143 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 144 | CLANG_WARN_BOOL_CONVERSION = YES; 145 | CLANG_WARN_COMMA = YES; 146 | CLANG_WARN_CONSTANT_CONVERSION = YES; 147 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 148 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 149 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 150 | CLANG_WARN_EMPTY_BODY = YES; 151 | CLANG_WARN_ENUM_CONVERSION = YES; 152 | CLANG_WARN_INFINITE_RECURSION = YES; 153 | CLANG_WARN_INT_CONVERSION = YES; 154 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 155 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 156 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 157 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 158 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 159 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 160 | CLANG_WARN_STRICT_PROTOTYPES = YES; 161 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 162 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 163 | CLANG_WARN_UNREACHABLE_CODE = YES; 164 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 165 | COPY_PHASE_STRIP = NO; 166 | DEBUG_INFORMATION_FORMAT = dwarf; 167 | ENABLE_STRICT_OBJC_MSGSEND = YES; 168 | ENABLE_TESTABILITY = YES; 169 | GCC_C_LANGUAGE_STANDARD = gnu11; 170 | GCC_DYNAMIC_NO_PIC = NO; 171 | GCC_NO_COMMON_BLOCKS = YES; 172 | GCC_OPTIMIZATION_LEVEL = 0; 173 | GCC_PREPROCESSOR_DEFINITIONS = ( 174 | "DEBUG=1", 175 | "$(inherited)", 176 | ); 177 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 178 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 179 | GCC_WARN_UNDECLARED_SELECTOR = YES; 180 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 181 | GCC_WARN_UNUSED_FUNCTION = YES; 182 | GCC_WARN_UNUSED_VARIABLE = YES; 183 | MACOSX_DEPLOYMENT_TARGET = 11.0; 184 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 185 | MTL_FAST_MATH = YES; 186 | ONLY_ACTIVE_ARCH = YES; 187 | SDKROOT = macosx; 188 | }; 189 | name = Debug; 190 | }; 191 | CB32CA0C24AF83F100BF9B43 /* Release */ = { 192 | isa = XCBuildConfiguration; 193 | buildSettings = { 194 | ALWAYS_SEARCH_USER_PATHS = NO; 195 | CLANG_ANALYZER_NONNULL = YES; 196 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 197 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 198 | CLANG_CXX_LIBRARY = "libc++"; 199 | CLANG_ENABLE_MODULES = YES; 200 | CLANG_ENABLE_OBJC_ARC = YES; 201 | CLANG_ENABLE_OBJC_WEAK = YES; 202 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 203 | CLANG_WARN_BOOL_CONVERSION = YES; 204 | CLANG_WARN_COMMA = YES; 205 | CLANG_WARN_CONSTANT_CONVERSION = YES; 206 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 207 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 208 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 209 | CLANG_WARN_EMPTY_BODY = YES; 210 | CLANG_WARN_ENUM_CONVERSION = YES; 211 | CLANG_WARN_INFINITE_RECURSION = YES; 212 | CLANG_WARN_INT_CONVERSION = YES; 213 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 214 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 215 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 216 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 217 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 218 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 219 | CLANG_WARN_STRICT_PROTOTYPES = YES; 220 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 221 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 222 | CLANG_WARN_UNREACHABLE_CODE = YES; 223 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 224 | COPY_PHASE_STRIP = NO; 225 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 226 | ENABLE_NS_ASSERTIONS = NO; 227 | ENABLE_STRICT_OBJC_MSGSEND = YES; 228 | GCC_C_LANGUAGE_STANDARD = gnu11; 229 | GCC_NO_COMMON_BLOCKS = YES; 230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 232 | GCC_WARN_UNDECLARED_SELECTOR = YES; 233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 234 | GCC_WARN_UNUSED_FUNCTION = YES; 235 | GCC_WARN_UNUSED_VARIABLE = YES; 236 | MACOSX_DEPLOYMENT_TARGET = 11.0; 237 | MTL_ENABLE_DEBUG_INFO = NO; 238 | MTL_FAST_MATH = YES; 239 | SDKROOT = macosx; 240 | }; 241 | name = Release; 242 | }; 243 | CB32CA0E24AF83F100BF9B43 /* Debug */ = { 244 | isa = XCBuildConfiguration; 245 | buildSettings = { 246 | CODE_SIGN_STYLE = Automatic; 247 | PRODUCT_NAME = "$(TARGET_NAME)"; 248 | }; 249 | name = Debug; 250 | }; 251 | CB32CA0F24AF83F100BF9B43 /* Release */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | CODE_SIGN_STYLE = Automatic; 255 | PRODUCT_NAME = "$(TARGET_NAME)"; 256 | }; 257 | name = Release; 258 | }; 259 | /* End XCBuildConfiguration section */ 260 | 261 | /* Begin XCConfigurationList section */ 262 | CB32CA0124AF83F100BF9B43 /* Build configuration list for PBXProject "testasm" */ = { 263 | isa = XCConfigurationList; 264 | buildConfigurations = ( 265 | CB32CA0B24AF83F100BF9B43 /* Debug */, 266 | CB32CA0C24AF83F100BF9B43 /* Release */, 267 | ); 268 | defaultConfigurationIsVisible = 0; 269 | defaultConfigurationName = Release; 270 | }; 271 | CB32CA0D24AF83F100BF9B43 /* Build configuration list for PBXNativeTarget "testasm" */ = { 272 | isa = XCConfigurationList; 273 | buildConfigurations = ( 274 | CB32CA0E24AF83F100BF9B43 /* Debug */, 275 | CB32CA0F24AF83F100BF9B43 /* Release */, 276 | ); 277 | defaultConfigurationIsVisible = 0; 278 | defaultConfigurationName = Release; 279 | }; 280 | /* End XCConfigurationList section */ 281 | }; 282 | rootObject = CB32C9FE24AF83F100BF9B43 /* Project object */; 283 | } 284 | -------------------------------------------------------------------------------- /Chapter 03/testasm/testasm.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Chapter 03/testasm/testasm.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Chapter 03/testasm/testasm.xcodeproj/xcshareddata/xcschemes/testasm.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Chapter 03/testasm/testasm/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // MacAs 4 | // 5 | // Created by Alexander von Below on 03.07.20. 6 | // 7 | 8 | #include 9 | 10 | extern void start( void ); 11 | 12 | int main(int argc, const char * argv[]) { 13 | // insert code here... 14 | start(); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 04/.gitignore: -------------------------------------------------------------------------------- 1 | printdword 2 | -------------------------------------------------------------------------------- /Chapter 04/case.s: -------------------------------------------------------------------------------- 1 | // AArch64 Assembly Code 2 | // Programming with 64-Bit ARM Assembly Language 3 | // Chapter #4: Excercise #2 (Page 81) 4 | // Jeff Rosengarden 08/27/20 5 | 6 | // 7 | // Create assembly code to emulate a switch/case statement 8 | 9 | // REGISTERS USED IN CODE 10 | // w11 - holds switch variable (1 thru 3 for this case statement) 11 | // w12 - holds the exit value that can be queried at the OS level with: echo $? 12 | // NOTE: w12 is transferred to w0 just before program exit so the 13 | // user can query the value with $? 14 | // w13 - work register used during calculation of mesg length 15 | 16 | // X0 - X2 hold parameters for Darwin/kernel system call 17 | // X0 - holds FD (file device) for output (stdout in this case) 18 | // X1 - holds address of mesg 19 | // X2 - holds length of mesg 20 | 21 | // X16 - used to hold Darwin/Kernel system call ID 22 | // X9 - holds calculated length of mesg 23 | 24 | 25 | 26 | 27 | .global _start // Provide program starting address 28 | .align 4 29 | 30 | _start: // this is the switch portion of the case statement 31 | // branching to select1, select2, select3 or default 32 | // labels based on value in w11 33 | 34 | 35 | // set "select" value (1 thru 3) in w11 36 | 37 | mov w12, 0xff // Prepare for error case 38 | cmp x0, #2 // Make sure we have precisely two arguments 39 | bne endit // If it is not: exit 40 | ldr x11, [x1, #8] // Get the pointer at x1 + 8 41 | ldrb w11, [x11] // Load the Byte pointed to by that pointer into w11 42 | sub w11, w11, #'0' // Subtract the ascii value for '0' 43 | 44 | cmp w11, #1 // will set Z flag to 1 if w11 - 1 == 0 45 | b.eq select1 // Z Flag == 1 ? 46 | cmp w11, #2 // will set Z flag to 1 if w11 - 2 == 0 47 | b.eq select2 // Z Flag == 1 ? 48 | cmp w11, #3 // will set Z flag to 1 if w11 - 3 == 0 49 | b.eq select3 // Z Flag == 1 ? 50 | 51 | // if w11 contains anything other than 1 thru 3 the program 52 | // will fall thru to the default label here 53 | 54 | // each label is a switch/case target based on the above select code 55 | 56 | default: mov w12, #99 // Use 99 return code for os query ($?) 57 | b break // same as switch/case break statement 58 | 59 | select1: mov w12, #1 // Use 1 return code for os query ($?) 60 | b break // same as switch/case break statement 61 | 62 | select2: mov w12, #2 // Use 2 return code for os query ($?) 63 | b break // same as switch/case break statement 64 | 65 | select3: mov w12, #3 // Use 3 return code for os query ($?) 66 | // b break not necessary here as it will 67 | // fall thru when done executing the 68 | // select3: case 69 | 70 | break: nop // nop here just to prove we actually 71 | // wind up here from each case statement 72 | // when debugging with lldb 73 | 74 | // code after the select/case would go 75 | // here 76 | 77 | ADRP X1, mesg@PAGE // start of message to display at OS level 78 | ADD X1, X1, mesg@PAGEOFF 79 | 80 | // calculate length of mesg (store it in x9) 81 | 82 | mov x9, #0 // zero out x9 before starting 83 | cloop: 84 | ldrb w13, [x1,x9] // get the next digit in mesg 85 | cmp w13, #255 // is it equal to 255 (0xFF) 86 | b.eq cend // yes - jump to cend 87 | add x9, x9, #1 // no - increase x9 count by 1 88 | b cloop // do it again 89 | cend: 90 | 91 | 92 | // Setup the parameters to print string 93 | // and then call Darwin/kernel to do it. 94 | MOV X0, #1 // 1 = StdOut 95 | 96 | 97 | 98 | MOV X2, X9 // length of our string 99 | MOV X16, #4 // Darwin write system call 100 | SVC #0x80 // Call Darwin/kernel to output the string 101 | 102 | 103 | // Setup the parameters to exit the program 104 | // and then call the kernel to do it. 105 | endit: 106 | mov W0, W12 // move return code into X0 so it can be 107 | // queried at OS level 108 | MOV X16, #1 // System call number 1 terminates this program 109 | SVC #0x80 // Call Darwin/kernel to terminate the program 110 | 111 | // return 0 112 | 113 | 114 | .data 115 | mesg: .byte 0x1B // clear screen 116 | .byte 'c' // and start msg at 117 | .byte 0 // top of screen 118 | .asciz "Chapter 4; Excercise #2\n" 119 | .asciz " - Emulate switch/case in assembly code\n\n" 120 | .asciz " -By Jeff Rosengarden\n" 121 | .asciz " -Created on Apple DTK\n\n" 122 | .asciz " Use: echo $? to see result of program\n" 123 | .asciz "\n\n\n" // 3 add'l blank lines 124 | .byte 255 125 | 126 | 127 | // alternative clear screen command (clears screen and starts msg @ bottom) 128 | // .asciz "\33[2J" 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /Chapter 04/codesnippets.s: -------------------------------------------------------------------------------- 1 | // 2 | // This file contains the various code 3 | // snippets from Chapter 4. This ensures 4 | // they compile and gives you a chance 5 | // to single step through them. 6 | // They are labeled, so you can set a 7 | // breakpoint at the one you are interested in. 8 | 9 | .global _start 10 | .p2align 2 11 | 12 | _start: 13 | // uncomment the next 2 lines if you want to see 14 | // an infinite loop 15 | l1: // MOV X1, #1 16 | //B _start 17 | 18 | l2: CMP X4, #45 19 | B.EQ _start 20 | 21 | CMP W4, #45 22 | B.EQ _start 23 | 24 | 25 | MOV W2, #1 // W2 holds I 26 | loop: // body of the loop goes here. 27 | 28 | // Most of the logic is at the end 29 | ADD W2, W2, #1 // I = I + 1 30 | CMP W2, #10 31 | B.LE loop // IF I <= 10 goto loop 32 | 33 | l4: MOV W2, #10 // R2 holds I 34 | loop2: // body of the loop goes here. 35 | 36 | // The CMP is redundant since we 37 | // are doing SUBS. 38 | SUBS W2, W2, #1 // I = I - 1 39 | B.NE loop2 // branch until I = 0 40 | 41 | l5: // W4 is X and has been initialized 42 | loop3: CMP W4, #5 43 | B.GE loopdone 44 | // … other statements in the loop body … 45 | B loop3 46 | loopdone: // program continues 47 | 48 | l6: CMP W5, #10 49 | B.GE elseclause 50 | 51 | // … if statements … 52 | 53 | B endif 54 | elseclause: 55 | 56 | // … else statements … 57 | 58 | endif: // continue on after the /then/else … 59 | 60 | // mask off the high order byte 61 | AND W6, W6, #0xFF000000 62 | 63 | // shift the byte down to the 64 | // low order position. 65 | LSR W6, W6, #24 66 | 67 | l8: ORR X6, X6, #0xFF 68 | 69 | l9: BIC X6, X6, #0xFF 70 | 71 | // Setup the parameters to exit the program 72 | // and then call the kernel to do it. 73 | MOV W0, #0 // Use 0 return code 74 | MOV X16, #1 // System call number 1 terminates this program 75 | SVC #0x80 // Call kernel to terminate the program 76 | 77 | .data 78 | helloworld: .ascii "Hello World!" 79 | -------------------------------------------------------------------------------- /Chapter 04/makefile: -------------------------------------------------------------------------------- 1 | OBJS = printdword.o 2 | CSOBJS = codesnippets.o 3 | 4 | ifdef DEBUG 5 | DEBUGFLGS = -g 6 | else 7 | DEBUGFLGS = 8 | endif 9 | 10 | LDFLAGS = -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 11 | 12 | %.o : %.s 13 | as $(DEBUGFLGS) $< -o $@ 14 | 15 | all: printdword codesnippets case 16 | 17 | printdword: $(OBJS) 18 | ld -o printdword $(LDFLAGS) $(OBJS) 19 | 20 | codesnippets: $(CSOBJS) 21 | ld -o codesnippets $(LDFLAGS) $(CSOBJS) 22 | 23 | case: case.o 24 | ld -o case $(LDFLAGS) case.o 25 | 26 | clean: 27 | rm *.o codesnippets printdword 28 | -------------------------------------------------------------------------------- /Chapter 04/printdword.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to print a register in hex 3 | // to stdout. 4 | // 5 | // X0-X2 - parameters to linux function services 6 | // X1 - is also address of byte we are writing 7 | // X4 - register to print 8 | // W5 - loop index 9 | // W6 - current character 10 | // X8 - linux function number 11 | // 12 | 13 | .global _start // Provide program starting address 14 | .align 4 15 | 16 | _start: MOV X4, #0x6E3A 17 | MOVK X4, #0x4F5D, LSL #16 18 | MOVK X4, #0xFEDC, LSL #32 19 | MOVK X4, #0x1234, LSL #48 20 | 21 | // Set X1 to the end of the destination 22 | ADRP X1, hexstr@PAGE 23 | ADD X1, X1, hexstr@PAGEOFF 24 | ADD X1, X1, #17 25 | 26 | // The loop is FOR W5 = 16 TO 1 STEP -1 27 | MOV W5, #16 // 16 digits to print 28 | loop: AND W6, W4, #0xf // mask of least sig digit 29 | // If W6 >= 10 then goto letter 30 | CMP W6, #10 // is 0-9 or A-F 31 | B.GE letter 32 | // Else its a number so convert to an ASCII digit 33 | ADD W6, W6, #'0' 34 | B cont // goto to end if 35 | letter: // handle the digits A to F 36 | ADD W6, W6, #('A'-10) 37 | cont: // end if 38 | STRB W6, [X1] // store ascii digit 39 | SUB X1, X1, #1 // decrement address for next digit 40 | LSR X4, X4, #4 // shift off the digit we just processed 41 | 42 | // next W5 43 | SUBS W5, W5, #1 // step W5 by -1 44 | B.NE loop // another for loop if not done 45 | 46 | // Setup the parameters to print our hex number 47 | // and then call Linux to do it. 48 | MOV X0, #1 // 1 = StdOut 49 | ADRP X1, hexstr@PAGE // start of string 50 | ADD X1, X1, hexstr@PAGEOFF 51 | MOV X2, #19 // length of our string 52 | MOV X16, #4 // linux write system call 53 | SVC #0x80 // Call linux to output the string 54 | 55 | // Setup the parameters to exit the program 56 | // and then call the kernel to do it. 57 | MOV X0, #0 // Use 0 return code 58 | MOV X16, #1 // System call number 1 terminates this program 59 | SVC #0x80 // Call kernel to terminate the program 60 | 61 | .data 62 | hexstr: .ascii "0x123456789ABCDEFG\n" 63 | 64 | -------------------------------------------------------------------------------- /Chapter 05/.gitignore: -------------------------------------------------------------------------------- 1 | upper 2 | -------------------------------------------------------------------------------- /Chapter 05/codesnippets.s: -------------------------------------------------------------------------------- 1 | // 2 | // This file contains the various code 3 | // snippets from Chapter 5. This ensures 4 | // they compile and gives you a chance 5 | // to single step through them. 6 | // They are labeled, so you can set a 7 | // breakpoint at the one you are interested in. 8 | 9 | .global _start 10 | .global _l9 11 | 12 | .data 13 | l1: .byte 74, 0112, 0b01001010, 0x4A, 0X4a, 'J', 'H' + 2 14 | .word 0x1234ABCD, -1434 15 | .quad 0x123456789ABCDEF0 16 | .ascii "Hello World\n" 17 | 18 | l2: .byte -0x45, -33, ~0b00111001 19 | 20 | l3: .fill 10, 4, 0 21 | 22 | l4: .rept 3 23 | .byte 0, 1, 2 24 | .endr 25 | 26 | .byte 0, 1, 2 27 | .byte 0, 1, 2 28 | .byte 0, 1, 2 29 | 30 | l5: .byte 0x3F 31 | .align 4 32 | .word 0x12345678 33 | 34 | .text 35 | 36 | _start: 37 | l6: ADRP X1, helloworld@PAGE 38 | ADD X1, X1, helloworld@PAGEOFF 39 | ADR X1, helloworld2 40 | 41 | l7: LDR X1, =0x1234ABCD1234ABCD 42 | 43 | l8: 44 | // load the address of mynumber into X1 45 | ADRP X1, mynumber@PAGE 46 | ADD X1, X1, mynumber@PAGEOFF 47 | // load the word stored at mynumber into X2 48 | LDR X2, [X1] 49 | 50 | 51 | _l9: ADRP X1, arr1@PAGE 52 | ADD X1, X1, arr1@PAGEOFF 53 | 54 | l10: // Load the first element 55 | LDR W2, [X1] 56 | // Load element 3 57 | // The elements count from 0, so 2 is 58 | // the third one. Each word is 4 bytes, 59 | // so we need to multiply by 4 60 | LDR W2, [X1, #(2 * 4)] 61 | 62 | 63 | l11: // The 3rd element is still number 2 64 | MOV X3, #(2 * 4) 65 | // Add the offset in X3 to X1 to get our element. 66 | LDR W2, [X1, X3] 67 | 68 | l12: LDR W2, [X1, #-(2 * 4)] 69 | MOV X3, #(-2 * 4) 70 | LDR W2, [X1, X3] 71 | 72 | l13: // Our array is of WORDs. 2 is the index 73 | MOV X3, #2 74 | // Shift X3 left by 2 positions to multiply 75 | // by 4 to get the correct address. 76 | LDR W2, [X1, X3, LSL #2] 77 | 78 | 79 | l14: LDR W2, [X1, #(2 * 4)]! 80 | 81 | ADRP X2, arr1@PAGE 82 | ADD X2, X2, arr1@PAGEOFF 83 | l15: // Load X1 with the memory pointed to by X2 84 | // Then do X2 = X2 + 2 85 | LDR X1, [X2], #2 86 | 87 | l16: ADRP X1, myoctaword@PAGE 88 | ADD X1, X1, myoctaword@PAGEOFF 89 | LDP X2, X3, [X1] 90 | STP X2, X3, [X1] 91 | 92 | // Setup the parameters to exit the program 93 | // and then call the kernel to do it. 94 | mov X0, #0 // Use 0 return code 95 | mov X16, #1 // System call number 1 terminates this program 96 | svc #0x80 // Call kernel to terminate the program 97 | helloworld2: .ascii "Hello World!" 98 | 99 | .data 100 | helloworld: .ascii "Hello World!" 101 | .align 4 102 | mynumber: .quad 0x123456789ABCDEF0 103 | arr1: .fill 10, 4, 0 104 | myoctaword: .octa 0x12345678876543211234567887654321 105 | -------------------------------------------------------------------------------- /Chapter 05/makefile: -------------------------------------------------------------------------------- 1 | CSOBJS = codesnippets.o 2 | UPPEROBJS = upper.o 3 | 4 | ifdef DEBUG 5 | DEBUGFLGS = -g 6 | else 7 | DEBUGFLGS = 8 | endif 9 | LSTFLGS = 10 | 11 | LDFLAGS = -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 12 | 13 | all: codesnippets upper 14 | 15 | %.o : %.s 16 | as $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 17 | codesnippets: $(CSOBJS) 18 | ld -o codesnippets $(LDFLAGS) $(CSOBJS) 19 | 20 | upper: $(UPPEROBJS) 21 | ld -o upper $(LDFLAGS) $(UPPEROBJS) 22 | 23 | clean: 24 | rm -f *.o upper codesnippets 25 | -------------------------------------------------------------------------------- /Chapter 05/upper.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X0-X2 - parameters to linux function services 6 | // X3 - address of output string 7 | // X4 - address of input string 8 | // W5 - current character being processed 9 | // X8 - linux function number 10 | // 11 | 12 | .global _start // Provide program starting address to linker 13 | .p2align 2 14 | 15 | _start: ADRP X4, instr@PAGE // start of input string 16 | ADD X4, X4, instr@PAGEOFF 17 | ADRP X3, outstr@PAGE // address of output string 18 | ADD X3, X3, outstr@PAGEOFF 19 | // The loop is until byte pointed to by X1 is non-zero 20 | loop: LDRB W5, [X4], #1 // load character and increment pointer 21 | // If W5 > 'z' then goto cont 22 | CMP W5, #'z' // is letter > 'z'? 23 | B.GT cont 24 | // Else if W5 < 'a' then goto end if 25 | CMP W5, #'a' 26 | B.LT cont // goto to end if, if < 'a' 27 | // if we got here then the letter is lower case, so convert it. 28 | SUB W5, W5, #('a'-'A') 29 | cont: // end if 30 | STRB W5, [X3], #1 // store character to output str 31 | CMP W5, #0 // stop on hitting a null character 32 | B.NE loop // loop if character isn't null 33 | 34 | // Setup the parameters to print our hex number 35 | // and then call the Kernel to do it. 36 | MOV X0, #1 // 1 = StdOut 37 | ADRP X1, outstr@PAGE // string to print 38 | ADD X1, X1, outstr@PAGEOFF 39 | SUB X2, X3, X1 // get the length by subtracting the pointers 40 | MOV X16, #4 // Unix write system call 41 | SVC #0x80 // Call kernel to output the string 42 | 43 | // Setup the parameters to exit the program 44 | // and then call the kernel to do it. 45 | mov X0, #0 // Use 0 return code 46 | mov X16, #1 // System call number 1 terminates this program 47 | svc #0x80 // Call kernel to terminate the program 48 | 49 | .data 50 | instr: .asciz "This is our Test String that we will convert.\n" 51 | outstr: .fill 255, 1, 0 52 | 53 | -------------------------------------------------------------------------------- /Chapter 06/.gitignore: -------------------------------------------------------------------------------- 1 | upper 2 | uppermacro 3 | -------------------------------------------------------------------------------- /Chapter 06/codesnippets.s: -------------------------------------------------------------------------------- 1 | // 2 | // This file contains the various code 3 | // snippets from Chapter 6. This ensures 4 | // they compile and gives you a chance 5 | // to single step through them. 6 | // They are labeled, so you can set a 7 | // breakpoint at the one you are interested in. 8 | 9 | .global _start 10 | .p2align 2 11 | 12 | _start: 13 | l1: STR X0, [SP, #-16]! 14 | LDR X0, [SP], #16 15 | STP X0, X1, [SP, #-16]! 16 | LDP X0, X1, [SP], #16 17 | 18 | l2: // … other code ... 19 | BL myfunc 20 | MOV X1, #4 21 | // … more code … 22 | 23 | B l3 24 | 25 | myfunc: // do some work 26 | RET 27 | 28 | l3: // … other code ... 29 | BL myfuncb 30 | MOV X1, #4 31 | // … more code … 32 | 33 | B l4 34 | 35 | myfuncb: STR LR, [SP, #-16]! // PUSH LR 36 | // do some work … 37 | BL myfuncb2 38 | // do some more work... 39 | LDR LR, [SP], #16 // POP LR 40 | RET 41 | myfuncb2: // do some work .... 42 | RET 43 | 44 | l4: SUB SP, SP, #16 45 | 46 | l5: STR W0, [SP] // Store a 47 | STR W1, [SP, #4] // Store b 48 | STR W2, [SP, #8] // Store c 49 | 50 | l6: ADD SP, SP, #16 51 | 52 | l7: SUB FP, SP, #16 53 | SUB SP, SP, #16 54 | 55 | l8: STR W0, [FP] // Store a 56 | STR W1, [FP, #-4] // Store b 57 | STR W2, [FP, #-8] // Store c 58 | 59 | ADD SP, SP, #16 60 | 61 | l9: BL SUMFN 62 | B l10 63 | 64 | // Simple function that takes 2 parameters 65 | // VAR1 and VAR2. The function adds them, 66 | // storing the result in a variable SUM. 67 | // The function returns the sum. 68 | // It is assumed this function does other work, 69 | // including other functions. 70 | 71 | // Define our variables 72 | .equ VAR1, 0 73 | .equ VAR2, 4 74 | .equ SUM, 8 75 | 76 | SUMFN: STP LR, FP, [SP, #-16]! 77 | SUB FP, SP, #16 78 | SUB SP, SP, #16 // room for 3 32-bit values 79 | STR W0, [FP, #VAR1] // save first param. 80 | STR W1, [FP, #VAR2] // save second param. 81 | 82 | // Do a bunch of other work, but don’t change SP. 83 | 84 | LDR W4, [FP, #VAR1] 85 | LDR W5, [FP, #VAR2] 86 | ADD W6, W4, W5 87 | STR W6, [FP, #SUM] 88 | 89 | // Do other work 90 | 91 | // Function Epilog 92 | LDR W0, [FP, #SUM] // load sum to return 93 | ADD SP, SP, #16 // Release local vars 94 | LDP LR, FP, [SP], #16 // Restore LR, FP 95 | RET 96 | 97 | .macro PUSH1 register 98 | STR \register, [SP, #-16]! 99 | .endmacro 100 | .macro POP1 register 101 | LDR \register, [SP], #16 102 | .endmacro 103 | .macro PUSH2 register1, register2 104 | STP \register1, \register2, [SP, #-16]! 105 | .endmacro 106 | .macro POP2 register1, register2 107 | LDP \register1, \register2, [SP], #16 108 | .endmacro 109 | 110 | Myfunction: 111 | PUSH1 LR 112 | PUSH2 X20, X23 113 | // function body … 114 | POP2 X20, X23 115 | POP1 LR 116 | RET 117 | 118 | l10: 119 | 120 | // Setup the parameters to exit the program 121 | // and then call Linux to do it. 122 | MOV X0, #0 // Use 0 return code 123 | mov X16, #1 // System call number 1 terminates this program 124 | svc #0x80 // Call kernel to terminate the program 125 | -------------------------------------------------------------------------------- /Chapter 06/main.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case by calling a function. 4 | // 5 | // X0-X2 - parameters to linux function services 6 | // X1 - address of output string 7 | // X0 - address of input string 8 | // X8 - linux function number 9 | // 10 | 11 | .global _start // Provide program starting address to linker 12 | .p2align 2 13 | 14 | _start: ADRP X0, instr@PAGE // start of input string 15 | ADD X0, X0, instr@PAGEOFF 16 | ADRP X1, outstr@PAGE // address of output string 17 | ADD X1, X1, outstr@PAGEOFF 18 | 19 | BL toupper 20 | 21 | // Setup the parameters to print our hex number 22 | // and then call the kernel to do it. 23 | MOV X2,X0 // return code is the length of the string 24 | 25 | MOV X0, #1 // 1 = StdOut 26 | ADRP X1, outstr@PAGE // start of string 27 | ADD X1, X1, outstr@PAGEOFF 28 | MOV X16, #4 // Unix write system call 29 | SVC #0x80 // Call kernel to output the string 30 | 31 | // Setup the parameters to exit the program 32 | // and then call the kernel to do it. 33 | MOV X0, #0 // Use 0 return code 34 | MOV X16, #1 // System call number 1 terminates this program 35 | SVC #0x80 // Call kernel to terminate the program 36 | 37 | .data 38 | instr: .asciz "This is our Test String that we will convert.\n" 39 | outstr: .fill 255, 1, 0 40 | 41 | -------------------------------------------------------------------------------- /Chapter 06/mainmacro.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case by calling a function. 4 | // 5 | // X0-X2 - parameters to linux function services 6 | // X1 - address of output string 7 | // X0 - address of input string 8 | // X2 - original address of input string 9 | // X8 - linux function number 10 | // 11 | 12 | .include "uppermacro.s" 13 | 14 | .global _start // Provide program starting address to linker 15 | .align 4 16 | 17 | _start: 18 | // Convert tststr to uppercase 19 | toupper tststr, buffer 20 | 21 | // Setup the parameters to print 22 | // and then call the kernel to do it. 23 | MOV X2,X0 // return code is the length of the string 24 | 25 | MOV X0, #1 // 1 = StdOut 26 | ADRP X1, buffer@PAGE // string to print 27 | ADD X1, X1, buffer@PAGEOFF 28 | MOV X16, #4 // Unix write system call 29 | SVC #0x80 // Call kernel to output the string 30 | 31 | // Convert tststr2 to uppercase 32 | toupper tststr2, buffer 33 | 34 | // Setup the parameters to print 35 | // and then call the kernel to do it. 36 | MOV X2,X0 // return code is the length of the string 37 | 38 | MOV X0, #1 // 1 = StdOut 39 | ADRP X1, buffer@PAGE // string to print 40 | ADD X1, X1, buffer@PAGEOFF 41 | MOV X16, #4 // Unix write system call 42 | SVC #0x80 // Call kernel to output the string 43 | 44 | // Setup the parameters to exit the program 45 | // and then call the kernel to do it. 46 | MOV X0, #0 // Use 0 return code 47 | MOV X16, #1 // System call number 1 terminates this program 48 | SVC #0x80 // Call kernel to terminate the program 49 | 50 | .data 51 | tststr: .asciz "This is our Test String that we will convert.\n" 52 | tststr2: .asciz "A second string to upper case!!\n" 53 | buffer: .fill 255, 1, 0 54 | 55 | -------------------------------------------------------------------------------- /Chapter 06/makefile: -------------------------------------------------------------------------------- 1 | CSOBJS = codesnippets.o 2 | UPPEROBJS = main.o upper.o 3 | UPPERMACOBJS = mainmacro.o 4 | 5 | ifdef DEBUG 6 | DEBUGFLGS = -g 7 | else 8 | DEBUGFLGS = 9 | endif 10 | LSTFLGS = 11 | 12 | all: upper uppermacro codesnippets 13 | 14 | LDFLAGS = -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 15 | 16 | mainmacro.o: mainmacro.s uppermacro.s 17 | as $(DEBUGFLGS) $(LSTFLGS) -arch arm64 $< -o mainmacro.o 18 | 19 | %.o : %.s 20 | as $(DEBUGFLGS) $(LSTFLGS) -arch arm64 $< -o $@ 21 | codesnippets: $(CSOBJS) 22 | ld -o codesnippets $(LDFLAGS) $(CSOBJS) 23 | 24 | upper: $(UPPEROBJS) 25 | ld -o upper $(LDFLAGS) $(UPPEROBJS) 26 | 27 | uppermacro: $(UPPERMACOBJS) 28 | ld -o uppermacro $(LDFLAGS) $(UPPERMACOBJS) 29 | 30 | clean: 31 | rm -f $(CSOBJS) $(UPPERMACOBJS) $(UPPEROBJS) upper uppermacro uppermacro.o codesnippets 32 | -------------------------------------------------------------------------------- /Chapter 06/upper.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X4 - original output string for length calc. 8 | // W5 - current character being processed 9 | // 10 | 11 | .global toupper // Allow other files to call this routine 12 | .align 4 13 | 14 | toupper: MOV X4, X1 15 | // The loop is until byte pointed to by X1 is non-zero 16 | loop: LDRB W5, [X0], #1 // load character and increment pointer 17 | // If W5 > 'z' then goto cont 18 | CMP W5, #'z' // is letter > 'z'? 19 | B.GT cont 20 | // Else if W5 < 'a' then goto end if 21 | CMP W5, #'a' 22 | B.LT cont // goto to end if 23 | // if we got here then the letter is lower case, so convert it. 24 | SUB W5, W5, #('a'-'A') 25 | cont: // end if 26 | STRB W5, [X1], #1 // store character to output str 27 | CMP W5, #0 // stop on hitting a null character 28 | B.NE loop // loop if character isn't null 29 | SUB X0, X1, X4 // get the length by subtracting the pointers 30 | RET // Return to caller 31 | -------------------------------------------------------------------------------- /Chapter 06/uppermacro.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X2 - original output string for length calc. 8 | // W3 - current character being processed 9 | // 10 | 11 | // label 1 = loop 12 | // label 2 = cont 13 | 14 | .macro toupper instr, outstr 15 | ADRP X0, \instr@PAGE 16 | ADD X0, X0, \instr@PAGEOFF 17 | ADRP X1, \outstr@PAGE 18 | ADD X1, X1, \outstr@PAGEOFF 19 | MOV X2, X1 20 | // The loop is until byte pointed to by X1 is non-zero 21 | 1: LDRB W3, [X0], #1 // load character and increment pointer 22 | // If R5 > 'z' then goto cont 23 | CMP W3, #'z' // is letter > 'z'? 24 | B.GT 2f 25 | // Else if R5 < 'a' then goto end if 26 | CMP W3, #'a' 27 | B.LT 2f // goto to end if 28 | // if we got here then the letter is lower case, so convert it. 29 | SUB W3, W3, #('a'-'A') 30 | 2: // end if 31 | STRB W3, [X1], #1 // store character to output str 32 | CMP W3, #0 // stop on hitting a null character 33 | B.NE 1b // loop if character isn't null 34 | SUB X0, X1, X2 // get the length by subtracting the pointers 35 | .endm 36 | -------------------------------------------------------------------------------- /Chapter 07/.gitignore: -------------------------------------------------------------------------------- 1 | upper 2 | upper.txt 3 | -------------------------------------------------------------------------------- /Chapter 07/fileio.S: -------------------------------------------------------------------------------- 1 | // Various macros to perform file I/O 2 | 3 | // The fd parameter needs to be a register. 4 | // Uses X0-X3, X16. 5 | // Return code is in X0. 6 | 7 | #include 8 | 9 | .equ O_RDONLY, 0 10 | .equ O_WRONLY, 1 11 | .equ O_CREAT, 0x00000200 12 | .equ S_RDWR, 0666 13 | .equ AT_FDCWD, -2 14 | 15 | .macro openFile fileName, flags 16 | mov X0, #AT_FDCWD 17 | adrp X1, \fileName@PAGE 18 | add X1, X1, \fileName@PAGEOFF 19 | mov X2, #\flags 20 | mov X3, #S_RDWR // RW access rights 21 | mov X16, #SYS_openat 22 | svc #0x80 23 | .endm 24 | .macro readFile fd, buffer, length 25 | mov X0, \fd // file descriptor 26 | adrp X1, \buffer@PAGE 27 | add X1, X1, \buffer@PAGEOFF 28 | mov X2, #\length 29 | mov X16, #SYS_read 30 | svc #0x80 31 | .endm 32 | .macro writeFile fd, buffer, length 33 | mov X0, \fd // file descriptor 34 | adrp X1, \buffer@PAGE 35 | add X1, X1, \buffer@PAGEOFF 36 | mov X2, \length 37 | mov X16, #SYS_write 38 | svc #0x80 39 | .endm 40 | .macro flushClose fd 41 | //fsync syscall 42 | mov X0, \fd 43 | mov X16, #SYS_fsync 44 | svc #0x80 45 | 46 | //close syscall 47 | mov X0, \fd 48 | mov X16, #SYS_close 49 | svc #0x80 50 | .endm 51 | -------------------------------------------------------------------------------- /Chapter 07/main.S: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case by calling a function. 4 | // 5 | // X0-X2, X16 - used by macros to call kernel 6 | // X11 - input file descriptor 7 | // X9 - output file descriptor 8 | // X10 - number of characters read 9 | // 10 | 11 | //#include 12 | .equ O_RDONLY, 0 13 | #include "fileio.S" 14 | 15 | .equ BUFFERLEN, 250 16 | 17 | .global _start // Provide program starting address to linker 18 | .align 4 19 | 20 | _start: MOV X0, #-1 21 | openFile inFile, O_RDONLY 22 | MOV X11, X0 // save file descriptor (or error) 23 | B.CC nxtfil // carry clear, file opened ok 24 | MOV X1, #1 // stdout 25 | ADRP X2, inpErrsz@PAGE // Error msg 26 | ADD X2, X2, inpErrsz@PAGEOFF 27 | LDR W2, [X2] 28 | writeFile X1, inpErr, X2 // print the error 29 | B exit 30 | 31 | nxtfil: openFile outFile, O_CREAT+O_WRONLY 32 | MOV X9 , X0 // save file descriptor (or error) 33 | B.CC loop // carry clear, file opened ok 34 | MOV X1, #1 35 | ADRP X2, outErrsz@PAGE 36 | ADD X2, X2, outErrsz@PAGEOFF 37 | LDR W2, [X2] 38 | writeFile X1, outErr, X2 39 | B exit 40 | 41 | // loop through file until done. 42 | loop: readFile X11, buffer, BUFFERLEN 43 | MOV X10, X0 // Keep the length read 44 | MOV X1, #0 // Null terminator for string 45 | 46 | // setup call to toupper and call function 47 | ADRP X0, buffer@PAGE // first param for toupper 48 | ADD X0, X0, buffer@PAGEOFF 49 | STRB W1, [X0, X10] // put null at end of string. 50 | ADRP X1, outBuf@PAGE 51 | ADD X1, X1, outBuf@PAGEOFF 52 | BL toupper 53 | 54 | writeFile X9, outBuf, X10 55 | 56 | CMP X10, #BUFFERLEN 57 | B.EQ loop 58 | 59 | flushClose X11 60 | flushClose X9 61 | 62 | // Setup the parameters to exit the program 63 | // and then call the kernel to do it. 64 | exit: MOV X0, #0 // Use 0 return code 65 | MOV X16, #1 66 | SVC #0x80 // Call kernel to terminate the program 67 | 68 | .data 69 | inFile: .asciz "main.S" 70 | outFile: .asciz "upper.txt" 71 | buffer: .fill BUFFERLEN + 1, 1, 0 72 | outBuf: .fill BUFFERLEN + 1, 1, 0 73 | inpErr: .asciz "Failed to open input file.\n" 74 | inpErrsz: .word .-inpErr 75 | outErr: .asciz "Failed to open output file.\n" 76 | outErrsz: .word .-outErr 77 | 78 | -------------------------------------------------------------------------------- /Chapter 07/makefile: -------------------------------------------------------------------------------- 1 | UPPEROBJS = main.o upper.o 2 | 3 | ifdef DEBUG 4 | DEBUGFLGS = -g 5 | else 6 | DEBUGFLGS = 7 | endif 8 | LSTFLGS = 9 | 10 | all: upper 11 | 12 | LDFLAGS = -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 13 | 14 | %.o : %.S 15 | clang $(DEBUGFLGS) $(LSTFLGS) -c $< -o $@ 16 | 17 | %.o : %.s 18 | as $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 19 | 20 | upper: $(UPPEROBJS) 21 | ld -o upper $(LDFLAGS) $(UPPEROBJS) 22 | 23 | -------------------------------------------------------------------------------- /Chapter 07/upper.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X4 - original output string for length calc. 8 | // W5 - current character being processed 9 | // 10 | 11 | .global toupper // Allow other files to call this routine 12 | .align 4 13 | 14 | toupper: 15 | MOV X4, X1 16 | // The loop is until byte pointed to by X1 is non-zero 17 | loop: LDRB W5, [X0], #1 // load character and increment pointer 18 | // If W5 > 'z' then goto cont 19 | CMP W5, #'z' // is letter > 'z'? 20 | B.GT cont 21 | // Else if W5 < 'a' then goto end if 22 | CMP W5, #'a' 23 | B.LT cont // goto to end if 24 | // if we got here then the letter is lower case, so convert it. 25 | SUB W5, W5, #('a'-'A') 26 | cont: // end if 27 | STRB W5, [X1], #1 // store character to output str 28 | CMP W5, #0 // stop on hitting a null character 29 | B.NE loop // loop if character isn't null 30 | SUB X0, X1, X4 // get the length by subtracting the pointers 31 | RET // Return to caller 32 | -------------------------------------------------------------------------------- /Chapter 09/.gitignore: -------------------------------------------------------------------------------- 1 | addexamp2 2 | libupper.a 3 | uppertst 4 | uppertst? 5 | libup.*.dylib 6 | -------------------------------------------------------------------------------- /Chapter 09/addexamp2.s: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Example of 128-Bit addition with the ADD/ADC instructions. 4 | // 5 | 6 | .include "debug.s" 7 | 8 | .global main // Provide program starting address 9 | .p2align 2 10 | 11 | // Load the registers with some data 12 | // First 64-bit number is 0x0000000000000003FFFFFFFFFFFFFFFF 13 | main: 14 | STR LR,[SP,#-16]! 15 | MOV X2, #0x0000000000000003 16 | MOV X3, #0xFFFFFFFFFFFFFFFF //Assembler will change to MOVN 17 | // Second 64-bit number is 0x00000000000000050000000000000001 18 | MOV X4, #0x0000000000000005 19 | MOV X5, #0x0000000000000001 20 | 21 | printStr "Inputs:" 22 | printReg 2 23 | printReg 3 24 | printReg 4 25 | printReg 5 26 | ADDS X1, X3, X5 // Lower order word 27 | ADC X0, X2, X4 // Higher order word 28 | 29 | 30 | printStr "Outputs:" 31 | printReg 1 32 | printReg 0 33 | MOV X0, #0 // return code 34 | LDR LR, [SP], #16 35 | RET 36 | 37 | -------------------------------------------------------------------------------- /Chapter 09/build: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | as -g -o test.o test.s 4 | ld -o test test.o -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _main -arch arm64 5 | -------------------------------------------------------------------------------- /Chapter 09/debug.s: -------------------------------------------------------------------------------- 1 | // Various macros to help with debugging 2 | 3 | // These macros preseve all registers. 4 | // Beware they will change the condition flags. 5 | 6 | .macro printReg reg 7 | stp X0, X1, [SP, #-16]! 8 | stp X2, X3, [SP, #-16]! 9 | stp X4, X5, [SP, #-16]! 10 | stp X6, X7, [SP, #-16]! 11 | stp X8, X9, [SP, #-16]! 12 | stp X10, X11, [SP, #-16]! 13 | stp X12, X13, [SP, #-16]! 14 | stp X14, X15, [SP, #-16]! 15 | stp X16, X17, [SP, #-16]! 16 | stp X18, LR, [SP, #-16]! 17 | mov X1, #\reg // for the %u 18 | mov X2, X\reg // for the %d 19 | mov X3, X\reg // for the %x 20 | str X1, [SP, #-32]! // Move the stack pointer four doublewords (32 bytes) down and push X1 onto the stack 21 | str X2, [SP, #8] // Push X2 to one doubleword above the current stack pointer 22 | str X3, [SP, #16] // Push X3 to two doublewords above the current stack pointer 23 | adrp X0, ptfStr@PAGE // printf format str 24 | add X0, X0, ptfStr@PAGEOFF // add offset for format str 25 | bl _printf // call printf 26 | add SP, SP, #32 // Clean up stack 27 | ldp X18, LR, [SP], #16 28 | ldp X16, X17, [SP], #16 29 | ldp X14, X15, [SP], #16 30 | ldp X12, X13, [SP], #16 31 | ldp X10, X11, [SP], #16 32 | ldp X8, X9, [SP], #16 33 | ldp X6, X7, [SP], #16 34 | ldp X4, X5, [SP], #16 35 | ldp X2, X3, [SP], #16 36 | ldp X0, X1, [SP], #16 37 | .endm 38 | 39 | .macro printStr str 40 | stp X0, X1, [SP, #-16]! 41 | stp X2, X3, [SP, #-16]! 42 | stp X4, X5, [SP, #-16]! 43 | stp X6, X7, [SP, #-16]! 44 | stp X8, X9, [SP, #-16]! 45 | stp X10, X11, [SP, #-16]! 46 | stp X12, X13, [SP, #-16]! 47 | stp X14, X15, [SP, #-16]! 48 | stp X16, X17, [SP, #-16]! 49 | stp X18, LR, [SP, #-16]! 50 | adr X0, 1f // load print str 51 | bl _printf // call printf 52 | ldp X18, LR, [SP], #16 53 | ldp X16, X17, [SP], #16 54 | ldp X14, X15, [SP], #16 55 | ldp X12, X13, [SP], #16 56 | ldp X10, X11, [SP], #16 57 | ldp X8, X9, [SP], #16 58 | ldp X6, X7, [SP], #16 59 | ldp X4, X5, [SP], #16 60 | ldp X2, X3, [SP], #16 61 | ldp X0, X1, [SP], #16 62 | b 2f // branch around str 63 | 1: .asciz "\str\n" 64 | .align 4 65 | 2: 66 | .endm 67 | 68 | .data 69 | ptfStr: .asciz "X%-2u = %32ld, 0x%016lx\n" 70 | .align 4 71 | .text 72 | -------------------------------------------------------------------------------- /Chapter 09/makefile: -------------------------------------------------------------------------------- 1 | LIBOBJS = upper.o 2 | 3 | ifdef DEBUG 4 | DEBUGFLGS = -g 5 | else 6 | DEBUGFLGS = 7 | endif 8 | LSTFLGS = 9 | 10 | LDFLAGS = -lSystem -lc -e main -arch arm64 11 | 12 | all: addexamp2 uppertst uppertst2 uppertst3 uppertst4 13 | 14 | upper.e.o : upper.s 15 | as -arch arm64e $(DEBUGFLAG) $< -o upper.e.o 16 | 17 | %.o : %.s 18 | as $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 19 | 20 | addexamp2: addexamp2.s debug.s 21 | clang $(LDFLAGS) $(DEBUGFLGS) -o addexamp2 addexamp2.s 22 | 23 | uppertst: uppertst.c upper.s 24 | clang -o uppertst uppertst.c upper.s 25 | 26 | libupper.a: $(LIBOBJS) 27 | ar -cvq libupper.a upper.o 28 | 29 | uppertst2: uppertst.c libupper.a 30 | clang -o uppertst2 uppertst.c libupper.a 31 | 32 | libup.dylib: $(LIBOBJS) upper.e.o 33 | clang -current_version 1.0 -compatibility_version 1.0 -dynamiclib -o libup.arm64.dylib $(LIBOBJS) 34 | clang -arch arm64e -current_version 1.0 -compatibility_version 1.0 -dynamiclib -o libup.arm64e.dylib upper.e.o 35 | lipo -create -output libup.A.dylib libup.arm64.dylib libup.arm64e.dylib 36 | mkdir -p ~/lib 37 | mv libup.A.dylib ~/lib/ 38 | ln -sf ~/lib/libup.A.dylib ~/lib/libup.dylib 39 | 40 | uppertst3: libup.dylib 41 | clang -o uppertst3 uppertst.c -L ~/lib -lup 42 | 43 | uppertst4: uppertst4.c 44 | clang -o uppertst4 uppertst4.c 45 | 46 | clean: 47 | rm -f *.o addexamp2 uppertst libupper.a uppertst? ~/lib/libup.dylib ~/lib/libup.A.dylib 48 | -------------------------------------------------------------------------------- /Chapter 09/test.s: -------------------------------------------------------------------------------- 1 | // Test for printf on OS X 2 | 3 | 4 | .global _main // Provide program starting address 5 | .align 4 6 | 7 | _main: 8 | // Setup 9 | stp x29, LR, [sp, #-16]! ; Save LR, FR 10 | adrp X0, ptfStr@PAGE // printf format str 11 | add X0, X0, ptfStr@PAGEOFF 12 | mov x2, #4711 13 | mov x3, #3845 14 | mov x10, #65 15 | str x10, [SP, #-32]! 16 | str x2, [SP, #8] 17 | str x3, [SP, #16] 18 | 19 | bl _printf // call printf 20 | 21 | add SP, SP, #32 // Clean up stack 22 | 23 | MOV X0, #0 // return code 24 | ldp x29, LR, [sp], #16 ; Restore FR, LR 25 | RET 26 | .data 27 | ptfStr: .asciz "Hello World %c %ld %ld\n" 28 | .align 4 29 | .text 30 | -------------------------------------------------------------------------------- /Chapter 09/upper.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X4 - original output string for length calc. 8 | // W5 - current character being processed 9 | // 10 | 11 | .global _mytoupper // Allow other files to call this routine 12 | .p2align 2 13 | 14 | _mytoupper: 15 | MOV X4, X1 16 | // The loop is until byte pointed to by X1 is non-zero 17 | loop: LDRB W5, [X0], #1 // load character and increment pointer 18 | // If W5 > 'z' then goto cont 19 | CMP W5, #'z' // is letter > 'z'? 20 | B.GT cont 21 | // Else if W5 < 'a' then goto end if 22 | CMP W5, #'a' 23 | B.LT cont // goto to end if 24 | // if we got here then the letter is lower case, so convert it. 25 | SUB W5, W5, #('a'-'A') 26 | cont: // end if 27 | STRB W5, [X1], #1 // store character to output str 28 | CMP W5, #0 // stop on hitting a null character 29 | B.NE loop // loop if character isn't null 30 | SUB X0, X1, X4 // get the length by subtracting the pointers 31 | RET // Return to caller 32 | -------------------------------------------------------------------------------- /Chapter 09/uppertst.c: -------------------------------------------------------------------------------- 1 | // 2 | // C program to call our Assembly 3 | // toupper routine. 4 | // 5 | 6 | #include 7 | 8 | extern int mytoupper( char *, char * ); 9 | 10 | #define MAX_BUFFSIZE 255 11 | int main() 12 | { 13 | char *str = "This is a test."; 14 | char outBuf[MAX_BUFFSIZE]; 15 | int len; 16 | 17 | len = mytoupper( str, outBuf ); 18 | printf("Before str: %s\n", str); 19 | printf("After str: %s\n", outBuf); 20 | printf("Str len = %d\n", len); 21 | return(0); 22 | } 23 | -------------------------------------------------------------------------------- /Chapter 09/uppertst4.c: -------------------------------------------------------------------------------- 1 | // 2 | // C program to embed our Assembly 3 | // toupper routine inline. 4 | // 5 | 6 | #include 7 | 8 | #define MAX_BUFFSIZE 255 9 | int main() 10 | { 11 | char *str = "This is a test."; 12 | char outBuf[MAX_BUFFSIZE]; 13 | long len; 14 | 15 | asm 16 | ( 17 | "MOV X4, %2\n" 18 | "loop: LDRB W5, [%1], #1\n" 19 | "CMP W5, #'z'\n" 20 | "BGT Lcont\n" 21 | "CMP W5, #'a'\n" 22 | "BLT Lcont\n" 23 | "SUB W5, W5, #('a'-'A')\n" 24 | "Lcont: STRB W5, [%2], #1\n" 25 | "CMP W5, #0\n" 26 | "B.NE loop\n" 27 | "SUB %0, %2, X4\n" 28 | : "=r" (len) 29 | : "r" (str), "r" (outBuf) 30 | : "r4", "r5" 31 | ); 32 | 33 | printf("Before str: %s\n", str); 34 | printf("After str: %s\n", outBuf); 35 | printf("Str len = %ld\n", len); 36 | return(0); 37 | } 38 | -------------------------------------------------------------------------------- /Chapter 09/uppertst5.py: -------------------------------------------------------------------------------- 1 | from ctypes import * 2 | 3 | libupper = CDLL("/Users/below/lib/libup.dylib") 4 | 5 | libupper.mytoupper.argtypes = [c_char_p, c_char_p] 6 | libupper.mytoupper.restype = c_int 7 | 8 | inStr = create_string_buffer(b"This is a test!") 9 | outStr = create_string_buffer(250) 10 | 11 | len = libupper.mytoupper(inStr, outStr) 12 | 13 | print(inStr.value) 14 | print(outStr.value) 15 | print(len) 16 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | }, 93 | { 94 | "idiom" : "mac", 95 | "scale" : "1x", 96 | "size" : "16x16" 97 | }, 98 | { 99 | "idiom" : "mac", 100 | "scale" : "2x", 101 | "size" : "16x16" 102 | }, 103 | { 104 | "idiom" : "mac", 105 | "scale" : "1x", 106 | "size" : "32x32" 107 | }, 108 | { 109 | "idiom" : "mac", 110 | "scale" : "2x", 111 | "size" : "32x32" 112 | }, 113 | { 114 | "idiom" : "mac", 115 | "scale" : "1x", 116 | "size" : "128x128" 117 | }, 118 | { 119 | "idiom" : "mac", 120 | "scale" : "2x", 121 | "size" : "128x128" 122 | }, 123 | { 124 | "idiom" : "mac", 125 | "scale" : "1x", 126 | "size" : "256x256" 127 | }, 128 | { 129 | "idiom" : "mac", 130 | "scale" : "2x", 131 | "size" : "256x256" 132 | }, 133 | { 134 | "idiom" : "mac", 135 | "scale" : "1x", 136 | "size" : "512x512" 137 | }, 138 | { 139 | "idiom" : "mac", 140 | "scale" : "2x", 141 | "size" : "512x512" 142 | } 143 | ], 144 | "info" : { 145 | "author" : "xcode", 146 | "version" : 1 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // Shared 4 | // 5 | // Created by Alexander von Below on 06.07.20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | class UpperTextModel: ObservableObject { 11 | @Published var input = "" 12 | @Published var output = "" 13 | } 14 | 15 | struct ContentView: View { 16 | 17 | @State var text: String = "" 18 | 19 | func toUpper(_ input: String) -> String { 20 | var output : [CChar] = Array(repeating: 0, count: 255) 21 | 22 | let s: String = text 23 | mytoupper(s, &output) 24 | 25 | guard let outputString = String(validatingUTF8: output) else { 26 | return "Unable to convert \(input)" 27 | } 28 | return outputString 29 | } 30 | 31 | var body: some View { 32 | #if os(macOS) 33 | let alignment = TextAlignment.leading 34 | #else 35 | let alignment = TextAlignment.center 36 | #endif 37 | 38 | VStack { 39 | TextField("Enter some text here", text: $text).padding(20) 40 | Text(toUpper(text)) 41 | 42 | }.multilineTextAlignment(alignment).padding() 43 | } 44 | } 45 | 46 | struct ContentView_Previews: PreviewProvider { 47 | static var previews: some View { 48 | ContentView() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/ToUpper-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #include "upper.h" 6 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/ToUpperApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ToUpperApp.swift 3 | // Shared 4 | // 5 | // Created by Alexander von Below on 06.07.20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct ToUpperApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/upper.h: -------------------------------------------------------------------------------- 1 | // 2 | // upper.h 3 | // ToUpper 4 | // 5 | // Created by Stephen Smith on 2020-01-24. 6 | // Copyright © 2020 Stephen Smith. All rights reserved. 7 | // 8 | 9 | #ifndef upper_h 10 | #define upper_h 11 | 12 | extern int mytoupper(const char *, char *); 13 | 14 | #endif /* upper_h */ 15 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/Shared/upper.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X4 - original output string for length calc. 8 | // W5 - current character being processed 9 | // 10 | 11 | .global _mytoupper // Allow other files to call this routine 12 | .align 4 13 | 14 | _mytoupper: MOV X4, X1 15 | // The loop is until byte pointed to by X1 is non-zero 16 | loop: LDRB W5, [X0], #1 // load character and increment pointer 17 | // If W5 > 'z' then goto cont 18 | CMP W5, #'z' // is letter > 'z'? 19 | B.GT cont 20 | // Else if W5 < 'a' then goto end if 21 | CMP W5, #'a' 22 | B.LT cont // goto to end if 23 | // if we got here then the letter is lower case, so convert it. 24 | SUB W5, W5, #('a'-'A') 25 | cont: // end if 26 | STRB W5, [X1], #1 // store character to output str 27 | CMP W5, #0 // stop on hitting a null character 28 | B.NE loop // loop if character isn't null 29 | SUB X0, X1, X4 // get the length by subtracting the pointers 30 | RET // Return to caller 31 | 32 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper WatchKit App/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "role" : "notificationCenter", 6 | "scale" : "2x", 7 | "size" : "24x24", 8 | "subtype" : "38mm" 9 | }, 10 | { 11 | "idiom" : "watch", 12 | "role" : "notificationCenter", 13 | "scale" : "2x", 14 | "size" : "27.5x27.5", 15 | "subtype" : "42mm" 16 | }, 17 | { 18 | "idiom" : "watch", 19 | "role" : "companionSettings", 20 | "scale" : "2x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "watch", 25 | "role" : "companionSettings", 26 | "scale" : "3x", 27 | "size" : "29x29" 28 | }, 29 | { 30 | "idiom" : "watch", 31 | "role" : "appLauncher", 32 | "scale" : "2x", 33 | "size" : "40x40", 34 | "subtype" : "38mm" 35 | }, 36 | { 37 | "idiom" : "watch", 38 | "role" : "appLauncher", 39 | "scale" : "2x", 40 | "size" : "44x44", 41 | "subtype" : "40mm" 42 | }, 43 | { 44 | "idiom" : "watch", 45 | "role" : "appLauncher", 46 | "scale" : "2x", 47 | "size" : "50x50", 48 | "subtype" : "44mm" 49 | }, 50 | { 51 | "idiom" : "watch", 52 | "role" : "quickLook", 53 | "scale" : "2x", 54 | "size" : "86x86", 55 | "subtype" : "38mm" 56 | }, 57 | { 58 | "idiom" : "watch", 59 | "role" : "quickLook", 60 | "scale" : "2x", 61 | "size" : "98x98", 62 | "subtype" : "42mm" 63 | }, 64 | { 65 | "idiom" : "watch", 66 | "role" : "quickLook", 67 | "scale" : "2x", 68 | "size" : "108x108", 69 | "subtype" : "44mm" 70 | }, 71 | { 72 | "idiom" : "watch-marketing", 73 | "scale" : "1x", 74 | "size" : "1024x1024" 75 | } 76 | ], 77 | "info" : { 78 | "author" : "xcode", 79 | "version" : 1 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper WatchKit App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper WatchKit App/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | ToUpper WatchKit App 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | UISupportedInterfaceOrientations 24 | 25 | UIInterfaceOrientationPortrait 26 | UIInterfaceOrientationPortraitUpsideDown 27 | 28 | WKWatchKitApp 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper WatchKit Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | ToUpper WatchKit Extension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionAttributes 26 | 27 | WKAppBundleIdentifier 28 | com.example.ToUpper.watchkitapp 29 | 30 | NSExtensionPointIdentifier 31 | com.apple.watchkit 32 | 33 | WKWatchOnly 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (iOS).xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (macOS).xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (tvOS).xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (watchOS).xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 57 | 59 | 65 | 66 | 67 | 68 | 74 | 76 | 82 | 83 | 84 | 85 | 87 | 88 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | 28 | UIApplicationSupportsIndirectInputEvents 29 | 30 | UILaunchScreen 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/macOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/macOS/macOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "layers" : [ 7 | { 8 | "filename" : "Front.imagestacklayer" 9 | }, 10 | { 11 | "filename" : "Middle.imagestacklayer" 12 | }, 13 | { 14 | "filename" : "Back.imagestacklayer" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "layers" : [ 7 | { 8 | "filename" : "Front.imagestacklayer" 9 | }, 10 | { 11 | "filename" : "Middle.imagestacklayer" 12 | }, 13 | { 14 | "filename" : "Back.imagestacklayer" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "filename" : "App Icon - App Store.imagestack", 5 | "idiom" : "tv", 6 | "role" : "primary-app-icon", 7 | "size" : "1280x768" 8 | }, 9 | { 10 | "filename" : "App Icon.imagestack", 11 | "idiom" : "tv", 12 | "role" : "primary-app-icon", 13 | "size" : "400x240" 14 | }, 15 | { 16 | "filename" : "Top Shelf Image Wide.imageset", 17 | "idiom" : "tv", 18 | "role" : "top-shelf-image-wide", 19 | "size" : "2320x720" 20 | }, 21 | { 22 | "filename" : "Top Shelf Image.imageset", 23 | "idiom" : "tv", 24 | "role" : "top-shelf-image", 25 | "size" : "1920x720" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "tv-marketing", 13 | "scale" : "1x" 14 | }, 15 | { 16 | "idiom" : "tv-marketing", 17 | "scale" : "2x" 18 | } 19 | ], 20 | "info" : { 21 | "author" : "xcode", 22 | "version" : 1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "idiom" : "tv-marketing", 13 | "scale" : "1x" 14 | }, 15 | { 16 | "idiom" : "tv-marketing", 17 | "scale" : "2x" 18 | } 19 | ], 20 | "info" : { 21 | "author" : "xcode", 22 | "version" : 1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchScreen 24 | 25 | UIRequiredDeviceCapabilities 26 | 27 | arm64 28 | 29 | UIUserInterfaceStyle 30 | Automatic 31 | 32 | 33 | -------------------------------------------------------------------------------- /Chapter 10/ToUpper/tvOS/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Chapter 11/.gitignore: -------------------------------------------------------------------------------- 1 | divexamp 2 | matrixmult 3 | mulexamp 4 | -------------------------------------------------------------------------------- /Chapter 11/ans: -------------------------------------------------------------------------------- 1 | 2 | 30 24 18 3 | 4 | 84 69 54 5 | 6 | 138 114 90 7 | -------------------------------------------------------------------------------- /Chapter 11/debug.s: -------------------------------------------------------------------------------- 1 | // Various macros to help with debugging 2 | 3 | // These macros preseve all registers. 4 | // Beware they will change the condition flags. 5 | 6 | .macro printReg reg 7 | stp X0, X1, [SP, #-16]! 8 | stp X2, X3, [SP, #-16]! 9 | stp X4, X5, [SP, #-16]! 10 | stp X6, X7, [SP, #-16]! 11 | stp X8, X9, [SP, #-16]! 12 | stp X10, X11, [SP, #-16]! 13 | stp X12, X13, [SP, #-16]! 14 | stp X14, X15, [SP, #-16]! 15 | stp X16, X17, [SP, #-16]! 16 | stp X18, LR, [SP, #-16]! 17 | mov X1, #\reg // for the %u 18 | mov X2, X\reg // for the %d 19 | mov X3, X\reg // for the %x 20 | str X1, [SP, #-32]! // Move the stack pointer four doublewords (32 bytes) down and push X1 onto the stack 21 | str X2, [SP, #8] // Push X2 to one doubleword above the current stack pointer 22 | str X3, [SP, #16] // Push X3 to two doublewords above the current stack pointer 23 | adrp X0, ptfStr@PAGE // printf format str 24 | add X0, X0, ptfStr@PAGEOFF // add offset for format str 25 | bl _printf // call printf 26 | add SP, SP, #32 // Clean up stack 27 | ldp X18, LR, [SP], #16 28 | ldp X16, X17, [SP], #16 29 | ldp X14, X15, [SP], #16 30 | ldp X12, X13, [SP], #16 31 | ldp X10, X11, [SP], #16 32 | ldp X8, X9, [SP], #16 33 | ldp X6, X7, [SP], #16 34 | ldp X4, X5, [SP], #16 35 | ldp X2, X3, [SP], #16 36 | ldp X0, X1, [SP], #16 37 | .endm 38 | 39 | .macro printStr str 40 | stp X0, X1, [SP, #-16]! 41 | stp X2, X3, [SP, #-16]! 42 | stp X4, X5, [SP, #-16]! 43 | stp X6, X7, [SP, #-16]! 44 | stp X8, X9, [SP, #-16]! 45 | stp X10, X11, [SP, #-16]! 46 | stp X12, X13, [SP, #-16]! 47 | stp X14, X15, [SP, #-16]! 48 | stp X16, X17, [SP, #-16]! 49 | stp X18, LR, [SP, #-16]! 50 | adr X0, 1f // load print str 51 | bl _printf // call printf 52 | ldp X18, LR, [SP], #16 53 | ldp X16, X17, [SP], #16 54 | ldp X14, X15, [SP], #16 55 | ldp X12, X13, [SP], #16 56 | ldp X10, X11, [SP], #16 57 | ldp X8, X9, [SP], #16 58 | ldp X6, X7, [SP], #16 59 | ldp X4, X5, [SP], #16 60 | ldp X2, X3, [SP], #16 61 | ldp X0, X1, [SP], #16 62 | b 2f // branch around str 63 | 1: .asciz "\str\n" 64 | .align 4 65 | 2: 66 | .endm 67 | 68 | .data 69 | ptfStr: .asciz "X%-2u = %32ld, 0x%016lx\n" 70 | .align 4 71 | .text 72 | -------------------------------------------------------------------------------- /Chapter 11/divexamp.s: -------------------------------------------------------------------------------- 1 | // 2 | // Examples of 64-Bit Integer Division 3 | // 4 | 5 | .include "debug.s" 6 | 7 | .global main // Provide program starting address 8 | .align 4 9 | 10 | // Load the registers with some data 11 | // Perform various division instructions 12 | main: 13 | MOV X2, #100 14 | MOV X3, #4 15 | 16 | printStr "Inputs:" 17 | printReg 2 18 | printReg 3 19 | 20 | SDIV X4, X2, X3 21 | printStr "Outputs:" 22 | printReg 4 23 | 24 | UDIV X4, X2, X3 25 | printStr "Outputs:" 26 | printReg 4 27 | 28 | // Division by zero 29 | printStr "Division by zero:" 30 | MOV X3, #0 31 | SDIV X4, X2, X3 32 | printStr "Outputs:" 33 | printReg 4 34 | 35 | MOV X0, #0 // return code 36 | RET 37 | 38 | -------------------------------------------------------------------------------- /Chapter 11/makefile: -------------------------------------------------------------------------------- 1 | 2 | ifdef DEBUG 3 | DEBUGFLGS = -g 4 | else 5 | DEBUGFLGS = 6 | endif 7 | LSTFLGS = 8 | 9 | LDFLAGS = -lSystem -lc -e main -arch arm64 10 | 11 | all: divexamp mulexamp matrixmult 12 | 13 | %.o : %.s 14 | as $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 15 | 16 | divexamp: divexamp.s debug.s 17 | clang $(LDFLAGS) -o divexamp divexamp.s 18 | 19 | mulexamp: mulexamp.s debug.s 20 | clang $(LDFLAGS) -o mulexamp mulexamp.s 21 | 22 | matrixmult: matrixmult.s 23 | clang $(LDFLAGS) -g -o matrixmult matrixmult.s 24 | 25 | 26 | -------------------------------------------------------------------------------- /Chapter 11/matrixmult.s: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Multiply 2 3x3 integer matrices 4 | // 5 | // Registers: 6 | // W1 - Row index 7 | // W2 - Column index 8 | // X4 - Address of row 9 | // X5 - Address of column 10 | // X7 - 64 bit accumulated sum 11 | // W9 - Cell of A 12 | // W10 - Cell of B 13 | // X19 - Position in C 14 | // X20 - Loop counter for printing 15 | // X12 - row in dotloop 16 | // X6 - col in dotloop 17 | 18 | .global main // Provide program starting address 19 | .align 4 20 | 21 | .equ N, 3 // Matrix dimensions 22 | .equ WDSIZE, 4 // Size of element 23 | main: 24 | STR LR, [SP, #-16]! // Save required regs 25 | STP X19, X20, [SP, #-16]! // Save required regs 26 | 27 | MOV W1, #N // Row index 28 | ADRP X4, A@PAGE // Address of current row 29 | ADD X4, X4, A@PAGEOFF 30 | ADRP X19, C@PAGE // Address of results matrix 31 | ADD X19, X19, C@PAGEOFF 32 | rowloop: 33 | ADRP X5, B@PAGE // first column in B 34 | ADD X5, X5, B@PAGEOFF 35 | MOV W2, #N // Column index (will count down to 0) 36 | 37 | colloop: 38 | // Zero accumulator registers 39 | MOV X7, #0 40 | 41 | MOV W0, #N // dot product loop counter 42 | MOV X12, X4 // row for dot product 43 | MOV X6, X5 // column for dot product 44 | dotloop: 45 | // Do dot product of a row of A with column of B 46 | LDR W9, [X12], #WDSIZE // load A[row, i] and incr 47 | LDR W10, [X6], #(N*WDSIZE) // load B[i, col] 48 | SMADDL X7, W9, W10, X7 // Do multiply and accumulate 49 | SUBS W0, W0, #1 // Dec loop counter 50 | B.NE dotloop // If not zero loop 51 | 52 | STR W7, [X19], #4 // C[row, col] = dotprod 53 | ADD X5, X5, #WDSIZE // Increment current col 54 | SUBS W2, W2, #1 // Dec col loop counter 55 | B.NE colloop // If not zero loop 56 | 57 | ADD X4, X4, #(N*WDSIZE) // Increment to next row 58 | SUBS W1, W1, #1 // Dec row loop counter 59 | B.NE rowloop // If not zero loop 60 | 61 | // Print out matrix C 62 | // Loop through 3 rows printing 3 cols each time. 63 | MOV W20, #3 // Print 3 rows 64 | ADRP X19, C@PAGE // Addr of results matrix 65 | ADD X19, X19, C@PAGEOFF 66 | printloop: 67 | 68 | ADRP X0, prtstr@PAGE // printf format string 69 | ADD X0, X0, prtstr@PAGEOFF 70 | LDR W1, [X19], #WDSIZE // first element in current row 71 | LDR W2, [X19], #WDSIZE // second element in current row 72 | LDR W3, [X19], #WDSIZE // third element in curent row 73 | STR W1, [SP, #-32]! // Push W1 onto the stack, leaving room for W2 and W3 74 | STR W2, [SP, #8] 75 | STR W3, [SP, #16] // Push X3 onto the stack 76 | BL _printf // Call printf 77 | ADD SP, SP, #32 // Clean up stack 78 | SUBS W20, W20, #1 // Dec loop counter 79 | B.NE printloop // If not zero loop 80 | 81 | MOV X0, #0 // return code 82 | LDP X19, X20, [SP], #16 // Restore Regs 83 | LDR LR, [SP], #16 // Restore LR 84 | RET 85 | 86 | .data 87 | // First matrix 88 | A: .word 1, 2, 3 89 | .word 4, 5, 6 90 | .word 7, 8, 9 91 | // Second matrix 92 | B: .word 9, 8, 7 93 | .word 6, 5, 4 94 | .word 3, 2, 1 95 | // Result matix 96 | C: .fill 9, 4, 0 97 | 98 | prtstr: .asciz "%3d %3d %3d\n" 99 | -------------------------------------------------------------------------------- /Chapter 11/mulexamp.s: -------------------------------------------------------------------------------- 1 | // 2 | // Example of 32 & 64-Bit Multiplication 3 | // 4 | 5 | .include "debug.s" 6 | 7 | .global main // Provide program starting address 8 | 9 | // Load the registers with some data 10 | // Use small positive numbers that will work for all 11 | // multiply instructions. 12 | main: 13 | MOV X2, #25 14 | MOV X3, #4 15 | 16 | 17 | printStr "Inputs:" 18 | printReg 2 19 | printReg 3 20 | 21 | MUL X4, X2, X3 22 | printStr "MUL X4=X2*X3:" 23 | printReg 4 24 | 25 | MNEG X4, X2, X3 26 | printStr "MNEG X4=-X2*X3:" 27 | printReg 4 28 | 29 | SMULL X4, W2, W3 30 | printStr "SMULL X4=W2*W3:" 31 | printReg 4 32 | 33 | SMNEGL X4, W2, W3 34 | printStr "SMNEGL X4=-W2*W3:" 35 | printReg 4 36 | 37 | UMULL X4, W2, W3 38 | printStr "UMULL X4=W2*W3:" 39 | printReg 4 40 | 41 | UMNEGL X4, W2, W3 42 | printStr "UMNEGL X4=-W2*W3:" 43 | printReg 4 44 | 45 | ADRP X2, A@PAGE 46 | ADD X2, X2, A@PAGEOFF 47 | LDR X2, [X2] 48 | ADRP X3, B@PAGE 49 | ADD X3, X3, B@PAGEOFF 50 | LDR X3, [X3] 51 | MUL X4, X2, X3 52 | printStr "Inputs:" 53 | printReg 2 54 | printReg 3 55 | MUL X4, X2, X3 56 | printStr "MUL X4 = bottom 64 bits of X2*X3:" 57 | printReg 4 58 | SMULH X4, X2, X3 59 | printStr "SMULH X4 = top 64 bits of X2*X3 (signed):" 60 | printReg 4 61 | 62 | UMULH X4, X2, X3 63 | printStr "UMULH X4 = top 64 bits of X2*X3 (unsigned):" 64 | printReg 4 65 | 66 | MOV X0, #0 // return code 67 | RET 68 | 69 | .data 70 | A: .dword 0x7812345678 71 | B: .dword 0xFABCD12345678901 72 | 73 | -------------------------------------------------------------------------------- /Chapter 12/.gitignore: -------------------------------------------------------------------------------- 1 | distance 2 | fpcomp 3 | 4 | -------------------------------------------------------------------------------- /Chapter 12/codesnippets.s: -------------------------------------------------------------------------------- 1 | // 2 | // This file contains the various code 3 | // snippets from Chapter 11. This ensures 4 | // they compile and gives you a chance 5 | // to single step through them. 6 | // They are labeled, so you can set a 7 | // breakpoint at the one you are interested in. 8 | 9 | .global _start 10 | .align 4 11 | 12 | _start: 13 | l1: STP Q8, Q9, [SP, #-32]! 14 | STR Q10, [SP, #-16]! 15 | LDP Q8, Q9, [SP], #32 16 | LDR Q10, [SP], #16 17 | 18 | l2: ADRP X1, fp1@PAGE 19 | ADD X1, X1, fp1@PAGEOFF 20 | LDR S4, [X1] 21 | LDR D5, [X1, #4] 22 | STR S4, [X1] 23 | STR D5, [X1, #4] 24 | 25 | l3: FMOV H1, W2 26 | FMOV W2, H1 27 | FMOV S1, W2 28 | FMOV X1, D2 29 | FMOV D2, D3 30 | 31 | l4: FADD H1, H2, H3 // H1 = H2 + H3 32 | FADD S1, S2, S3 // S1 = S2 + S3 33 | FADD D1, D2, D3 // D1 = D2 + D3 34 | FSUB D1, D2, D3 // D1 = D2 - D3 35 | FMUL D1, D2, D3 // D1 = D2 * D3 36 | FDIV D1, D2, D3 // D1 = D2 / D3 37 | FMADD D1, D2, D3, D4 // D1 = D4 + D2 * D3 38 | FMSUB D1, D2, D3, D4 // D1 = D4 - D2 * D3 39 | FNEG D1, D2 // D1 = - D2 40 | FABS D1, D2 // D1 = Absolute Value( D2 ) 41 | FMAX D1, D2, D3 // D1 = Max( D2, D3 ) 42 | FMIN D1, D2, D3 // D1 = Min( D2, D3 ) 43 | FSQRT D1, D2 // D1 = Square Root( D2 ) 44 | 45 | l5: FCVT D1, S2 46 | FCVT S1, D2 47 | FCVT S1, H2 48 | FCVT H1, S2 49 | 50 | l6: SCVTF D1, X2 // D1 = signed integer from X2 51 | UCVTF S1, W2 // S1 = unsigned integer from W2 52 | 53 | l7: FCVTAS W1, H2 // signed, round to nearest 54 | FCVTAU W1, S2 // unsigned, round to nearest 55 | FCVTMS X1, D2 // signed, round towards minus infinity 56 | FCVTMU X1, D2 // unsigned, round towards minus infinity 57 | FCVTPS X1, D2 // signed, round towards positive infinity 58 | FCVTPU X1, D2 // unsigned, round towards positive infinity 59 | FCVTZS X1, D2 // signed, round towards zero 60 | FCVTZU X1, D2 // unsigned, round towards zero 61 | 62 | l8: FCMP H1, H2 63 | FCMP H1, #0.0 64 | FCMP S1, S2 65 | FCMP S1, #0.0 66 | FCMP D1, D2 67 | FCMP D1, #0.0 68 | 69 | // Setup the parameters to exit the program 70 | // and then call the kernel to do it. 71 | MOV X0, #0 // Use 0 return code 72 | MOV X16, #1 // Service command code 1 terminates 73 | SVC #0x80 // Call kernel to terminate the program 74 | 75 | .data 76 | .single 1.343, 4.343e20, -0.4343, -0.4444e-10 77 | .double -4.24322322332e-10, 3.141592653589793 78 | fp1: .single 3.14159 79 | fp2: .double 4.3341 80 | fp3: .single 0.0 81 | fp4: .double 0.0 82 | 83 | -------------------------------------------------------------------------------- /Chapter 12/debug.s: -------------------------------------------------------------------------------- 1 | @ Various macros to help with debugging 2 | 3 | @ These macros preseve all registers. 4 | @ Beware they will change cpsr. 5 | 6 | .macro printReg reg 7 | push {r0-r4, lr} @ save regs 8 | mov r2, R\reg @ for the %d 9 | mov r3, R\reg @ for the %x 10 | mov r1, #\reg 11 | add r1, #'0' @ for %c 12 | ldr r0, =ptfStr @ printf format str 13 | str r1, [sp, #-32] 14 | str r2, [sp, #8] 15 | str r3, [sp, #16] 16 | bl _printf @ call printf 17 | add sp, sp, #32 18 | pop {r0-r4, lr} @ restore regs 19 | .endm 20 | 21 | .macro printStr str 22 | push {r0-r4, lr} @ save regs 23 | ldr r0, =1f @ load print str 24 | bl _printf @ call printf 25 | pop {r0-r4, lr} @ restore regs 26 | b 2f @ branch around str 27 | 1: .asciz "\str\n" 28 | .align 4 29 | 2: 30 | .endm 31 | 32 | .data 33 | ptfStr: .asciz "R%c = %16d, 0x%08x\n" 34 | .align 4 35 | .text 36 | -------------------------------------------------------------------------------- /Chapter 12/distance.s: -------------------------------------------------------------------------------- 1 | // 2 | // Example function to calculate the distance 3 | // between two points in single precision 4 | // floating point. 5 | // 6 | // Inputs: 7 | // X0 - pointer to the 4 FP numbers 8 | // they are x1, y1, x2, y2 9 | // Outputs: 10 | // X0 - the length (as single precision FP) 11 | 12 | .global distance // Allow function to be called by others 13 | .align 4 14 | 15 | // 16 | distance: 17 | // push all registers to be safe, we don't really 18 | // need to push so many. 19 | STR LR, [SP, #-16]! 20 | 21 | // load all 4 numbers at once 22 | LDP S0, S1, [X0], #8 23 | LDP S2, S3, [X0] 24 | 25 | // calc s4 = x2 - x1 26 | FSUB S4, S2, S0 27 | // calc s5 = y2 - y1 28 | FSUB S5, S3, S1 29 | // calc s4 = S4 * S4 (x2-X1)^2 30 | FMUL S4, S4, S4 31 | // calc s5 = s5 * s5 (Y2-Y1)^2 32 | FMUL S5, S5, S5 33 | // calc S4 = S4 + S5 34 | FADD S4, S4, S5 35 | // calc sqrt(S4) 36 | FSQRT S4, S4 37 | // move result to X0 to be returned 38 | FMOV W0, S4 39 | 40 | // restore what we preserved. 41 | LDR LR, [SP], #16 42 | RET 43 | 44 | -------------------------------------------------------------------------------- /Chapter 12/fpcomp.s: -------------------------------------------------------------------------------- 1 | // 2 | // Function to compare to floating point numbers 3 | // the parameters are a pointer to the two numbers 4 | // and an error epsilon. 5 | // 6 | // Inputs: 7 | // X0 - pointer to the 3 FP numbers 8 | // they are x1, x2, e 9 | // Outputs: 10 | // X0 - 1 if they are equal, else 0 11 | 12 | .global fpcomp // Allow function to be called by others 13 | .align 4 14 | 15 | // 16 | fpcomp: // load the 3 numbers 17 | LDP S0, S1, [X0], #8 18 | LDR S2, [X0] 19 | 20 | // calc s3 = x2 - x1 21 | FSUB S3, S1, S0 22 | FABS S3, S3 23 | FCMP S3, S2 24 | B.LE notequal 25 | MOV X0, #1 26 | B done 27 | 28 | notequal:MOV X0, #0 29 | 30 | done: RET 31 | -------------------------------------------------------------------------------- /Chapter 12/main.s: -------------------------------------------------------------------------------- 1 | // 2 | // Main program to test our distance function 3 | // 4 | // W19 - loop counter 5 | // X20 - address to current set of points 6 | 7 | .global main // Provide program starting address to linker 8 | .align 4 9 | 10 | // 11 | 12 | .equ N, 3 // Number of points. 13 | 14 | main: 15 | STP X19, X20, [SP, #-16]! 16 | STR LR, [SP, #-16]! 17 | 18 | ADRP X20, points@PAGE // pointer to current points 19 | ADD X20, X20, points@PAGEOFF 20 | 21 | MOV W19, #N // number of loop iterations 22 | 23 | loop: MOV X0, X20 // move pointer to parameter 1 (X0) 24 | 25 | BL distance // call distance function 26 | 27 | // need to take the single precision return value 28 | // and convert it to a double, because the C printf 29 | // function can only print doubles. 30 | FMOV S2, W0 // move back to fpu for conversion 31 | FCVT D0, S2 // convert single to double 32 | FMOV X1, D0 // return double to X1 33 | STR X1, [SP, #-16]! // Push X1 onto the stack 34 | ADRP X0, prtstr@PAGE // load print string 35 | ADD X0, X0, prtstr@PAGEOFF 36 | BL _printf // print the distance 37 | ADD SP, SP, #16 38 | 39 | ADD X20, X20, #(4*4) // 4 points each 4 bytes 40 | SUBS W19, W19, #1 // decrement loop counter 41 | B.NE loop // loop if more points 42 | 43 | MOV X0, #0 // return code 44 | LDR LR, [SP], #16 45 | LDP X19, X20, [SP], #16 46 | RET 47 | 48 | .data 49 | points: .single 0.0, 0.0, 3.0, 4.0 50 | .single 1.3, 5.4, 3.1, -1.5 51 | .single 1.323e10, -1.2e-4, 34.55, 5454.234 52 | prtstr: .asciz "Distance = %f\n" 53 | 54 | 55 | -------------------------------------------------------------------------------- /Chapter 12/maincomp.s: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Main program to test our distance function 4 | // 5 | // W19 - loop counter 6 | // X20 - address to current set of points 7 | 8 | .global main // Provide program starting address 9 | .align 4 10 | 11 | // 12 | 13 | .equ N, 100 // Number of additions. 14 | 15 | main: 16 | STP X19, X20, [SP, #-16]! 17 | STR LR, [SP, #-16]! 18 | 19 | // Add up one hundred cents and test if they equal $1.00 20 | 21 | MOV W19, #N // number of loop iterations 22 | 23 | // load cents, running sum and real sum to FPU 24 | ADRP X0, cent@PAGE 25 | ADD X0, X0, cent@PAGEOFF 26 | LDP S0, S1, [X0], #8 27 | LDR S2, [X0] 28 | loop: 29 | // add cent to running sum 30 | FADD S1, S1, S0 31 | SUBS W19, W19, #1 // decrement loop counter 32 | B.NE loop // loop if more points 33 | 34 | // compare running sum to real sum 35 | FCMP S1, S2 36 | // print if the numbers are equal or not 37 | B.EQ equal 38 | ADRP X0, notequalstr@PAGE 39 | ADD X0, X0, notequalstr@PAGEOFF 40 | BL _printf 41 | B next 42 | equal: ADRP X0, equalstr@PAGE 43 | ADD X0, X0, equalstr@PAGEOFF 44 | BL _printf 45 | 46 | next: 47 | // load pointer to running sum, real sum and epsilon 48 | ADRP X0, runsum@PAGE 49 | ADD X0, X0, runsum@PAGEOFF 50 | 51 | // call comparison function 52 | BL fpcomp // call comparison function 53 | // compare return code to 1 and print if the numbers 54 | // are equal or not (within epsilon). 55 | CMP X0, #1 56 | B.EQ equal2 57 | ADRP X0, notequalstr@PAGE 58 | ADD X0, X0, notequalstr@PAGEOFF 59 | BL _printf 60 | B done 61 | equal2: ADRP X0, equalstr@PAGE 62 | ADD X0, X0, equalstr@PAGEOFF 63 | BL _printf 64 | 65 | done: MOV X0, #0 // return code 66 | LDR LR, [SP], #16 67 | LDP X19, X20, [SP], #16 68 | RET 69 | 70 | .data 71 | cent: .single 0.01 72 | runsum: .single 0.0 73 | sum: .single 1.00 74 | epsilon:.single 0.00001 75 | equalstr: .asciz "equal\n" 76 | notequalstr: .asciz "not equal\n" 77 | 78 | 79 | -------------------------------------------------------------------------------- /Chapter 12/makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | ifdef DEBUG 4 | DEBUGFLGS = -g 5 | else 6 | DEBUGFLGS = 7 | endif 8 | LSTFLGS = 9 | 10 | LDFLAGS = -syslibroot `xcrun -sdk macosx --show-sdk-path` -lSystem -e _start -arch arm64 11 | CFLAGS = -lc -e main 12 | 13 | all: codesnippets distance fpcomp 14 | 15 | %.o : %.s 16 | as -march="armv8.2-a+fp16" $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 17 | 18 | codesnippets: codesnippets.o 19 | ld $(LDFLAGS) -o codesnippets codesnippets.o 20 | 21 | distance: distance.s main.s 22 | clang $(CFLAGS) -g -o distance distance.s main.s 23 | 24 | fpcomp: fpcomp.s maincomp.s 25 | clang $(CFLAGS) -g -o fpcomp fpcomp.s maincomp.s 26 | -------------------------------------------------------------------------------- /Chapter 13/.gitignore: -------------------------------------------------------------------------------- 1 | distance 2 | matrixmultneon 3 | 4 | -------------------------------------------------------------------------------- /Chapter 13/ans: -------------------------------------------------------------------------------- 1 | 2 | 30 24 18 3 | 4 | 84 69 54 5 | 6 | 138 114 90 7 | -------------------------------------------------------------------------------- /Chapter 13/distance.s: -------------------------------------------------------------------------------- 1 | // 2 | // Example function to calculate the distance 3 | // between 4D two points in single precision 4 | // floating point using the NEON Processor 5 | // 6 | // Inputs: 7 | // X0 - pointer to the 8 FP numbers 8 | // they are (x1, x2, x3, x4), 9 | // (y1, y2, y3, y4) 10 | // Outputs: 11 | // W0 - the length (as single precision FP) 12 | 13 | .global distance // Allow function to be called by others 14 | .align 4 15 | 16 | // 17 | distance: 18 | // load all 4 numbers at once 19 | LDP Q2, Q3, [X0] 20 | 21 | // calc V1 = V2 - V3 22 | FSUB V1.4S, V2.4S, V3.4S 23 | // calc V1 = V1 * V1 = (xi-yi)^2 24 | FMUL V1.4S, V1.4S, V1.4S 25 | // calc S0 = S0 + S1 + S2 + S3 26 | FADDP V0.4S, V1.4S, V1.4S 27 | FADDP V0.4S, V0.4S, V0.4S 28 | // calc sqrt(S0) 29 | FSQRT S4, S0 30 | // move result to W0 to be returned 31 | FMOV W0, S4 32 | 33 | RET 34 | 35 | -------------------------------------------------------------------------------- /Chapter 13/main.s: -------------------------------------------------------------------------------- 1 | // 2 | // Main program to test our distance function 3 | // 4 | // W19 - loop counter 5 | // X20 - address to current set of points 6 | 7 | .global main // Provide program starting address to linker 8 | .align 4 9 | 10 | // 11 | 12 | .equ N, 3 // Number of points. 13 | 14 | main: 15 | STP X19, X20, [SP, #-16]! 16 | STR LR, [SP, #-16]! 17 | 18 | ADRP X20, points@PAGE // pointer to current points 19 | ADD X20, X20, points@PAGEOFF 20 | 21 | MOV W19, #N // number of loop iterations 22 | 23 | loop: MOV X0, X20 // move pointer to parameter 1 (r0) 24 | 25 | BL distance // call distance function 26 | 27 | // need to take the single precision return value 28 | // and convert it to a double, because the C printf 29 | // function can only print doubles. 30 | FMOV S2, W0 // move back to fpu for conversion 31 | FCVT D0, S2 // convert single to double 32 | FMOV X1, D0 // return double to r2, r3 33 | STR X1, [SP, #-16]! 34 | ADRP X0, prtstr@PAGE // load print string 35 | ADD X0, X0, prtstr@PAGEOFF 36 | BL _printf // print the distance 37 | ADD SP, SP, #16 38 | 39 | ADD X20, X20, #(8*4) // 8 elements each 4 bytes 40 | SUBS W19, W19, #1 // decrement loop counter 41 | B.NE loop // loop if more points 42 | 43 | MOV X0, #0 // return code 44 | LDR LR, [SP], #16 45 | LDP X19, X20, [SP], #16 46 | RET 47 | 48 | .data 49 | points: .single 0.0, 0.0, 0.0, 0.0, 17.0, 4.0, 2.0, 1.0 50 | .single 1.3, 5.4, 3.1, -1.5, -2.4, 0.323, 3.4, -0.232 51 | .single 1.323e10, -1.2e-4, 34.55, 5454.234, 10.9, -3.6, 4.2, 1.3 52 | prtstr: .asciz "Distance = %f\n" 53 | 54 | 55 | -------------------------------------------------------------------------------- /Chapter 13/makefile: -------------------------------------------------------------------------------- 1 | 2 | ifdef DEBUG 3 | DEBUGFLGS = -g 4 | else 5 | DEBUGFLGS = 6 | endif 7 | 8 | CFLAGS = -lc -e main 9 | 10 | all: distance matrixmultneon 11 | 12 | %.o : %.s 13 | as $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 14 | 15 | distance: distance.s main.s 16 | clang $(CFLAGS) $(DEBUGFLGS) -o distance distance.s main.s 17 | 18 | matrixmultneon: matrixmultneon.s 19 | clang $(CFLAGS) $(DEBUGFLGS) -o matrixmultneon matrixmultneon.s 20 | 21 | -------------------------------------------------------------------------------- /Chapter 13/matrixmultneon.s: -------------------------------------------------------------------------------- 1 | // 2 | // Multiply 2 3x3 integer matrices 3 | // Uses the NEON Coprocessor to do 4 | // some operations in parallel. 5 | // 6 | // Registers: 7 | // D0 - first column of matrix A 8 | // D1 - second column of matrix A 9 | // D2 - third column of matrix A 10 | // D3 - first column of matrix B 11 | // D4 - second column of matrix B 12 | // D5 - third column of matrix B 13 | // D6 - first column of matrix C 14 | // D7 - second column of matrix C 15 | // D8 - third column of matrix C 16 | 17 | .global main // Provide program starting address to linker 18 | .align 4 19 | 20 | main: 21 | STP X19, X20, [SP, #-16]! 22 | STR LR, [SP, #-16]! 23 | 24 | // load matrix A into Neon registers D0, D1, D2 25 | ADRP X0, A@PAGE // Address of A 26 | ADD X0, X0, A@PAGEOFF 27 | LDP D0, D1, [X0], #16 28 | LDR D2, [X0] 29 | 30 | // load matrix B into Neon registers D3, D4, D5 31 | ADRP X0, B@PAGE // Address of B 32 | ADD X0, X0, B@PAGEOFF 33 | LDP D3, D4, [X0], #16 34 | LDR D5, [X0] 35 | 36 | .macro mulcol ccol bcol 37 | MUL \ccol\().4H, V0.4H, \bcol\().H[0] 38 | MLA \ccol\().4H, V1.4H, \bcol\().H[1] 39 | MLA \ccol\().4H, V2.4H, \bcol\().H[2] 40 | .endm 41 | 42 | mulcol V6, V3 // process first column 43 | mulcol V7, V4 // process second column 44 | mulcol V8, V5 // process third column 45 | 46 | ADRP X1, C@PAGE // Address of C 47 | ADD X1, X1, C@PAGEOFF 48 | STP D6, D7, [X1], #16 49 | STR D8, [X1] 50 | 51 | // Print out matrix C 52 | // Loop through 3 rows printing 3 cols each time. 53 | MOV W19, #3 // Print 3 rows 54 | ADRP X20, C@PAGE // Addr of results matrix 55 | ADD X20, X20, C@PAGEOFF 56 | printloop: 57 | 58 | ADRP X0, prtstr@PAGE // printf format string 59 | ADD X0, X0, prtstr@PAGEOFF 60 | // print transpose so matrix is in usual row column order. 61 | // first ldrh post-indexes by 2 for next row 62 | // so second ldrh adds 6, so is ahead by 2+6=8=row size 63 | // simlarly for third ldh ahead by 2+14=16 = 2 x row size 64 | LDRH W1, [X20], #2 // first element in current row 65 | LDRH W2, [X20,#6] // second element in current row 66 | LDRH W3, [X20,#14] // third element in curent row 67 | STR W1, [SP, #-32]! // Push W1 onto the stack, leaving room for W2 and W3 68 | STR W2, [SP, #8] 69 | STR W3, [SP, #16] // Push X3 onto the stack 70 | BL _printf // Call printf 71 | ADD SP, SP, #32 // Clean up stack 72 | SUBS W19, W19, #1 // Dec loop counter 73 | B.NE printloop // If not zero loop 74 | 75 | MOV X0, #0 // return code 76 | LDR LR, [SP], #16 77 | LDP X19, X20, [SP], #16 78 | RET 79 | 80 | .data 81 | // First matrix in column major order 82 | A: .short 1, 4, 7, 0 83 | .short 2, 5, 8, 0 84 | .short 3, 6, 9, 0 85 | // Second matrix in column major order 86 | B: .short 9, 6, 3, 0 87 | .short 8, 5, 2, 0 88 | .short 7, 4, 1, 0 89 | // Result matix in column major order 90 | C: .fill 12, 2, 0 91 | 92 | prtstr: .asciz "%3d %3d %3d\n" 93 | -------------------------------------------------------------------------------- /Chapter 14/.gitignore: -------------------------------------------------------------------------------- 1 | upper 2 | upper? 3 | -------------------------------------------------------------------------------- /Chapter 14/main.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case by calling a function. 4 | // 5 | // X0-R2 - parameters to linux function services 6 | // X1 - address of output string 7 | // X0 - address of input string 8 | // X8 - linux function number 9 | // 10 | 11 | .global _start // Provide program starting address to linker 12 | .align 4 13 | 14 | _start: ADRP X0, instr@PAGE // start of input string 15 | ADD X0,X0, instr@PAGEOFF 16 | ADRP X1, outstr@PAGE // address of output string 17 | ADD X1, X1, outstr@PAGEOFF 18 | 19 | BL toupper 20 | 21 | // Setup the parameters to print our hex number 22 | // and then call the Kernel to do it. 23 | MOV X2,X0 // return code is the length of the string 24 | 25 | MOV X0, #1 // 1 = StdOut 26 | ADRP X1, outstr@PAGE // string to print 27 | ADD X1, X1, outstr@PAGEOFF 28 | MOV X16, #4 // Unix write system call 29 | SVC #0x80 // Call kernel to output the string 30 | 31 | // Setup the parameters to exit the program 32 | // and then call the Kernel to do it. 33 | MOV X0, #0 // Use 0 return code 34 | MOV X16, #1 // System call number 1 terminates 35 | SVC #0x80 // Call kernel to terminate the program 36 | 37 | .data 38 | instr: .asciz "This is our Test String that we will convert. AaZz@[`{\n" 39 | .align 4 40 | outstr: .fill 255, 1, 0 41 | 42 | -------------------------------------------------------------------------------- /Chapter 14/makefile: -------------------------------------------------------------------------------- 1 | UPPEROBJS = main.o upper.o 2 | UPPER2OBJS = main.o upper2.o 3 | UPPER3OBJS = upper3.o 4 | UPPER4OBJS = main.o upper4.o 5 | 6 | ifdef DEBUG 7 | DEBUGFLGS = -g 8 | else 9 | DEBUGFLGS = 10 | endif 11 | LSTFLGS = 12 | 13 | all: upper upper2 upper3 upper4 14 | 15 | LDFLAGS = -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 16 | 17 | %.o : %.s 18 | as $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 19 | 20 | upper: $(UPPEROBJS) 21 | ld $(LDFLAGS) -o upper $(UPPEROBJS) 22 | 23 | upper2: $(UPPER2OBJS) 24 | ld $(LDFLAGS) -o upper2 $(UPPER2OBJS) 25 | 26 | upper3: $(UPPER3OBJS) 27 | ld $(LDFLAGS) -o upper3 $(UPPER3OBJS) 28 | 29 | upper4: $(UPPER4OBJS) 30 | ld $(LDFLAGS) -o upper4 $(UPPER4OBJS) 31 | -------------------------------------------------------------------------------- /Chapter 14/upper.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X4 - original output string for length calc. 8 | // W5 - current character being processed 9 | // W6 - minus 'a' to compare < 26. 10 | // 11 | 12 | .global toupper // Allow other files to call this routine 13 | .align 4 14 | 15 | toupper: MOV X4, X1 16 | // The loop is until byte pointed to by X1 is non-zero 17 | loop: LDRB W5, [X0], #1 // load character and increment pointer 18 | // Want to know if 'a' <= W5 <= 'z' 19 | // First subtract 'a' 20 | SUB W6, W5, #'a' 21 | // Now want to know if W6 <= 25 22 | CMP W6, #25 // chars are 0-25 after shift 23 | B.HI cont 24 | // if we got here then the letter is lowercase, so convert it. 25 | SUB W5, W5, #('a'-'A') 26 | cont: // end if 27 | STRB W5, [X1], #1 // store character to output str 28 | CMP W5, #0 // stop on hitting a null character 29 | B.NE loop // loop if character isn't null 30 | SUB X0, X1, X4 // get the length by subtracting the pointers 31 | RET // Return to caller 32 | -------------------------------------------------------------------------------- /Chapter 14/upper2.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X4 - original output string for length calc. 8 | // W5 - current character being processed 9 | // W6 - minus 'a' to compare < 26. 10 | // W6 - char minus 0x20, potentiall upper cased 11 | // 12 | 13 | .global toupper // Allow other files to call this routine 14 | .align 4 15 | 16 | toupper: 17 | MOV X4, X1 18 | // The loop is until byte pointed to by R1 is non-zero 19 | loop: LDRB W5, [X0], #1 // load character and increment pointer 20 | // Want to know if 'a' <= W5 <= 'z' 21 | // First subtract 'a' 22 | SUB W6, W5, #'a' 23 | // Now want to know if W6 <= 25 24 | CMP W6, #25 // chars are 0-25 after shift 25 | // perform lower case conversion to W6 26 | SUB W6, W5, #('a'-'A') 27 | // Use W6 if lower case, other wise use orginal character in W5 28 | CSEL W5, W6, W5, LS 29 | STRB W5, [X1], #1 // store character to output str 30 | CMP W5, #0 // stop on hitting a null character 31 | B.NE loop // loop if character isn't null 32 | SUB X0, X1, X4 // get the length by subtracting the pointers 33 | RET // Return to caller 34 | -------------------------------------------------------------------------------- /Chapter 14/upper3.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. Assumes only alphabetic 4 | // characters. Uses bit clear blindly without 5 | // checking if character is alphabetic or not. 6 | // 7 | // X0 - address of input string 8 | // X1 - address of output string 9 | // X2 - original output string for length calc. 10 | // W3 - current character being processed 11 | // 12 | 13 | .global _start // Provide program starting address 14 | .align 4 15 | 16 | .macro toupper inputstr, outputstr 17 | ADRP X0, \inputstr@PAGE // start of input string 18 | ADD X0, X0, \inputstr@PAGEOFF 19 | ADRP X1, \outputstr@PAGE // address of output string 20 | ADD X1, X1, \outputstr@PAGEOFF 21 | MOV X2, X1 22 | // The loop is until byte pointed to by R1 is non-zero 23 | loop: LDRB W3, [X0], #1 // load character and increment pointer 24 | BIC W3, W3, #0x20 // kill the bit that makes it lower case 25 | STRB W3, [X1], #1 // store character to output str 26 | CMP W3, #0 // stop on hitting a null charactser 27 | B.NE loop // loop if character isn't null 28 | SUB X0, X1, X2 // get the length by subtracting the pointers 29 | .endm 30 | 31 | _start: 32 | toupper instr, outstr 33 | 34 | // Setup the parameters to print our hex number 35 | // and then call the Kernel to do it. 36 | MOV X2,X0 // return code is the length of the string 37 | 38 | MOV X0, #1 // 1 = StdOut 39 | ADRP X1, outstr@PAGE // string to print 40 | ADD X1, X1, outstr@PAGEOFF 41 | MOV X16, #4 // Unix write system call 42 | SVC #0x80 // Call kernel to output the string 43 | 44 | // Setup the parameters to exit the program 45 | // and then call the Kernel to do it. 46 | MOV X0, #0 // Use 0 return code 47 | MOV X16, #1 // System call number 1 terminates 48 | SVC #0x80 // Call kernel to terminate the program 49 | 50 | .data 51 | instr: .asciz "ThisIsRatherALargeVariableNameAaZz//[`{\n" 52 | .align 4 53 | outstr: .fill 255, 1, 0 54 | -------------------------------------------------------------------------------- /Chapter 14/upper4.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X0 - address of input string 6 | // X1 - address of output string 7 | // X2 - use as indirection to load data 8 | // Q0 - 8 characters to be processed 9 | // V1 - contains all a's for comparison 10 | // V2 - result of comparison with 'a's 11 | // Q3 - all 25's for comp 12 | // Q8 - spaces for bic operation 13 | 14 | .global toupper // Allow other files to call this routine 15 | .align 4 16 | 17 | .equ N, 4 18 | toupper: 19 | ADRP X2, aaas@PAGE 20 | ADD X2, X2, aaas@PAGEOFF 21 | LDR Q1, [X2] // Load Q1 with all as 22 | ADRP X2, endch@PAGE 23 | ADD X2, X2, endch@PAGEOFF 24 | LDR Q3, [X2] // Load Q3 with all 25's 25 | ADRP X2, spaces@PAGE 26 | ADD X2, X2, spaces@PAGEOFF 27 | LDR Q8, [X2] // Load Q8 with all spaces 28 | MOV W3, #N 29 | // The loop is until byte pointed to by R1 is non-zero 30 | loop: LDR Q0, [X0], #16 // load 16 characters and increment pointer 31 | SUB V2.16B, V0.16B, V1.16B // Subtract 'a's 32 | CMHI V2.16B, V2.16B, V3.16B // compare chars to 25's 33 | NOT V2.16B, V2.16B // no CMLO so need to not 34 | AND V2.16B, V2.16B, V8.16B // and result with spaces 35 | BIC V0.16B, V0.16B, V2.16B // kill the bit that makes it lowercase 36 | STR Q0, [X1], #16 // store character to output str 37 | SUBS W3, W3, #1 // decrement loop counter and set flags 38 | B.NE loop // loop if character isn't null 39 | MOV X0, #(N*16) // get the length by subtracting the pointers 40 | RET // Return to caller 41 | 42 | .data 43 | aaas: .fill 16, 1, 'a' // 16 a's 44 | endch: .fill 16, 1, 25 // after shift, chars are 0-25 45 | spaces: .fill 16, 1, 0x20 // spaces for bic 46 | 47 | -------------------------------------------------------------------------------- /Chapter 15/.gitignore: -------------------------------------------------------------------------------- 1 | upper 2 | upper2 3 | upperghidra 4 | *.txt 5 | -------------------------------------------------------------------------------- /Chapter 15/makefile: -------------------------------------------------------------------------------- 1 | 2 | all: upper upperghidra 3 | 4 | upper: upper.c 5 | # gcc -O3 -mcmodel=tiny -o upper upper.c 6 | # clang -O3 -momit-leaf-frame-pointer -o upper upper.c 7 | clang -O3 -g -o upper upper.c 8 | clang -O3 -S -fverbose-asm -g -o upper.s upper.c 9 | objdump -d -s upper >od.txt 10 | 11 | upperghidra: upperghidra.c 12 | clang -O3 -o upperghidra upperghidra.c 13 | -------------------------------------------------------------------------------- /Chapter 15/makeods: -------------------------------------------------------------------------------- 1 | gcc -o upper upper.c 2 | objdump -d upper> onopt.txt 3 | 4 | gcc -O3 -o upper upper.c 5 | objdump -d upper> oo3.txt 6 | 7 | gcc -Os -o upper upper.c 8 | objdump -d upper> oos.txt 9 | 10 | -------------------------------------------------------------------------------- /Chapter 15/upper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int mytoupper(char *instr, char *outstr) 4 | { 5 | char cur; 6 | char *orig_outstr = outstr; 7 | 8 | do 9 | { 10 | cur = *instr; 11 | if ((cur >= 'a') && (cur <='z')) 12 | { 13 | cur = cur - ('a'-'A'); 14 | } 15 | *outstr++ = cur; 16 | instr++; 17 | } while (cur != '\0'); 18 | return( outstr - orig_outstr ); 19 | } 20 | 21 | #define BUFFERSIZE 250 22 | 23 | char *tstStr = "This is a test!"; 24 | char outStr[BUFFERSIZE]; 25 | 26 | int main() 27 | { 28 | mytoupper(tstStr, outStr); 29 | printf("Input: %s\nOutput: %s\n", tstStr, outStr); 30 | 31 | return(0); 32 | } 33 | -------------------------------------------------------------------------------- /Chapter 15/upperghidra.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define BUFFERSIZE 250 4 | 5 | char *tstStr = "This is a test!"; 6 | char outStr[BUFFERSIZE]; 7 | 8 | typedef unsigned char byte; 9 | 10 | #define true 1 11 | 12 | int main(void) 13 | 14 | { 15 | char cVar1; 16 | char *pcVar2; 17 | char *pcVar3; 18 | char *pcVar4; 19 | char *pcVar5; 20 | 21 | pcVar2 = tstStr; 22 | pcVar3 = outStr; 23 | pcVar5 = tstStr; 24 | do { 25 | cVar1 = *pcVar5; 26 | pcVar4 = pcVar3; 27 | while( true ) { 28 | pcVar3 = pcVar4 + 1; 29 | pcVar5 = pcVar5 + 1; 30 | if (0x19 < (byte)(cVar1 + 0x9fU)) break; 31 | *pcVar4 = cVar1 + -0x20; 32 | cVar1 = *pcVar5; 33 | pcVar4 = pcVar3; 34 | } 35 | *pcVar4 = cVar1; 36 | } while (cVar1 != '\0'); 37 | printf("Input: %s\nOutput: %s\n",pcVar2,outStr); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Chapter 16/.gitignore: -------------------------------------------------------------------------------- 1 | upper 2 | uppercanary 3 | upperpie 4 | -------------------------------------------------------------------------------- /Chapter 16/main.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to demonstate a buffer 3 | // overrun hacking attack. 4 | // 5 | // X0-X2 - parameters to linux function services 6 | // X1 - address of output string 7 | // X0 - address of input string 8 | // X8 - linux function number 9 | // 10 | 11 | .global _start // Provide program starting address to linker 12 | .align 4 13 | 14 | DownloadCreditCardNumbers: 15 | // Setup the parameters to print hello world 16 | // and then call Linux to do it. 17 | mov X0, #1 // 1 = StdOut 18 | adrp X1, getcreditcards@PAGE // string to print 19 | add X1, X1, getcreditcards@PAGEOFF 20 | mov X2, #30 // length of our string 21 | mov X8, #64 // Linux write system call 22 | svc 0 // Call linux to output the string 23 | ret 24 | 25 | calltoupper: 26 | STR LR, [SP, #-16]! // Put LR on the stack 27 | SUB SP, SP, #16 // 16 bytes for outstr 28 | ADRP X0, instr@PAGE // start of input string 29 | ADD X0, X0, instr@PAGEOFF 30 | MOV X1, SP // address of output string 31 | 32 | BL toupper 33 | 34 | aftertoupper: // convenient label to use as a breakpoint 35 | ADD SP, SP, #16 // Free outstr 36 | LDR LR, [SP], #16 37 | RET 38 | 39 | _start: 40 | 41 | BL calltoupper 42 | 43 | 44 | // Setup the parameters to exit the program 45 | // and then call Linux to do it. 46 | MOV X0, #0 // Use 0 return code 47 | MOV X8, #93 // Service command code 93 terminates 48 | SVC 0 // Call Linux to terminate 49 | 50 | .data 51 | instr: .ascii "This is our Test" // Correct length string 52 | .dword 0x00000000004000b0 // overwrite for LR 53 | getcreditcards: .asciz "Downloading Credit Card Data!\n" 54 | .align 4 55 | 56 | 57 | -------------------------------------------------------------------------------- /Chapter 16/mainpie.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to demonstate a buffer 3 | // overrun hacking attack. 4 | // 5 | // X0-X2 - parameters to linux function services 6 | // X1 - address of output string 7 | // X0 - address of input string 8 | // X8 - linux function number 9 | // 10 | 11 | .global _start // Provide program starting address to linker 12 | 13 | DownloadCreditCardNumbers: 14 | // Setup the parameters to print hello world 15 | // and then call Linux to do it. 16 | MOV X0, #1 // 1 = StdOut 17 | LDR X1, =getcreditcards // string to print 18 | MOV X2, #30 // length of our string 19 | MOV X8, #64 // linux write system call 20 | SVC 0 // Call linux to output the string 21 | RET 22 | 23 | calltoupper: 24 | STR LR, [SP, #-16]! // Put LR on the stack 25 | SUB SP, SP, #16 // 16 bytes for outstr 26 | LDR X0, =instr // start of input string 27 | MOV X1, SP // address of output string 28 | 29 | BL toupper 30 | 31 | aftertoupper: 32 | ADD SP, SP, #16 // Free outstr 33 | LDR LR, [SP], #16 34 | RET 35 | 36 | _start: 37 | 38 | BL calltoupper 39 | 40 | 41 | // Setup the parameters to exit the program 42 | // and then call Linux to do it. 43 | MOV X0, #0 // Use 0 return code 44 | MOV X8, #93 // Service command code 93 terminates 45 | SVC 0 // Call linux to terminate the program 46 | 47 | .data 48 | instr: .ascii "This is our Test" // Correct length string 49 | .dword 0x00000000004000b0 // overwrite for LR 50 | getcreditcards: .asciz "Downloading Credit Card Data!\n" 51 | .align 4 52 | 53 | 54 | -------------------------------------------------------------------------------- /Chapter 16/makefile: -------------------------------------------------------------------------------- 1 | UPPEROBJS = main.o upper.o 2 | 3 | ifdef DEBUG 4 | DEBUGFLGS = -g 5 | else 6 | DEBUGFLGS = 7 | endif 8 | 9 | all: upper upperpie uppercanary 10 | 11 | LDFLAGS = -lSystem -syslibroot `xcrun -sdk macosx --show-sdk-path` -e _start -arch arm64 12 | 13 | %.o : %.s 14 | as $(DEBUGFLGS) $(LSTFLGS) $< -o $@ 15 | 16 | 17 | upper: $(UPPEROBJS) 18 | ld $(LDFLAGS) -no_pie -o upper $(UPPEROBJS) 19 | 20 | upperpie: $(UPPEROBJS) 21 | ld $(LDFLAGS) -pie -o upperpie $(UPPEROBJS) 22 | 23 | uppercanary: upper.c 24 | clang -o uppercanary -fstack-protector-all -O3 upper.c 25 | -------------------------------------------------------------------------------- /Chapter 16/odcanary.txt: -------------------------------------------------------------------------------- 1 | 2 | uppercanary: file format elf64-littleaarch64 3 | 4 | 5 | Disassembly of section .init: 6 | 7 | 0000000000000690 <_init>: 8 | 690: a9bf7bfd stp x29, x30, [sp, #-16]! 9 | 694: 910003fd mov x29, sp 10 | 698: 9400005e bl 810 11 | 69c: a8c17bfd ldp x29, x30, [sp], #16 12 | 6a0: d65f03c0 ret 13 | 14 | Disassembly of section .plt: 15 | 16 | 00000000000006b0 <.plt>: 17 | 6b0: a9bf7bf0 stp x16, x30, [sp, #-16]! 18 | 6b4: 90000090 adrp x16, 10000 <__FRAME_END__+0xf3c0> 19 | 6b8: f947fe11 ldr x17, [x16, #4088] 20 | 6bc: 913fe210 add x16, x16, #0xff8 21 | 6c0: d61f0220 br x17 22 | 6c4: d503201f nop 23 | 6c8: d503201f nop 24 | 6cc: d503201f nop 25 | 26 | 00000000000006d0 <__cxa_finalize@plt>: 27 | 6d0: b0000090 adrp x16, 11000 <__cxa_finalize@GLIBC_2.17> 28 | 6d4: f9400211 ldr x17, [x16] 29 | 6d8: 91000210 add x16, x16, #0x0 30 | 6dc: d61f0220 br x17 31 | 32 | 00000000000006e0 <__libc_start_main@plt>: 33 | 6e0: b0000090 adrp x16, 11000 <__cxa_finalize@GLIBC_2.17> 34 | 6e4: f9400611 ldr x17, [x16, #8] 35 | 6e8: 91002210 add x16, x16, #0x8 36 | 6ec: d61f0220 br x17 37 | 38 | 00000000000006f0 <__stack_chk_fail@plt>: 39 | 6f0: b0000090 adrp x16, 11000 <__cxa_finalize@GLIBC_2.17> 40 | 6f4: f9400a11 ldr x17, [x16, #16] 41 | 6f8: 91004210 add x16, x16, #0x10 42 | 6fc: d61f0220 br x17 43 | 44 | 0000000000000700 <__gmon_start__@plt>: 45 | 700: b0000090 adrp x16, 11000 <__cxa_finalize@GLIBC_2.17> 46 | 704: f9400e11 ldr x17, [x16, #24] 47 | 708: 91006210 add x16, x16, #0x18 48 | 70c: d61f0220 br x17 49 | 50 | 0000000000000710 : 51 | 710: b0000090 adrp x16, 11000 <__cxa_finalize@GLIBC_2.17> 52 | 714: f9401211 ldr x17, [x16, #32] 53 | 718: 91008210 add x16, x16, #0x20 54 | 71c: d61f0220 br x17 55 | 56 | 0000000000000720 : 57 | 720: b0000090 adrp x16, 11000 <__cxa_finalize@GLIBC_2.17> 58 | 724: f9401611 ldr x17, [x16, #40] 59 | 728: 9100a210 add x16, x16, #0x28 60 | 72c: d61f0220 br x17 61 | 62 | Disassembly of section .text: 63 | 64 | 0000000000000730
: 65 | 730: a9bc7bfd stp x29, x30, [sp, #-64]! 66 | 734: 90000001 adrp x1, 0 <_init-0x690> 67 | 738: 91294025 add x5, x1, #0xa50 68 | 73c: 910003fd mov x29, sp 69 | 740: f9000bf3 str x19, [sp, #16] 70 | 744: 90000093 adrp x19, 10000 <__FRAME_END__+0xf3c0> 71 | 748: 9100a3e2 add x2, sp, #0x28 72 | 74c: f947e660 ldr x0, [x19, #4040] 73 | 750: aa0203e4 mov x4, x2 74 | 754: f9400003 ldr x3, [x0] 75 | 758: f9001fe3 str x3, [sp, #56] 76 | 75c: d2800003 mov x3, #0x0 // #0 77 | 760: 384014a0 ldrb w0, [x5], #1 78 | 764: 91000484 add x4, x4, #0x1 79 | 768: 51018403 sub w3, w0, #0x61 80 | 76c: 12001c63 and w3, w3, #0xff 81 | 770: 7100647f cmp w3, #0x19 82 | 774: 54000128 b.hi 798 // b.pmore 83 | 778: 51008000 sub w0, w0, #0x20 84 | 77c: 381ff080 sturb w0, [x4, #-1] 85 | 780: 384014a0 ldrb w0, [x5], #1 86 | 784: 91000484 add x4, x4, #0x1 87 | 788: 51018403 sub w3, w0, #0x61 88 | 78c: 12001c63 and w3, w3, #0xff 89 | 790: 7100647f cmp w3, #0x19 90 | 794: 54ffff29 b.ls 778 // b.plast 91 | 798: 381ff080 sturb w0, [x4, #-1] 92 | 79c: 35fffe20 cbnz w0, 760 93 | 7a0: 91294021 add x1, x1, #0xa50 94 | 7a4: 90000000 adrp x0, 0 <_init-0x690> 95 | 7a8: 912aa000 add x0, x0, #0xaa8 96 | 7ac: 97ffffdd bl 720 97 | 7b0: f947e673 ldr x19, [x19, #4040] 98 | 7b4: f9401fe1 ldr x1, [sp, #56] 99 | 7b8: f9400260 ldr x0, [x19] 100 | 7bc: ca000020 eor x0, x1, x0 101 | 7c0: b50000a0 cbnz x0, 7d4 102 | 7c4: 52800000 mov w0, #0x0 // #0 103 | 7c8: f9400bf3 ldr x19, [sp, #16] 104 | 7cc: a8c47bfd ldp x29, x30, [sp], #64 105 | 7d0: d65f03c0 ret 106 | 7d4: 97ffffc7 bl 6f0 <__stack_chk_fail@plt> 107 | 108 | 00000000000007d8 <_start>: 109 | 7d8: d280001d mov x29, #0x0 // #0 110 | 7dc: d280001e mov x30, #0x0 // #0 111 | 7e0: aa0003e5 mov x5, x0 112 | 7e4: f94003e1 ldr x1, [sp] 113 | 7e8: 910023e2 add x2, sp, #0x8 114 | 7ec: 910003e6 mov x6, sp 115 | 7f0: 90000080 adrp x0, 10000 <__FRAME_END__+0xf3c0> 116 | 7f4: f947ec00 ldr x0, [x0, #4056] 117 | 7f8: 90000083 adrp x3, 10000 <__FRAME_END__+0xf3c0> 118 | 7fc: f947e863 ldr x3, [x3, #4048] 119 | 800: 90000084 adrp x4, 10000 <__FRAME_END__+0xf3c0> 120 | 804: f947d484 ldr x4, [x4, #4008] 121 | 808: 97ffffb6 bl 6e0 <__libc_start_main@plt> 122 | 80c: 97ffffc1 bl 710 123 | 124 | 0000000000000810 : 125 | 810: 90000080 adrp x0, 10000 <__FRAME_END__+0xf3c0> 126 | 814: f947e000 ldr x0, [x0, #4032] 127 | 818: b4000040 cbz x0, 820 128 | 81c: 17ffffb9 b 700 <__gmon_start__@plt> 129 | 820: d65f03c0 ret 130 | 824: d503201f nop 131 | 132 | 0000000000000828 : 133 | 828: b0000080 adrp x0, 11000 <__cxa_finalize@GLIBC_2.17> 134 | 82c: 91010000 add x0, x0, #0x40 135 | 830: b0000081 adrp x1, 11000 <__cxa_finalize@GLIBC_2.17> 136 | 834: 91010021 add x1, x1, #0x40 137 | 838: eb00003f cmp x1, x0 138 | 83c: 540000c0 b.eq 854 // b.none 139 | 840: 90000081 adrp x1, 10000 <__FRAME_END__+0xf3c0> 140 | 844: f947d821 ldr x1, [x1, #4016] 141 | 848: b4000061 cbz x1, 854 142 | 84c: aa0103f0 mov x16, x1 143 | 850: d61f0200 br x16 144 | 854: d65f03c0 ret 145 | 146 | 0000000000000858 : 147 | 858: b0000080 adrp x0, 11000 <__cxa_finalize@GLIBC_2.17> 148 | 85c: 91010000 add x0, x0, #0x40 149 | 860: b0000081 adrp x1, 11000 <__cxa_finalize@GLIBC_2.17> 150 | 864: 91010021 add x1, x1, #0x40 151 | 868: cb000021 sub x1, x1, x0 152 | 86c: d37ffc22 lsr x2, x1, #63 153 | 870: 8b810c41 add x1, x2, x1, asr #3 154 | 874: eb8107ff cmp xzr, x1, asr #1 155 | 878: 9341fc21 asr x1, x1, #1 156 | 87c: 540000c0 b.eq 894 // b.none 157 | 880: 90000082 adrp x2, 10000 <__FRAME_END__+0xf3c0> 158 | 884: f947f042 ldr x2, [x2, #4064] 159 | 888: b4000062 cbz x2, 894 160 | 88c: aa0203f0 mov x16, x2 161 | 890: d61f0200 br x16 162 | 894: d65f03c0 ret 163 | 164 | 0000000000000898 <__do_global_dtors_aux>: 165 | 898: a9be7bfd stp x29, x30, [sp, #-32]! 166 | 89c: 910003fd mov x29, sp 167 | 8a0: f9000bf3 str x19, [sp, #16] 168 | 8a4: b0000093 adrp x19, 11000 <__cxa_finalize@GLIBC_2.17> 169 | 8a8: 39410260 ldrb w0, [x19, #64] 170 | 8ac: 35000140 cbnz w0, 8d4 <__do_global_dtors_aux+0x3c> 171 | 8b0: 90000080 adrp x0, 10000 <__FRAME_END__+0xf3c0> 172 | 8b4: f947dc00 ldr x0, [x0, #4024] 173 | 8b8: b4000080 cbz x0, 8c8 <__do_global_dtors_aux+0x30> 174 | 8bc: b0000080 adrp x0, 11000 <__cxa_finalize@GLIBC_2.17> 175 | 8c0: f9401c00 ldr x0, [x0, #56] 176 | 8c4: 97ffff83 bl 6d0 <__cxa_finalize@plt> 177 | 8c8: 97ffffd8 bl 828 178 | 8cc: 52800020 mov w0, #0x1 // #1 179 | 8d0: 39010260 strb w0, [x19, #64] 180 | 8d4: f9400bf3 ldr x19, [sp, #16] 181 | 8d8: a8c27bfd ldp x29, x30, [sp], #32 182 | 8dc: d65f03c0 ret 183 | 184 | 00000000000008e0 : 185 | 8e0: 17ffffde b 858 186 | 8e4: d503201f nop 187 | 188 | 00000000000008e8 : 189 | 8e8: a9be7bfd stp x29, x30, [sp, #-32]! 190 | 8ec: 90000080 adrp x0, 10000 <__FRAME_END__+0xf3c0> 191 | 8f0: 910003fd mov x29, sp 192 | 8f4: f947e400 ldr x0, [x0, #4040] 193 | 8f8: f9400001 ldr x1, [x0] 194 | 8fc: f9000fe1 str x1, [sp, #24] 195 | 900: d2800001 mov x1, #0x0 // #0 196 | 904: f9400fe1 ldr x1, [sp, #24] 197 | 908: f9400000 ldr x0, [x0] 198 | 90c: ca000020 eor x0, x1, x0 199 | 910: b5000080 cbnz x0, 920 200 | 914: 52800040 mov w0, #0x2 // #2 201 | 918: a8c27bfd ldp x29, x30, [sp], #32 202 | 91c: d65f03c0 ret 203 | 920: 97ffff74 bl 6f0 <__stack_chk_fail@plt> 204 | 924: d503201f nop 205 | 206 | 0000000000000928 : 207 | 928: a9be7bfd stp x29, x30, [sp, #-32]! 208 | 92c: 90000085 adrp x5, 10000 <__FRAME_END__+0xf3c0> 209 | 930: aa0103e4 mov x4, x1 210 | 934: 910003fd mov x29, sp 211 | 938: f947e4a2 ldr x2, [x5, #4040] 212 | 93c: f9400043 ldr x3, [x2] 213 | 940: f9000fe3 str x3, [sp, #24] 214 | 944: d2800003 mov x3, #0x0 // #0 215 | 948: 38401402 ldrb w2, [x0], #1 216 | 94c: 91000484 add x4, x4, #0x1 217 | 950: 51018443 sub w3, w2, #0x61 218 | 954: 12001c63 and w3, w3, #0xff 219 | 958: 7100647f cmp w3, #0x19 220 | 95c: 54000128 b.hi 980 // b.pmore 221 | 960: 51008042 sub w2, w2, #0x20 222 | 964: 381ff082 sturb w2, [x4, #-1] 223 | 968: 91000484 add x4, x4, #0x1 224 | 96c: 38401402 ldrb w2, [x0], #1 225 | 970: 51018443 sub w3, w2, #0x61 226 | 974: 12001c63 and w3, w3, #0xff 227 | 978: 7100647f cmp w3, #0x19 228 | 97c: 54ffff29 b.ls 960 // b.plast 229 | 980: 381ff082 sturb w2, [x4, #-1] 230 | 984: 35fffe22 cbnz w2, 948 231 | 988: f947e4a5 ldr x5, [x5, #4040] 232 | 98c: cb010080 sub x0, x4, x1 233 | 990: f9400fe2 ldr x2, [sp, #24] 234 | 994: f94000a1 ldr x1, [x5] 235 | 998: ca010041 eor x1, x2, x1 236 | 99c: b5000061 cbnz x1, 9a8 237 | 9a0: a8c27bfd ldp x29, x30, [sp], #32 238 | 9a4: d65f03c0 ret 239 | 9a8: 97ffff52 bl 6f0 <__stack_chk_fail@plt> 240 | 9ac: d503201f nop 241 | 242 | 00000000000009b0 <__libc_csu_init>: 243 | 9b0: a9bc7bfd stp x29, x30, [sp, #-64]! 244 | 9b4: 910003fd mov x29, sp 245 | 9b8: a90153f3 stp x19, x20, [sp, #16] 246 | 9bc: 90000094 adrp x20, 10000 <__FRAME_END__+0xf3c0> 247 | 9c0: 9136a294 add x20, x20, #0xda8 248 | 9c4: a9025bf5 stp x21, x22, [sp, #32] 249 | 9c8: 90000095 adrp x21, 10000 <__FRAME_END__+0xf3c0> 250 | 9cc: 913682b5 add x21, x21, #0xda0 251 | 9d0: cb150294 sub x20, x20, x21 252 | 9d4: 2a0003f6 mov w22, w0 253 | 9d8: a90363f7 stp x23, x24, [sp, #48] 254 | 9dc: aa0103f7 mov x23, x1 255 | 9e0: aa0203f8 mov x24, x2 256 | 9e4: 97ffff2b bl 690 <_init> 257 | 9e8: eb940fff cmp xzr, x20, asr #3 258 | 9ec: 54000160 b.eq a18 <__libc_csu_init+0x68> // b.none 259 | 9f0: 9343fe94 asr x20, x20, #3 260 | 9f4: d2800013 mov x19, #0x0 // #0 261 | 9f8: f8737aa3 ldr x3, [x21, x19, lsl #3] 262 | 9fc: aa1803e2 mov x2, x24 263 | a00: 91000673 add x19, x19, #0x1 264 | a04: aa1703e1 mov x1, x23 265 | a08: 2a1603e0 mov w0, w22 266 | a0c: d63f0060 blr x3 267 | a10: eb13029f cmp x20, x19 268 | a14: 54ffff21 b.ne 9f8 <__libc_csu_init+0x48> // b.any 269 | a18: a94153f3 ldp x19, x20, [sp, #16] 270 | a1c: a9425bf5 ldp x21, x22, [sp, #32] 271 | a20: a94363f7 ldp x23, x24, [sp, #48] 272 | a24: a8c47bfd ldp x29, x30, [sp], #64 273 | a28: d65f03c0 ret 274 | a2c: d503201f nop 275 | 276 | 0000000000000a30 <__libc_csu_fini>: 277 | a30: d65f03c0 ret 278 | 279 | Disassembly of section .fini: 280 | 281 | 0000000000000a34 <_fini>: 282 | a34: a9bf7bfd stp x29, x30, [sp, #-16]! 283 | a38: 910003fd mov x29, sp 284 | a3c: a8c17bfd ldp x29, x30, [sp], #16 285 | a40: d65f03c0 ret 286 | -------------------------------------------------------------------------------- /Chapter 16/upper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int dummy() 4 | { 5 | return(2); 6 | } 7 | 8 | int mytoupper(char *instr, char *outstr) 9 | { 10 | char cur; 11 | char *orig_outstr = outstr; 12 | 13 | dummy(); 14 | do 15 | { 16 | cur = *instr; 17 | if ((cur >= 'a') && (cur <='z')) 18 | { 19 | cur = cur - ('a'-'A'); 20 | } 21 | label: *outstr++ = cur; 22 | instr++; 23 | } while (cur != '\0'); 24 | return( outstr - orig_outstr ); 25 | } 26 | 27 | #define BUFFERSIZE 10 28 | 29 | int main() 30 | { 31 | char *tstStr = "This is a test!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyandevenlongerandlongerandlonger"; 32 | char outStr[BUFFERSIZE]; 33 | 34 | mytoupper(tstStr, outStr); 35 | printf("Input: %s\nOutput: %s\n", tstStr, outStr); 36 | 37 | return(0); 38 | } 39 | -------------------------------------------------------------------------------- /Chapter 16/upper.s: -------------------------------------------------------------------------------- 1 | // 2 | // Assembler program to convert a string to 3 | // all upper case. 4 | // 5 | // X1 - address of output string 6 | // X0 - address of input string 7 | // X4 - original output string for length calc. 8 | // W5 - current character being processed 9 | // W6 - minus 'a' to compare < 26. 10 | // 11 | 12 | .global toupper // Allow other files to call this routine 13 | .align 4 14 | 15 | toupper: MOV X4, X1 16 | // The loop is until byte pointed to by X1 is non-zero 17 | loop: LDRB W5, [X0], #1 // load character and increment pointer 18 | // Want to know if 'a' <= W5 <= 'z' 19 | // First subtract 'a' 20 | SUB W6, W5, #'a' 21 | // Now want to know if W6 <= 25 22 | CMP W6, #25 // chars are 0-25 after shift 23 | B.HI cont 24 | // if we got here then the letter is lowercase, so convert it. 25 | SUB W5, W5, #('a'-'A') 26 | cont: // end if 27 | STRB W5, [X1], #1 // store character to output str 28 | CMP W5, #0 // stop on hitting a null character 29 | B.NE loop // loop if character isn't null 30 | SUB X0, X1, X4 // get the length by subtracting the pointers 31 | RET // Return to caller 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Alexander von Below 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HelloSilicon 2 | 3 | An introduction to assembly on Apple silicon Macs. 4 | 5 | ## Introduction 6 | 7 | In this repository, I will code along with the book [Programming with 64-Bit ARM Assembly Language](https://link.springer.com/book/10.1007/978-1-4842-5881-1?source=shoppingads&locale=de&cjsku=9781484258804), adjusting all sample code for Apple's ARM64 line of computers. While Apple's marketing material seems to avoid a name for the platform and talks only about the M1 processor, the developer documentation uses the term "Apple silicon". I will use this term in the following. 8 | 9 | The original source code can be found [here](https://github.com/Apress/programming-with-64-bit-ARM-assembly-language). 10 | 11 | ## Prerequisites 12 | 13 | While I pretty much assume that people who made it here meet most if not all required prerequisites, it doesn't hurt to list them. 14 | 15 | * You need [Xcode 12.2](https://developer.apple.com/xcode/) or later, and to make things easier, the command line tools should be installed. This ensures that the tools are found in default locations (namely `/usr/bin`). If you are not sure that the tools are installed, check _Preferences → Locations_ in Xcode or run `xcode-select --install`. 16 | 17 | * All application samples also require at least [macOS Big Sur](https://developer.apple.com/macos/), [iOS 14](https://developer.apple.com/ios/) or their respective watchOS or tvOS equivalents. Especially for the later three systems it is not a necessity per-se (neither is Xcode 12.2), but it makes things a lot simpler. 18 | 19 | * Finally, while all samples can be adjusted to work on the iPhone and all other of Apple's ARM64 devices, for best results you should have access to an [Apple silicon Mac](https://www.apple.com/newsroom/2020/11/introducing-the-next-generation-of-mac/). 20 | 21 | 22 | ## Acknowledgments 23 | 24 | I would like to thank [@claui](https://github.com/claui), [@jannau](https://github.com/jannau), [@jrosengarden](https://github.com/jrosengarden), [@m-schmidt](https://github.com/m-schmidt), [@saagarjha](https://github.com/saagarjha), and [@zhuowei](https://github.com/zhuoweir)! They helped me when I hit a wall, or asked questions that let me improve the content. 25 | 26 | ## Changes To The Book 27 | 28 | With the exception of the existing iOS samples, the book is based on the Linux operating system. Apple's operating systems (macOS, iOS, watchOS and tvOS) are actually just flavors of the [Darwin](https://en.wikipedia.org/wiki/Darwin_(operating_system)) operating system, so they share a set of common core components. 29 | 30 | Linux and Darwin, which were both inspired by [AT&T Unix System V](http://www.unix.org/what_is_unix/history_timeline.html), are significantly different at the level we are looking at. For the listings in the book, this mostly concerns system calls (i.e. when we want the Kernel to do someting for us), and the way Darwin accesses memory. 31 | 32 | This file is organized so that you can read the book, and read about the differences for Apple silicon side by side. The headlines in this document follow those in the book. 33 | 34 | ## Chapter 1: Getting Started 35 | 36 | ### Computers and Numbers 37 | 38 | The default Calculator.app on macOS has a "Programmer Mode", too. You enable it with _View → Programmer_ (⌘3). 39 | 40 | ### CPU Registers 41 | 42 | Apple has made certain platform specific choices for the registers: 43 | 44 | * Apple reserves **X18** for its own use. Do not use this register. 45 | * The frame pointer register (**FP**, **X29**) must always address a valid frame record. 46 | 47 | ### About the GCC Assembler 48 | 49 | The book uses Linux GNU tools, such as the GNU `as` assembler. While there is an `as` command on macOS, it will invoke the integrated [LLVM Clang](https://clang.llvm.org) assembler by default. And even if there is the `-Q` option to use the GNU based assembler, this was only ever an option for x86_64 — and is already deprecated as of this writing. 50 | ``` 51 | % as -Q -arch arm64 52 | /usr/bin/as: can't specifiy -Q with -arch arm64 53 | ``` 54 | Thus, the GNU assembler syntax is not an option, and the code will have to be adjusted for the Clang assembler syntax. 55 | 56 | Likewise, while there is a `gcc` command on macOS, this simply calls the Clang C-compiler. For transparancy, all calls to `gcc` will be replaced with `clang`. 57 | 58 | ``` 59 | % gcc --version 60 | Configured with: --prefix=/Applications/Xcode-beta.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1 61 | Apple clang version 12.0.0 (clang-1200.0.32.27) 62 | Target: arm64-apple-darwin20.1.0 63 | Thread model: posix 64 | InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin 65 | ``` 66 | 67 | ### Hello World 68 | 69 | If you are reading this, I assume you already knew that the macOS Terminal can be found in _Applications → Utilities → Terminal.app_. But if you didn't I feel honored to tell you and I wish you lots of fun on this journey! Don't be afraid to ask questions. 70 | 71 | To make "Hello World" run on Apple silicon, first the changes from page 78 (Chapter 3) have to be applied to account for the differences between Darwin and the Linux kernel. 72 | To silence the warning, I insert `.align 4` (or `.p2align 2`), because Darwin likes things to be aligned on even boundaries. The books mentions this in Aligning Data in Chapter 5, page 114. 73 | 74 | System calls in Linux and macOS have several differences due to the unique conventions of each system. Here are some key distinctions: 75 | * Function Number: The function numbers differ between the two systems, with Linux using 64 and macOS using 4. The table for Darwin (Apple) system calls can be found at this link: [Darwin System Calls](https://github.com/apple-oss-distributions/xnu/blob/main/bsd/kern/syscalls.master). 76 | > [!CAUTION] 77 | > Darwin function numbers are considered private by Apple, and are subject to change. They are provided here for educational purposes only 78 | * Address for Storing Function Numbers: The address used for storing function numbers also varies. In Linux, it’s on X8, while in macOS, it’s on X16. 79 | * Interruption Call: The call for interruption is 0 in Linux, whereas it’s 0x80 on Apple Silicon. 80 | 81 | 82 | 83 | To make the linker work, a little more is needed, most of it should look familiar to Mac/iOS developers. These changes need to be applied to the `makefile` and to the `build` file. The complete call to the linker looks like this: 84 | 85 | ``` 86 | ld -o HelloWorld HelloWorld.o \ 87 | -lSystem \ 88 | -syslibroot `xcrun -sdk macosx --show-sdk-path` \ 89 | -e _start \ 90 | -arch arm64 91 | ``` 92 | 93 | We know the `-o` switch, let's examine the others: 94 | 95 | 96 | * `-lSystem` tells the linker to link our executable with `libSystem.dylib`. We do that to add the `LC_MAIN` load command to the executable. Generally, Darwin does not support [statically linked executables](https://developer.apple.com/library/archive/qa/qa1118/_index.html). It is [possible](https://stackoverflow.com/questions/32453849/minimal-mach-o-64-binary/32659692#32659692), if not especially elegant to create executables without using `libSystem.dylib`. I will go deeper into that topic when time permits. For people who read _Mac OS X Internals_ I will just add that this replaced `LC_UNIXTHREAD` as of MacOS X 10.7. 97 | * `-sysroot`: In order to find `libSystem.dylib`, it is mandatory to tell our linker where to find it. It seems this was not necessary on macOS 10.15 because _"New in macOS Big Sur 11 beta, the system ships with a built-in dynamic linker cache of all system-provided libraries. As part of this change, copies of dynamic libraries are no longer present on the filesystem."_. We use `xcrun -sdk macosx --show-sdk-path` to dynamically use the currently active version of Xcode. 98 | * `-e _start`: Darwin expects an entrypoint `_main`. In order to keep the sample both as close as possible to the book, and to allow it's use within the C-Sample from _Chapter 3_, I opted to keep `_start` and tell the linker that this is the entry point we want to use 99 | * `-arch arm64` for good measure, let's throw in the option to cross-compile this from an Intel Mac. You can leave this off when running on Apple silicon. 100 | 101 | 102 | ### Reverse Engineering Our Program 103 | 104 | While the `objdump` command line program works just as well on Darwin and produces the expected output, also try the `--macho` (or `-m`) option, which causes objdump to use the Mach-O specific object file parser. 105 | 106 | ## Chapter 2: Loading and Adding 107 | 108 | The changes from [Chapter 1](https://github.com/below/HelloSilicon#chapter-1) (makefile, alignment, system calls) have to be applied. 109 | 110 | ### Register and Shift 111 | 112 | The gcc assembler accepts `MOV X1, X2, LSL #1`, which is not defined by the [ARM Compiler User Guide](https://developer.arm.com/documentation/dui0801/g/A64-General-Instructions/MOV--register-?lang=en). Instead, `LSL X1, X2, #1` (etc) is used. 113 | 114 | ### Register and Extension 115 | 116 | Clang requires the source register to be 32-bit. This makes sense because with these extensions, the upper 32 Bit of a 64-bit register will never be touched: 117 | ``` 118 | ADD X2, X1, W0, SXTB 119 | ``` 120 | The GNU Assembler seems to ignore this and allows you to specifiy a 64-bit source register. 121 | 122 | ## Chapter 3: Tooling Up 123 | 124 | ### Beginning GDB 125 | 126 | On macOS, `gdb` has been replaced with the [LLDB Debugger](https://lldb.llvm.org) `lldb` of the LLVM project. The syntax is not always the same as for gdb, so I will note the differences here. 127 | 128 | To start debugging our **movexamps** program, enter the command 129 | 130 | ``` 131 | lldb movexamps 132 | ``` 133 | 134 | This yields the abbreviated output: 135 | 136 | ``` 137 | (lldb) target create "movexamps" 138 | Current executable set to 'movexamps' (arm64). 139 | (lldb) 140 | ``` 141 | 142 | Commands like `run` or `list` work just the same, and there is a nice [GDB to LLDB command map](https://lldb.llvm.org/use/map.html). 143 | 144 | To disassemble our program, a slightly different syntax is used for lldb: 145 | 146 | ``` 147 | disassemble --name start 148 | ``` 149 | 150 | Note that because we are linking a dynamic executable, the listing will be long and include other `start` functions. Our code will be listed under the line ``movexamps`start``. 151 | 152 | Likewise, lldb wants the breakpoint name without the underscore: `b start` 153 | 154 | To get the registers on lldb, we use **register read** (or **re r**). Without arguments, this command will print all registers, or you can specify just the registers you would like to see, like `re r SP X0 X1`. 155 | 156 | We can see all the breakpoints with **breakpoint list** (or **br l**). We can delete a breakpoint with **breakpoint delete** (or **br de**) specifying the breakpoint number to delete. 157 | 158 | **lldb** has even more powerful mechanisms to display memory. The main command is **memory read** (or **m read**). For starters, these are the parameters used by the book: 159 | 160 | ``` 161 | memory read -fx -c4 -s4 $address 162 | ``` 163 | 164 | where 165 | * **-f** is the display format 166 | * **-s** size of the data 167 | * **-c** count 168 | 169 | ### Listing 3-1 170 | 171 | As an exercise, I have added code to find the default Xcode toolchain on macOS. In the book they are using this to later switch from a Linux to an Android toolchain. This process is much different for macOS and iOS: It does not usually involve a different toolchain, but instead a different Software Development Kit (SDK). You can see this in [Listing 1-1](https://github.com/below/HelloSilicon#listing-1-1) where `-sysroot` is set. 172 | 173 | That said, while it is possible to build an iOS executable with the command line it is not a trivial process. So for building apps I will stick to Xcode. 174 | 175 | ### Apple Xcode 176 | 177 | As [Chapter 10](https://github.com/below/HelloSilicon#chapter-10) focusses on building an app that will run on iOS, I have chosen to simply create a Command Line Tool here which is now using the same `HelloWorld.s` file. 178 | 179 | Be aware that the function numbers are not only different, but on Darwin, they are considered private and subject to change. 180 | 181 | ## Chapter 4: Controlling Program Flow 182 | 183 | Besides the common changes, we face a new issue which is described in the book in Chapter 5: Darwin does not like `LDR X1, =symbol`, it will produce the error `ld: Absolute addressing not allowed in arm64 code`. If we use `ADR X1, symbol`, as suggested in Chapter 3 of the book, our data has to be in the read-only `.text` section. In this sample however, we want writable data. 184 | 185 | The [Apple Documentation](https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachOTopics/1-Articles/x86_64_code.html#//apple_ref/doc/uid/TP40005044-SW1) tells us that on Darwin: 186 | > All large or possibly nonlocal data is accessed indirectly through a global offset table (GOT) entry. The GOT entry is accessed directly using RIP-relative addressing. 187 | 188 | And by default, on Darwin all data contained in the `.data` section, where data is writeable, is "possibly nonlocal". 189 | 190 | The full answer can be found [here](https://reverseengineering.stackexchange.com/a/15324): 191 | > The `ADRP` instruction loads the address of the 4KB page anywhere in the +/-4GB (33 bits) range of the current instruction (which takes 21 high bits of the offset). This is denoted by the `@PAGE` operator. then, we can either use `LDR` or `STR` to read or write any address inside that page or `ADD` to to calculate the final address using the remaining 12 bits of the offset (denoted by `@PAGEOFF`). 192 | 193 | So this: 194 | 195 | ``` 196 | LDR X1, =outstr // address of output string 197 | ``` 198 | 199 | becomes this: 200 | 201 | ``` 202 | ADRP X1, outstr@PAGE // address of output string 4k page 203 | ADD X1, X1, outstr@PAGEOFF // offset to outstr within the page 204 | ``` 205 | 206 | ### Exercises 207 | 208 | I was asked how to read the command line, and I gladly [answered](https://github.com/below/HelloSilicon/issues/22#issuecomment-682205151) the question. 209 | 210 | Sample code can be found in Chapter 4 in the file [`case.s`](Chapter%2004/case.s). 211 | 212 | ## Chapter 5: Thanks for the Memories 213 | 214 | The important differences in memory addressing for Darwin were already addresed above. 215 | 216 | ### Listing 5-1 217 | The `quad`, `octa` and `fill` keywords must be in lowercase for the llvm assembler. (See bottom of this file) 218 | 219 | ### Listing 5-10 220 | 221 | Changes like in Chapter 4. 222 | 223 | ## Chapter 6: Functions and the Stack 224 | 225 | As we learned in Chapter 5, all assembler directives (like `.equ`) must be in lowercase. 226 | 227 | ## Chapter 7: Linux Operating System Services 228 | `asm/unistd.h` does not exist in the Apple SDKs, instead `sys/syscalls.h` can be used. 229 | 230 | **Warning:** Be aware that syscall numbers in Darwin are officially considered private and subject to change. They are presented here for educational purposes only. 231 | 232 | It is also important to notice that while the calls and definitions look similar, Linux and Darwin are not the same: `AT_FDCWD` is -100 on Linux, but must be -2 on Darwin. 233 | 234 | Unlike Linux, errors are signified by setting the carry flag, and the error codes are non-negative. We therefore `MOV` the result into the required register instead of `ADDS` (we don't need to check for negative numbers, and need to preserve the condition flags) and B.CC to the success path. 235 | 236 | ## Chapter 8: Programming GPIO Pins 237 | 238 | This chapter is specifically for the Raspberry Pi 4, so there is nothing to do here. 239 | 240 | ## Chapter 9: Interacting with C and Python 241 | 242 | For transparency reasons, I replaced `gcc` with `clang`. 243 | 244 | ### Listing 9-1 245 | Apart from the usual changes, Apple diverges from the ARM64 standard ABI (i.e. the convention how functions are called) for variadic functions. Variadic functions are functions which take a variable number of arguments, and `printf` is one of them. Where Linux will accept arguments passed in the registers we must pass them on the stack for Darwin. 246 | 247 | ``` 248 | str X1, [SP, #-32]! // Move the stack pointer four doublewords (32 bytes) down and push X1 onto the stack 249 | str X2, [SP, #8] // Push X2 to one doubleword above the current stack pointer 250 | str X3, [SP, #16] // Push X3 to two doublewords above the current stack pointer 251 | adrp X0, ptfStr@PAGE // printf format str 252 | add X0, X0, ptfStr@PAGEOFF // add offset for format str 253 | bl _printf // call printf 254 | add SP, SP, #32 // Clean up stack 255 | ``` 256 | 257 | So first, we are growing the stack downwards 32 bytes to make room for three 64-bit values. We are creating space for a fourth value for padding because, as pointed out on page 137 in the book, ARM hardware requires the stack pointer to always be 16-byte aligned. 258 | 259 | In the same command, **X1** is stored at the new location of the stack pointer. 260 | 261 | Now, we fill the rest of the space that was just created by storing **X2** in a location eight bytes above, and **X3** 16 bytes above the stack pointer. Note that the **str** commands for **X2** and **X3** do not move **SP**. 262 | 263 | We could fill the stack in different ways; what is important that the `printf` function expects the parameters as doubleword values in order, upwards from the current stackpointer. So in the case of the `debug.s` file, it expects the parameter for the `%c` to be at the location of **SP**, the parameter for `%32ld` at one doubleword above this, and finally the parameter for `%016lx` two doublewords, 16 bytes, above the current stack pointer. 264 | 265 | What we have effectively done is [allocating memory on the stack](https://en.wikipedia.org/wiki/Stack-based_memory_allocation). As we, the caller, "own" that memory we need to release it after the function branch, in this case simply by shrinking the stack (upwards) by the 32 bytes we allocated. The instruction `add SP, SP, #32` will do that. 266 | 267 | ### Listing 9-5 268 | `mytoupper` was prefixed with `_` as this is necessary for C on Darwin to find it. 269 | 270 | ### Listing 9-6 271 | 272 | No change was required. 273 | 274 | ### Listing 9-7 275 | Instead of a shared `.so` ELF library, a dynamic Mach-O libary is created. Further information can be found here: [Creating Dynamic Libraries](https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/CreatingDynamicLibraries.html) 276 | 277 | ### Listing 9-8 278 | In inline-assembly, which we are using here, The `cont` label must be declared as a local label by prefixing it with `L`. While this was not necessary in pure assembly, like in Chapter 5, the llvm C-Frontend will automatically add the directive [`.subsections_via_symbols`](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/Assembler/040-Assembler_Directives/asm_directives.html#//apple_ref/doc/uid/TP30000823-SW13) to the code: 279 | 280 | > Funny Darwin hack: This flag tells the linker that no global symbols contain code that falls through to other global symbols (e.g. the obvious implementation of multiple entry points). If this doesn't occur, the linker can safely perform dead code stripping. Since LLVM never generates code that does this, it is always safe to set. 281 | (From [llvm source code](https://github.com/llvm/llvm-project/blob/89b57061f7b769e9ea9bf6ed686e284f3e55affe/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp#L568)) 282 | 283 | While we are using the LLVM toolchain, in assembly — including inline-assembly — all safety checks are off so we must take extra precautions and specifically declare the forward label local. 284 | 285 | Also, the size of one variable had to be changed from int to long to make the compiler complete happy and remove all warnings 286 | 287 | ### Calling Assembly from Python 288 | 289 | ### Listing 9-9 290 | 291 | While the `uppertst5.py` file only needed a minimal change, calling the code is a little more challenging. On Apple silicon Macs, Python is a Mach-O universal binary with two architectures, x86\_64 and arm64e: 292 | 293 | ``` 294 | % lipo -info /usr/bin/python3 295 | Architectures in the fat file: /usr/bin/python3 are: x86_64 arm64e 296 | ``` 297 | 298 | Notably absent is the arm64 architecture we were building for up to this point. This makes our dylib unusable with Python. 299 | 300 | arm64e is the [Armv-8 architecture](https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/armv8-a-architecture-2016-additions), which Apple is using since the A12 chip. If you want to address devices prior to the A12, you must stick to arm64. The first Macs to use ARM64 run on the M1 CPU based on the A14 architecture, thus Apple decided to take advangage of the new features. 301 | 302 | So, what to do? We could compile everything as arm64e, but that would make the library useless on devices like the iPhone X or older, and we would like to support them, too. 303 | 304 | Above, you read something about a _universal binary_. For a very long time, the Mach-O executable format was supporting several processor architectures in a single file. This includes, but is not limited to, Motorola 68k (on NeXT computers), PowerPC, Intel x86, as well ARM code, each with their 32 and 64 bit variantes where applicable. In this case, I am building a universal dynamic library which includes both arm64 and arm64e code. More information can be found [here](https://developer.apple.com/documentation/xcode/building_a_universal_macos_binary). 305 | 306 | While most of the Python IDEs that work for Linux are also avilable for macOS, as of this writing, the only Python IDEs which itself runs as arm64 — and thus will load arm64 libraries — is Python.org [IDLE](https://www.python.org/downloads/macos/), version 3.10 or newer. 307 | 308 | ![Figure 9-1. . Our Python program running in the IDLE IDE](images/Figure_9-1.png?raw=true "Our Python program running in the IDLE IDE") 309 | 310 | ***Figure 9-1.*** *Our Python program running in the IDLE IDE* 311 | 312 | Alternatively, you can use the command line to test the program. (As of macOS 12.3, Apple [removed Python 2](https://developer.apple.com/documentation/macos-release-notes/macos-12_3-release-notes) and developers should use Python 3) 313 | 314 | ``` 315 | % python3 uppertst5.py 316 | b'This is a test!' 317 | b'THIS IS A TEST!' 318 | 16 319 | ``` 320 | 321 | A final note: While the Apple python3 binary is arm64e, the Python Framework used by IDLE is arm64. The fact that the library built in this chapter is a universal binary containing both architectures allows it to be used in either environment. 322 | 323 | 324 | ## Chapter 10: Interfacing with Kotlin and Swift 325 | 326 | No changes in the core code were required, but instead of just an iOS app I created a SwiftUI app that will work on macOS, iOS, watchOS (Series 4 and later), and tvOS. 327 | 328 | ## Chapter 11: Multiply, Divide, and Accumulate 329 | 330 | At this point, the changes should be self-explainatory. The usual makefile adjustments, `.align 4`, address mode changes, and `_printf` adjustments. 331 | 332 | ## Chapter 12: Floating-Point Operations 333 | 334 | Like in Chapter 11, all the chages have been introduced already. Nothing new here. 335 | 336 | ## Chapter 13: Neon Coprocessor 337 | 338 | The example used a nonstandard syntax for referencing a single vector element, 339 | which GNU assembler accepts, but Clang doesn't. 340 | Where the example used `V3.4H[0]` for referencing the first 16 bit element, 341 | the correct, standard syntax is `V3.H[0]`, which is accepted both by GNU 342 | assembler and Clang. 343 | 344 | All other changes to the code should be trivial at this point. 345 | 346 | ## Chapter 14: Optimizing Code 347 | 348 | No unusal changes here. 349 | 350 | ## Chapter 15: Reading and Understanding Code 351 | 352 | ### Copying a Page of Memory 353 | 354 | Some place to start reading ARM64 code in the Darwin Kernel can be found in [bcopy.s](https://github.com/apple/darwin-xnu/blob/master/osfmk/arm64/bcopy.s). There is a lot more in that directory and the repository in general. 355 | 356 | ### Code Created by GCC 357 | 358 | No changes were required. The "tiny" code model is not supported for Mach-O excecutables: 359 | 360 | ``` 361 | % clang -O3 -mcmodel=tiny -o upper upper.c 362 | fatal error: error in backend: tiny code model is only supported on ELF 363 | ``` 364 | 365 | ## Chapter 16: Hacking Code 366 | 367 | All that can be said is that clang automatically enables position-independent executables, and the option `-no-pie` does not work. Therefore, the exploit shown in the `upper.s` file can not be reproduced. 368 | 369 | ## Additional references 370 | 371 | * [Writing ARM64 Code for Apple Platforms](https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms), documentation how Apple platforms diverge from the standard 64-bit ARM architecture 372 | * [Mach-O Programming Topics](https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/MachOTopics/0-Introduction/introduction.html#//apple_ref/doc/uid/TP40001827-SW1), an excellent introduction to the Mach-O executable format and how it differs from ELF. Even if it still refrences PowerPC 64-bit architecture and says nothing about ARM, most of it is still true. 373 | * [What is required for a Mach-O executable to load?](https://stackoverflow.com/a/42399119/1600891) 374 | * [Mac OS X Internals, A Systems Approach](https://www.pearson.ch/Informatik/Macintosh/EAN/9780134426549/Mac-OS-X-Internals) Amit Singh, 2007. For better or worse, this is still the definite compendium on the core of macOS and it's siblings. 375 | * [WWDC20: Explore the new system architecture of Apple silicon Macs](https://developer.apple.com/videos/play/wwdc2020/10686/) A system overview of the new Apple silicon machines 376 | * [Darwin Source Code](https://opensource.apple.com/source/xnu/) 377 | * [ARM Architecture Reference Manual](https://developer.arm.com/documentation/ddi0487/latest/) 378 | 379 | ## One More Thing… 380 | _"The C language is case-sensitive. Compilers are case-sensitive. The Unix command line, ufs, and nfs file systems are case-sensitive. I'm case-sensitive too, especially about product names. The IDE is called Xcode. Big X, little c. Not XCode or xCode or X-Code. Remember that now."_ — Chris Espinosa 381 | -------------------------------------------------------------------------------- /images/Figure_9-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/below/HelloSilicon/eb91924a2839375642a0af727fda937765c0cd7f/images/Figure_9-1.png --------------------------------------------------------------------------------