Git Product home page Git Product logo

hellosilicon's Introduction

HelloSilicon

An introduction to assembly on Apple silicon Macs.

Introduction

In this repository, I will code along with the book Programming with 64-Bit ARM Assembly Language, 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.

The original source code can be found here.

Prerequisites

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.

  • You need Xcode 12.2 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.

  • All application samples also require at least macOS Big Sur, iOS 14 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.

  • 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.

Acknowledgments

I would like to thank @claui, @jannau, @jrosengarden, @m-schmidt, @saagarjha, and @zhuowei! They helped me when I hit a wall, or asked questions that let me improve the content.

Changes To The Book

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 operating system, so they share a set of common core components.

Linux and Darwin, which were both inspired by AT&T Unix System V, 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.

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.

Chapter 1: Getting Started

Computers and Numbers

The default Calculator.app on macOS has a "Programmer Mode", too. You enable it with View → Programmer (⌘3).

CPU Registers

Apple has made certain platform specific choices for the registers:

  • Apple reserves X18 for its own use. Do not use this register.
  • The frame pointer register (FP, X29) must always address a valid frame record.

About the GCC Assembler

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 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.

% as -Q -arch arm64
/usr/bin/as: can't specifiy -Q with -arch arm64

Thus, the GNU assembler syntax is not an option, and the code will have to be adjusted for the Clang assembler syntax.

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.

% gcc --version
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
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: arm64-apple-darwin20.1.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

Hello World

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.

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. 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.

System calls in Linux and macOS have several differences due to the unique conventions of each system. Here are some key distinctions:

  • 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. Please note that this is a specific version (the most recent at the time of writing), and newer versions can be found here.

Caution

Darwin function numbers are considered private by Apple, and are subject to change. They are provided here for educational purposes only

  • 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.
  • Interruption Call: The call for interruption is 0 in Linux, whereas it’s 0x80 on Apple Silicon.

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:

ld -o HelloWorld HelloWorld.o \
	-lSystem \
	-syslibroot `xcrun -sdk macosx --show-sdk-path` \
	-e _start \
	-arch arm64

We know the -o switch, let's examine the others:

  • -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. It is possible, 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.
  • -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.
  • -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
  • -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.

Reverse Engineering Our Program

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.

Chapter 2: Loading and Adding

The changes from Chapter 1 (makefile, alignment, system calls) have to be applied.

Register and Shift

The gcc assembler accepts MOV X1, X2, LSL #1, which is not defined by the ARM Compiler User Guide, instead LSL X1, X2, #1 (etc) is used. After all, both are just aliasses for the instruction ORR X1, XZR, X2, LSL #1.

Register and Extension

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:

ADD X2, X1, W0, SXTB

The GNU Assembler seems to ignore this and allows you to specifiy a 64-bit source register.

Chapter 3: Tooling Up

Beginning GDB

On macOS, gdb has been replaced with the LLDB Debugger lldb of the LLVM project. The syntax is not always the same as for gdb, so I will note the differences here.

To start debugging our movexamps program, enter the command

lldb movexamps

This yields the abbreviated output:

(lldb) target create "movexamps"
Current executable set to 'movexamps' (arm64).
(lldb)

Commands like run or list work just the same, and there is a nice GDB to LLDB command map.

To disassemble our program, a slightly different syntax is used for lldb:

disassemble --name start

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.

Likewise, lldb wants the breakpoint name without the underscore: b start

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.

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.

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:

memory read -fx -c4 -s4 $address

where

  • -f is the display format
  • -s size of the data
  • -c count

Listing 3-1

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 where -sysroot is set.

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.

Apple Xcode

As 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.

Be aware that the function numbers are not only different, but on Darwin, they are considered private and subject to change.

Chapter 4: Controlling Program Flow

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 ASR 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.

The Apple Documentation tells us that on Darwin:

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:

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:

	LDR	X1, =outstr // address of output string

becomes this:

	ADRP	X1, outstr@PAGE	// address of output string 4k page
	ADD	X1, X1, outstr@PAGEOFF // offset to outstr within the page

Exercises

I was asked how to read the command line, and I gladly answered the question.

Sample code can be found in Chapter 4 in the file case.s.

Chapter 5: Thanks for the Memories

The important differences in memory addressing for Darwin were already addresed above.

Listing 5-1

The quad, octa and fill keywords must be in lowercase for the llvm assembler. (See bottom of this file)

Listing 5-10

Changes like in Chapter 4.

Chapter 6: Functions and the Stack

As we learned in Chapter 5, all assembler directives (like .equ) must be in lowercase.

