updated apple silicon chapter to reflect changes in the macros

This commit is contained in:
Perry Kivolowitz 2023-01-17 12:17:50 -06:00
parent f584354075
commit 4ec5ca1e45

View file

@ -25,7 +25,7 @@ macro as an early form of C++ templated function (kinda but not really).
Here's an example of an assembly language macro: Here's an example of an assembly language macro:
```text ```text
.macro LD_ADDR xreg, label .macro LLD_ADDR xreg, label
adrp \xreg, \label@PAGE adrp \xreg, \label@PAGE
add \xreg, \xreg, \label@PAGEOFF add \xreg, \xreg, \label@PAGEOFF
.endm .endm
@ -34,7 +34,7 @@ Here's an example of an assembly language macro:
Here's how it might be used: Here's how it might be used:
```text ```text
LD_ADDR x0, fmt LLD_ADDR x0, fmt
``` ```
This gets expanded to: This gets expanded to:
@ -62,6 +62,7 @@ would this be possible since we've seen that addresses are (often) six
bytes long and our instructions are always 4 bytes long? As we describe bytes long and our instructions are always 4 bytes long? As we describe
elsewhere, the above `ldr` instance is actually turned into instructions elsewhere, the above `ldr` instance is actually turned into instructions
to load an address relative to the address of the current instruction. to load an address relative to the address of the current instruction.
As long as the data we want is relatively close to the `ldr`, this works As long as the data we want is relatively close to the `ldr`, this works
out to a difference in addresses that is small (and so, can be fit into out to a difference in addresses that is small (and so, can be fit into
a 4 byte instruction). a 4 byte instruction).
@ -93,6 +94,11 @@ address into `x0` forming a complete address.
In this way, labels can be further away from the current instruction In this way, labels can be further away from the current instruction
than the Linux way. than the Linux way.
Apple does something similar with global variables, perhaps defined in
C or C++ files. Instead of `PAGE` and `PAGEOFF` they use global
versions. The macro `GLD_ADDR` is used in this case rather than
`LLD_ADDR` which works with "locally" defined addresses.
## How does this help bridge Apple and Linux? ## How does this help bridge Apple and Linux?
[Here](./macros.S) is an assembly language file containing the macros [Here](./macros.S) is an assembly language file containing the macros
@ -102,7 +108,7 @@ closer together.
Notice it has: Notice it has:
```text ```text
.macro LD_ADDR xreg, label .macro LLD_ADDR xreg, label
adrp \xreg, \label@PAGE adrp \xreg, \label@PAGE
add \xreg, \xreg, \label@PAGEOFF add \xreg, \xreg, \label@PAGEOFF
.endm .endm
@ -111,7 +117,7 @@ Notice it has:
but also: but also:
```text ```text
.macro LD_ADDR xreg, label .macro LLD_ADDR xreg, label
ldr \xreg, =\label ldr \xreg, =\label
.endm .endm
``` ```
@ -134,17 +140,17 @@ provided by the standard C pre-processor. I.e.:
C pre-processor. `clang` on Linux will not by default but can if you C pre-processor. `clang` on Linux will not by default but can if you
specify `-x assembler-with-cpp`. specify `-x assembler-with-cpp`.
gcc on Mac OS can be based on clang so on Mac OS it inherits `clang`'s `gcc` on Mac OS can be based on `clang` so on Mac OS it inherits
behavior. gcc on Linux does not run assembly language files through `clang`'s behavior. `gcc` on Linux does not run assembly language files
the C pre-processor *if the asm file ends in .s but WILL if the file through the C pre-processor *if the asm file ends in .s but WILL if the
ends in .S* It took the author a long time to find this... file ends in .S*
## Differences between Apple and Linux ## Differences between Apple and Linux
### Loading label addresses ### Loading label addresses
This was described above. If you use `LD_ADDR` the macros will adapt for This was described above. If you use `LLD_ADDR` the macros will adapt
you. for you.
### Function labels ### Function labels
@ -181,6 +187,8 @@ use
and the macros will adapt. and the macros will adapt.
You can find documentation on the macros [here](../../macros/README.md).
## Variadic functions ## Variadic functions
Functions like `printf()` are variadic. This means the function can take Functions like `printf()` are variadic. This means the function can take
@ -203,17 +211,24 @@ use the stack.
Apple will put the first parameter in the zero register and then shifts Apple will put the first parameter in the zero register and then shifts
immediately to putting all other parameters onto the stack. immediately to putting all other parameters onto the stack.
Here is how we overcame this difference: We overcome this difference by detecting which environment we are
building in using `#if` after having first set up for the Linux version.
By setting up for the Linux version, the Apple version involves just
pushing registers onto the stack.
Remember that to print a float or double, they must be copied to `x`
registers.
An example:
```text ```text
// setting up a two value printf as usual LLD_ADDR x0, fmt // loads the address of fmt
LD_ADDR x0, fmt // loads the address of fmt LLD_PTR x1, ptr // loads **ptr
LD_ADDR x1, ptr // loads **ptr ldr x1, [x1] // turns **ptr into *ptr
ldr x1, [x1] // dereferences **ptr to make *ptr ldr x2, [x1] // dereferences *ptr to get value
ldr x2, [x1] // dereferences *ptr to get value
# if defined(__APPLE__) # if defined(__APPLE__)
// if apple, push the second and third argument to stack // if apple, push the second and third argument to stack
stp x1, x2, [sp, -16]! PUSH_P x1, x2
CRT printf CRT printf
add sp, sp, 16 add sp, sp, 16
# else # else
@ -237,6 +252,8 @@ To be Apple compatible, in addition to backing up `x30` also back up
`mov x29, sp` `mov x29, sp`
We will be converting all sample code to do this over time.
### More? ### More?
As we discover more differences, they will be described here. As we discover more differences, they will be described here.
@ -248,6 +265,10 @@ code. These work the same on both Apple Silicon and Linux. If you want
these, put `START_PROC` after the label introducing a function. Then, these, put `START_PROC` after the label introducing a function. Then,
put `END_PROC` after the last statement of the function. put `END_PROC` after the last statement of the function.
This helps the debuggers understand where a function begins and ends.
We will transition all sample code to use this over time.
## A useful link ## A useful link
[Here](https://gcc.gnu.org/onlinedocs/gcc/Invoking-GCC.html) is an [Here](https://gcc.gnu.org/onlinedocs/gcc/Invoking-GCC.html) is an