diff --git a/Chapter 09/uppertst4.c b/Chapter 09/uppertst4.c index 7223296..9faf980 100644 --- a/Chapter 09/uppertst4.c +++ b/Chapter 09/uppertst4.c @@ -19,11 +19,11 @@ int main() "MOV X4, %2\n" "loop: LDRB W5, [%1], #1\n" "CMP W5, #'z'\n" - "BGT 2f\n" + "BGT Lcont\n" "CMP W5, #'a'\n" - "BLT 2f\n" + "BLT Lcont\n" "SUB W5, W5, #('a'-'A')\n" - "2: STRB W5, [%2], #1\n" + "Lcont: STRB W5, [%2], #1\n" "CMP W5, #0\n" "B.NE loop\n" "SUB %0, %2, X4\n" diff --git a/Chapter 10/ToUpper/ToUpper.xcodeproj/project.pbxproj b/Chapter 10/ToUpper/ToUpper.xcodeproj/project.pbxproj index 8476648..c9d152a 100644 --- a/Chapter 10/ToUpper/ToUpper.xcodeproj/project.pbxproj +++ b/Chapter 10/ToUpper/ToUpper.xcodeproj/project.pbxproj @@ -340,7 +340,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1200; - LastUpgradeCheck = 1200; + LastUpgradeCheck = 1300; TargetAttributes = { CB64C38724CED9F700D1C852 = { CreatedOnToolsVersion = 12.0; @@ -655,6 +655,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; ENABLE_PREVIEWS = YES; @@ -676,6 +677,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; ENABLE_PREVIEWS = YES; diff --git a/Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (iOS).xcscheme b/Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (iOS).xcscheme index 6790bc6..746b446 100644 --- a/Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (iOS).xcscheme +++ b/Chapter 10/ToUpper/ToUpper.xcodeproj/xcshareddata/xcschemes/ToUpper (iOS).xcscheme @@ -1,6 +1,6 @@ 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. And by default, on Darwin all data contained in the `.data` section, where data is writeable, is "possibly nonlocal". -The full answer can be found [here](https://reverseengineering.stackexchange.com/a/15324): +The full answer can be found [here](https://reverseengineering.stackexchange.com/a/15324): > 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`). -So this: +So this: ``` LDR X1, =outstr // address of output string @@ -189,9 +189,9 @@ becomes this: ### Excersises -I was asked how to read the command line, and I gladly [answered](https://github.com/below/HelloSilicon/issues/22#issuecomment-682205151) the question. +I was asked how to read the command line, and I gladly [answered](https://github.com/below/HelloSilicon/issues/22#issuecomment-682205151) the question. -Sample code can be found in Chapter 4 in the file [`case.s`](Chapter%204/case.s). +Sample code can be found in Chapter 4 in the file [`case.s`](Chapter%2004/case.s). ## Chapter 5 @@ -206,7 +206,7 @@ Changes like in Chapter 4. ## Chapter 6 -As we learned in Chapter 5, all assembler directives (like `.equ`) must be in lowercase. +As we learned in Chapter 5, all assembler directives (like `.equ`) must be in lowercase. ## Chapter 7 `asm/unistd.h` does not exist in the Apple SDKs, instead `sys/syscalls.h` can be used. @@ -234,13 +234,13 @@ bl _printf // call printf add SP, SP, #32 // Clean up stack ``` -So first, we are growing the stack downwards 32 bytes, to make room for three 64-Bit values. And because, as pointed out on page 137 in the book, ARM hardware requires the stack pointer to always be 16-byte aligned, we are creating space for a fourth value for padding. +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. In the same command, **X1** is stored at the new location of the stack pointer. -Now, we fill the rest of the space we 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**. +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**. -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. +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. 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. @@ -255,19 +255,24 @@ No change was required. 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) ### Listing 9-8 -The size of one variable had to be changed from int to long to make the assembler happy. +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: -More importantly, I had to change the `loop` label to a numeric label, and branch to it with the `f` — forward — option. If anyone has an idea how a non-numeric label can be used here, that would be apprecated. +> 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. +(From [llvm source code](https://github.com/llvm/llvm-project/blob/89b57061f7b769e9ea9bf6ed686e284f3e55affe/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp#L568)) + +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. + +Also, the size of one variable had to be changed from int to long to make the compiler complete happy and remove all warnings ### Listing 9-9 -While the `uppertst5.py` file only needed a minimal change, calling the code was more challenging than I had thought: On the MWMNSA, python is a Mach-O universal binary with two architectures: x86_64 and arm64e. Notably absent is the arm64 architecture we were building for up to this point. This makes our dylib unusable with python. +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. Notably absent is the arm64 architecture we were building for up to this point. This makes our dylib unusable with python. -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, thus Apple decided to take advangage of the new features. +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. -So, what to do? We could compile everything as arm64e, but that would make the library useless on any iPhone but the very latest, and we would like to support those, too. +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. -Above, you read something about _universal binary_. For a very long time, the Mach-O executable format had support for 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). +Above, you read something about a _universal binary_. For a very long time, the Mach-O executable format had support for 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). ## Chapter 10 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.