Chapter 7: Linux Operating System Services

asm/unistd.h does not exist in the Apple SDKs, instead sys/syscalls.h can be used.

Warning: Be aware that syscall numbers in Darwin are officially considered private and subject to change. They are presented here for educational purposes only.

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.

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.

Chapter 8: Programming GPIO Pins

This chapter is specifically for the Raspberry Pi 4, so there is nothing to do here.

Chapter 9: Interacting with C and Python

For transparency reasons, I replaced gcc with clang.

Listing 9-1

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.

str     X1, [SP, #-32]! // Move the stack pointer four doublewords (32 bytes) down and push X1 onto the stack
str     X2, [SP, #8]    // Push X2 to one doubleword above the current stack pointer
str     X3, [SP, #16]   // Push X3 to two doublewords above the current stack pointer
adrp    X0, ptfStr@PAGE // printf format str
add     X0, X0, ptfStr@PAGEOFF  // add offset for format str
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. 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 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.

What we have effectively done is allocating memory on the stack. 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.

Listing 9-5

mytoupper was prefixed with _ as this is necessary for C on Darwin to find it.

Listing 9-6

No change was required.

Listing 9-7

Instead of a shared .so ELF library, a dynamic Mach-O libary is created. Further information can be found here: Creating Dynamic Libraries

Listing 9-8

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 to the code:

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)

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

Calling Assembly from Python

Listing 9-9

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:

% lipo -info /usr/bin/python3 
Architectures in the fat file: /usr/bin/python3 are: x86_64 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, 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 devices like the iPhone X or older, and we would like to support them, too.

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.

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, version 3.10 or newer.

Figure 9-1. . Our Python program running in the IDLE IDE

Figure 9-1. Our Python program running in the IDLE IDE

Alternatively, you can use the command line to test the program. (As of macOS 12.3, Apple removed Python 2 and developers should use Python 3)

% python3 uppertst5.py 
b'This is a test!'
b'THIS IS A TEST!'
16

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.

Chapter 10: Interfacing with Kotlin and Swift

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.

Chapter 11: Multiply, Divide, and Accumulate

At this point, the changes should be self-explainatory. The usual makefile adjustments, .align 4, address mode changes, and _printf adjustments.

Chapter 12: Floating-Point Operations

Like in Chapter 11, all the chages have been introduced already. Nothing new here.

Chapter 13: Neon Coprocessor

Once again, the Clang assembler wants a slightly different syntax: Where gcc accepts

MUL V6.4H, V0.4H, V3.4H[0]

the Clang assembler expects

MUL.4H V6, V0, V3[0]

All other changes to the code should be trivial at this point.

Chapter 14: Optimizing Code

No unusal changes here.

Chapter 15: Reading and Understanding Code

Copying a Page of Memory

Some place to start reading ARM64 code in the Darwin Kernel can be found in bcopy.s. There is a lot more in that directory and the repository in general.

Code Created by GCC

No changes were required. The "tiny" code model is not supported for Mach-O excecutables:

% clang -O3 -mcmodel=tiny -o upper upper.c
fatal error: error in backend: tiny code model is only supported on ELF

Chapter 16: Hacking Code

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.

Additional references

One More Thing…

"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

hellosilicon's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hellosilicon's Issues

Change "as" to "clang" in all examples

"The stand-alone system assemblers for i386, x86_64, and arm are deprecated and may be removed in a future Xcode release. Using the as command with the -Q flag shows a warning that instructs you to transition to Clang’s integrated assembler and the -q flag. The as(1) driver will remain, as a standard way to invoke Clang’s integrated assembler, as well as any assemblers installed by the developer. (61299833)"

GAS generates local symbols for labels starting with the letter L

To be clear, I haven't used the setup in HelloSilicon, I'm just using Xcode out of the box. Still, this might be relevant here as well.
One caveat I've come across is that GAS generates local symbols for labels starting with the letter l. Thus, labels such as 'loop' are completely ignored by the debugger and breakpoint and single stepping behavior becomes weird. For example, setting a breakpoint anywhere in the loop will pause execution only at the next label in program order (say, cont in upper.s). Also, single stepping and hitting a branch back to loop (e.g. B.NE loop) doesn't get back there, but again hits the next label. Just mentioning this, since many examples in the book have loops.

Authoritative documentation of assembler for M1 machines?

I really appreciate this repository, and this isn't an issue with it as such, but I wanted to ask if anyone here can provide an actual documentation page for the assembler apple uses. It seems the mac OS X Assembler guide (old copy at http://personal.denison.edu/~bressoud/cs281-s07/Assembler.pdf )is out of date, and there isn't a meaningful guide for clang llvm assmbler (I guess, that's because it's a framework, not an assembler with macros and directives).

I sortof managed to muddle through some of the problems, but there are differences between apple's old documentation and the gas manual. E.g. macros - they can take named parameters. But you can't redefine symbols with .set (which is sometimes quite useful). I'd be great to have an authoritative manual, or alternatives to the apple assembler. E.g., is there a yasm etc that can be used ? I asked around in other places, but not much success yet.

I'm hesitant to make this an issue here, as this isn't y'all's fault. However, it seems y'all had to figure some of this out and it would be great to share any expertise you might have. If this is an unreasonable imposition, please feel free to close this without a comment.

Many thanks in advance.

Opting out of libc on Apple Silicon

Embedded platforms don't do static. However, if you're still curious here's how you can convince Xcode to make those files:

diff --git a/AsMain/main.s b/AsMain/main.s
index 953236a..61760cd 100644
--- a/AsMain/main.s
+++ b/AsMain/main.s
@@ -6,12 +6,11 @@
 // X16 - Mach function number
 //
 
-.global _main	            // Provide program starting address to linker
+.global start	            // Provide program starting address to linker
 .align 2
-
 // Setup the parameters to print hello world
 // and then call Linux to do it.
-_main: mov	X0, #1	    // 1 = StdOut
+start: mov	X0, #1	    // 1 = StdOut
     adr	X1, helloworld // string to print
 	mov	X2, #13	    // length of our string
 	mov	X16, #4	    // linux write system call
diff --git a/MacAs.xcodeproj/project.pbxproj b/MacAs.xcodeproj/project.pbxproj
index 11b501e..f95d6bd 100644
--- a/MacAs.xcodeproj/project.pbxproj
+++ b/MacAs.xcodeproj/project.pbxproj
@@ -318,6 +318,8 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CODE_SIGN_STYLE = Automatic;
+				LINK_WITH_STANDARD_LIBRARIES = NO;
+				OTHER_LDFLAGS = "-static";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Debug;
@@ -326,6 +328,8 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CODE_SIGN_STYLE = Automatic;
+				LINK_WITH_STANDARD_LIBRARIES = NO;
+				OTHER_LDFLAGS = "-static";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Release;

Screen Shot 2020-07-04 at 19 50 03

If you put an underscore in front of main in both places and give up on static linking:

Screen Shot 2020-07-04 at 19 51 31

Chapter 13, NEON: Invalid operand for instruction MUL

MUL \ccol\().4H, V0.4H, \bcol\().4H[0]

While the distance code works, the matrixmultneon code does not, and building it leads to the following error:

<instantiation>:1:24: error: invalid operand for instruction
MUL V6.4H, V0.4H, V3.4H[0]
                        ^

The book says:

MUL V6.4H, V0.4H, V3.4H[0]
This is multiplying each lane in V0 by the scalar contained in a specific lane of V3. This shows how we typically access a value in a specific lane by appending [lane number] to the end of the register specifier—counting lanes from zero.

Adding -arch arm64e does not change anything.

Maybe @steipete has an idea?

Brief explanation of changes

I've just started reading the book and when I got to the HelloWorld I noticed that the approach for doing system calls is different.

Since the repo went to trouble of stating where the terminal is (😅), I think a brief explanation of the differences would be important.

On the book (Linux):

...
_start: mov     X0, #1          // 1 = StdOut
     ldr        X1, =helloworld // string to print
     mov        X2, #13         // length of our string
     mov        X8, #64         // Linux write system call
     svc        0               // Call Linux to output the string
...

On the HelloSillicon repo (Mac):

...
_start: mov	X0, #1		// 1 = StdOut
	adr	X1, helloworld 	// string to print
	mov	X2, #13	    	// length of our string
	mov	X16, #4		// Unix write system call
	svc	#0x80		// Call kernel to output the string
...

For starters, why the system call is different: The function number is different (64 and 4) due to each system having different conventions. The table for the Darwin (Apple) system calls can be found at the following link:Darwin System Calls.

This is however one specific version (the most recent at time of writing). Newer versions can be found at here.

Also due to system conventions, the address for storing the function numbers is different.
While on Linux is on X8, in Apple Sillicon is X16.

And for calling the interruption as well, while on Linux is 0, on Apple Sillicon is 0x80.

objdump's `--macho` option makes `-M no-aliases` have no effect?

I cloned the repo, did cd HelloSilicon/Chapter\ 02, ran make then ran these commands:

objdump -d movexamps
objdump -d -M no-aliases movexamps

objdump -d --macho movexamps
objdump -d --macho -M no-aliases movexamps

These 3

objdump -d movexamps
objdump -d --macho movexamps
objdump -d --macho -M no-aliases movexamps

produce the same disassembly:

$ objdump -d movexamps

movexamps:	file format mach-o arm64

Disassembly of section __TEXT,__text:

0000000100003f7c <_start>:
100003f7c: 42 c7 8d d2 	mov	x2, #28218
100003f80: a2 eb a9 f2 	movk	x2, #20317, lsl #16
100003f84: 82 db df f2 	movk	x2, #65244, lsl #32
100003f88: 82 46 e2 f2 	movk	x2, #4660, lsl #48
100003f8c: e1 03 02 2a 	mov	w1, w2
100003f90: 41 f8 7f d3 	lsl	x1, x2, #1
100003f94: 41 fc 41 d3 	lsr	x1, x2, #1
100003f98: 41 fc 41 93 	asr	x1, x2, #1
100003f9c: 41 04 c2 93 	ror	x1, x2, #1
100003fa0: 01 60 b5 d2 	mov	x1, #2868903936
100003fa4: a1 05 80 12 	mov	w1, #-46
100003fa8: 21 00 80 12 	mov	w1, #-2
100003fac: 00 00 80 d2 	mov	x0, #0
100003fb0: 30 00 80 d2 	mov	x16, #1
100003fb4: 01 10 00 d4 	svc	#0x80
$ objdump -d --macho movexamps
movexamps:
(__TEXT,__text) section
_start:
100003f7c:	42 c7 8d d2	mov	x2, #28218
100003f80:	a2 eb a9 f2	movk	x2, #20317, lsl #16
100003f84:	82 db df f2	movk	x2, #65244, lsl #32
100003f88:	82 46 e2 f2	movk	x2, #4660, lsl #48
100003f8c:	e1 03 02 2a	mov	w1, w2
100003f90:	41 f8 7f d3	lsl	x1, x2, #1
100003f94:	41 fc 41 d3	lsr	x1, x2, #1
100003f98:	41 fc 41 93	asr	x1, x2, #1
100003f9c:	41 04 c2 93	ror	x1, x2, #1
100003fa0:	01 60 b5 d2	mov	x1, #2868903936
100003fa4:	a1 05 80 12	mov	w1, #-46
100003fa8:	21 00 80 12	mov	w1, #-2
100003fac:	00 00 80 d2	mov	x0, #0
100003fb0:	30 00 80 d2	mov	x16, #1
100003fb4:	01 10 00 d4	svc	#0x80
$ objdump -d --macho -M no-aliases movexamps
movexamps:
(__TEXT,__text) section
_start:
100003f7c:	42 c7 8d d2	mov	x2, #28218
100003f80:	a2 eb a9 f2	movk	x2, #20317, lsl #16
100003f84:	82 db df f2	movk	x2, #65244, lsl #32
100003f88:	82 46 e2 f2	movk	x2, #4660, lsl #48
100003f8c:	e1 03 02 2a	mov	w1, w2
100003f90:	41 f8 7f d3	lsl	x1, x2, #1
100003f94:	41 fc 41 d3	lsr	x1, x2, #1
100003f98:	41 fc 41 93	asr	x1, x2, #1
100003f9c:	41 04 c2 93	ror	x1, x2, #1
100003fa0:	01 60 b5 d2	mov	x1, #2868903936
100003fa4:	a1 05 80 12	mov	w1, #-46
100003fa8:	21 00 80 12	mov	w1, #-2
100003fac:	00 00 80 d2	mov	x0, #0
100003fb0:	30 00 80 d2	mov	x16, #1
100003fb4:	01 10 00 d4	svc	#0x80
$ 

Only -M no-aliases without --macho changes any instructions

$ objdump -d -M no-aliases movexamps

movexamps:	file format mach-o arm64

Disassembly of section __TEXT,__text:

0000000100003f7c <_start>:
100003f7c: 42 c7 8d d2 	mov	x2, #28218
100003f80: a2 eb a9 f2 	movk	x2, #20317, lsl #16
100003f84: 82 db df f2 	movk	x2, #65244, lsl #32
100003f88: 82 46 e2 f2 	movk	x2, #4660, lsl #48
100003f8c: e1 03 02 2a 	orr	w1, wzr, w2
100003f90: 41 f8 7f d3 	lsl	x1, x2, #1
100003f94: 41 fc 41 d3 	lsr	x1, x2, #1
100003f98: 41 fc 41 93 	asr	x1, x2, #1
100003f9c: 41 04 c2 93 	extr	x1, x2, x2, #1
100003fa0: 01 60 b5 d2 	mov	x1, #2868903936
100003fa4: a1 05 80 12 	mov	w1, #-46
100003fa8: 21 00 80 12 	mov	w1, #-2
100003fac: 00 00 80 d2 	mov	x0, #0
100003fb0: 30 00 80 d2 	mov	x16, #1
100003fb4: 01 10 00 d4 	svc	#0x80

Although it only changes mov w1, w2 -> orr w1, wzr, w2 and ror x1, x2, #1 -> extr x1, x2, x2, #1. I was promised that

// Example of MVN
MOVN W1, #45
// Example of a MOV that the Assembler will change to MVN
MOV W1, #0xFFFFFFFE // (-2)

but it stays the same

100003fa4: a1 05 80 12 	mov	w1, #-46
100003fa8: 21 00 80 12 	mov	w1, #-2

I'm on an M1 Macbook Air, macOS 13.2.1, Xcode version 14.1 (14B47b)

$ as --version
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: arm64-apple-darwin22.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$ objdump --version
Apple LLVM version 14.0.0 (clang-1400.0.29.202)
  Optimized build.
  Default target: arm64-apple-darwin22.3.0
  Host CPU: apple-a12
[...]
$ softwareupdate --list
Software Update Tool

Finding available software
No new software available.

can't use the command `objdump` command with no-aliases option

Hi, I'm really new to this row level world 🙏 and have an issue.

I'm not able to use the command with options, objdump -s -d -M no-aliases filename.o, and it says "Unrecognized disassembler option: no-aliases"

I don't know why, can't I use that option on m1?

thank you, in advance.

Access command line arguments (argv and argc) in AAarch64/Darwin assembly

I'm hoping you can possibly answer this question???

I've been working thru the book and your code changes in order for everything to work on the Machine We Must Not Speak About.

I'm trying to extend one of the Chapter 4 exercises and access the command line argument(s) (argc & argv) within my assembly code. I've searched high and low and just can't find anything that applies (or works).

Could you possibly provide any clues/hints on how to access the command line arguments (argv and argc) within the assembly program.

This very simple program is working fine but if you read the TODO, in the attached code, what I'm trying to do should make sense.

case.txt

Thanks much!

Linking failing after installing Big Sur 11.0.1

Well...I'm back.....this time with a problem (self-inflicted wound?)

I've been moving merrily along through your "Hello Silicon" project...learning tons (and having a blast).
Along the way I've been keeping my "MWMNSA" up-to-date with the OS betas and the Xcode betas.

My problem started this morning when I (foolishly?) installed the publicly available version of Big Sur - 11.0.1

Now all my projects fail to compile/link successfully (actually the failure is during the link phase).
Here is a sample of the error I'm getting

jeffrosengarden@MacMiniDTK Chapter 4 % make case
ld -o case -lSystem -syslibroot xcrun -sdk macosx --show-sdk-path -e _start -arch arm64 case.o
ld: warning: ignoring file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/lib/libSystem.tbd, missing required architecture arm64 in file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/lib/libSystem.tbd
ld: dynamic main executables must link with libSystem.dylib for architecture arm64
make: *** [case] Error 1

I'm not sure what to do here. Any help/advice would be greatly appreciated.

Thanks much!

incorrect `chapter4::printword.s` assembly program

Lines 21–23 are not required or were added by mistake, causing the program to output an incorrect string.
If we remove these three lines, the program works as expected.

Expected:
0x123456789ABCDEFG
Actual:
0x1234FEDC4F5D6E3A

I am very new to assembly; please let me know if I'm wrong somewhere.

openat syscall not working

I tried to adapt the openat call to Darwin, but it returns 9, regardless of the input file (i.e. even when I would be expecting an error).

I have disassembled libsystem_kernel.dylib, and didn't really get wiser:

   15548:       b7 13 40 b9     ldr     w23, [x29, #16]
   1554c:       e3 3e 00 12     and     w3, w23, #0xffff
   15550:       e0 03 15 aa     mov     x0, x21
   15554:       e1 03 14 aa     mov     x1, x20
   15558:       e2 03 13 aa     mov     x2, x19
   1555c:       27 b7 ff 97     bl      ___openat

___openat:      
    31f8:       f0 39 80 d2     mov     x16, #463 
    31fc:       01 10 00 d4     svc     #0x80
    3200:       e3 00 00 54     b.lo    0x321c

I can't really see a big difference in my call:

mov X16, #463 // openat, see bsd/kern/syscalls.master

If anyone has an idea …

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.