giant refactoring of macros

This commit is contained in:
Perry Kivolowitz 2023-01-18 17:24:12 -06:00
parent b153fad576
commit 4d41d9d9cd
5 changed files with 211 additions and 113 deletions

View file

@ -25,15 +25,26 @@ underscores to labels defined by libraries such as the CRT and certain
other symbols like `main`. other symbols like `main`.
So, `main` will not be found by the linker on Apple systems and `_main` So, `main` will not be found by the linker on Apple systems and `_main`
will be an error on Linux systems. There are macros to adjust for this. will be an error on Linux systems.
There are some exceptions such as making use of `FILE * stdin`. On The macros adjust for this.
Linux this would be `stdin`. On Mac OS you would expect `_stdin` but
you'd be wrong... instead Apple uses `___stdinp`. Why? Apple. There are some exceptions to the prepending rule on Apple such as making
use of `FILE * stdin`. On Linux this would be `stdin`. On Mac OS you
would expect `_stdin` but you'd be wrong... instead Apple uses
`___stdinp`. Why? Because Apple.
There is an assumption here that labels created by you do not have
prepended underscores. This can be a problem if this isn't the case. The
solution may be to add a parallel set of macros that either do prepend
or do not. This is an open question which we hope to get user input to
resolve.
## Macros of general use ## Macros of general use
These macros don't converge Apple and Linux. They're just nice to have. First, we describe a number of macros which are the same on both Apple
and Linux. These macros don't converge Apple and Linux. They're just
nice to have.
### PUSH_P, PUSH_R, POP_P and POP_R ### PUSH_P, PUSH_R, POP_P and POP_R
@ -61,97 +72,114 @@ These resolve to: `.cfi_startproc` and `.cfi_endproc` respectively.
Handy more readable macros for determining minima and maxima. Handy more readable macros for determining minima and maxima.
`MIN x0, x1, x2` Signature:
resolves to: `MIN src_a, src_b, dest`
`csel x2, x0, x1, GT` putting the minimum of `x0` and `x1` into `x2`. The smaller of `src_a` and `src_b` is put into `dest`.
Signature:
`MAX src_a, src_b, dest`
The larger of `src_a` and `src_b` is put into `dest`.
## Loads and Stores ## Loads and Stores
### GLD_PTR ### GLD_PTR
Loads the address of a label and then dereferences it where, on Apple Loads the address of a label and then *dereferences* it where, on Apple
the label is in the global space and on Linux is a relatively close the label is in the global space and on Linux is a relatively close
label. label.
Apple version: Signature:
```text ```text
.macro GLD_PTR xreg, label // Dereference a global * GLD_PTR xreg, label
adrp \xreg, _\label@GOTPAGE
ldr \xreg, [\xreg, _\label@GOTPAGEOFF]
.endm
``` ```
Linux version: When this macro finishes, the specified x register contains what
64 bit value lives at the specified label.
### GLD_ADDR
Loads the address of the label into the specified x register. No
dereferencing takes place. On Apple machines, the label will be
found in the global space.
Signature:
```text ```text
.macro GLD_PTR xreg, label // Dereference a global * GLD_ADDR xreg, label
ldr \xreg, =\label
ldr \xreg, [\xreg]
.endm
``` ```
When this macro completes, the address of the label is in the x
register.
### LLD_ADDR ### LLD_ADDR
Load the value of a "local" label. Similar to `GLD_ADDR` this macro loads the address of a "local" label.
Apple version: Signature:
```text ```text
.macro LLD_ADDR xreg, label // Load a local address LLD_ADDR xreg, label
adrp \xreg, \label@PAGE
add \xreg, \xreg, \label@PAGEOFF
.endm
``` ```
Linux version: When this macro completes, the address of the label is in the x
register.
```text ### LLD_DBL
.macro LLD_ADDR xreg, label
ldr \xreg, =\label
.endm
```
## Extern a global label Signature:
`LLD_DBL xreg, dreg, label`
When this macro completes, a double that lives at the specified local
label will sit in the specified double register.
Note: No underscore is prepended.
See [this sample program](./double.S) for an example.
### LLD_FLT
Signature:
`LLD_FLT xreg, sreg, label`
When this macro completes, a float that lives at the specified
local label will sit in the specified single precision
register.
Note: No underscore is prepended.
See [this sample program](./float.S) for an example.
## Mark a label as global
Makes a label available externally. Makes a label available externally.
Apple version: Signature:
```text `GLABEL label`
.macro GLABEL label
.global _\label
.endm
```
Linux version: An underscore is prepended.
```text ## Calling CRT functions
.macro GLABEL label
.global \label
.endm
```
For example:
```text
GLABEL main
```
## Calling functions
If you create your own function without an underscore, just call it as If you create your own function without an underscore, just call it as
usual. usual.
If you need to call a function such as those found in the C runtime If you need to call a function such as those found in the C runtime
library, use in this way: library, use this macro in this way:
```text `CRT strlen`
CRT strlen
``` An underscore is prepended.
## Declaring `main()` ## Declaring `main()`
Put `MAIN` on a line by itself. Notice there is no colon. Put `MAIN` on a line by itself. Notice there is no colon.
An underscore is prepended.

Binary file not shown.

View file

@ -1,77 +1,87 @@
// Macros to permit the "same" assembly language to build on ARM64 /* Macros to permit the "same" assembly language to build on ARM64
// Linux systems as well as Apple Silicon systems. Linux systems as well as Apple Silicon systems.
//
// Perry Kivolowitz
// A Gentle Introduction to Assembly Language
See the fuller documentation at:
https://github.com/pkivolowitz/asm_book/blob/main/macros/README.md
Perry Kivolowitz
A Gentle Introduction to Assembly Language
*/
.macro GLD_PTR xreg, label
#if defined(__APPLE__) #if defined(__APPLE__)
// Apple makes a distinction between loading something close by
// versus something global. Note the use of GOTPAGE rather then
// PAGE.
//
// Note: this macro dereferences the label getting what is at
// the label's address.
.macro GLD_PTR xreg, label // Dereference a global *
adrp \xreg, _\label@GOTPAGE adrp \xreg, _\label@GOTPAGE
ldr \xreg, [\xreg, _\label@GOTPAGEOFF] ldr \xreg, [\xreg, _\label@GOTPAGEOFF]
#else
ldr \xreg, =\label
ldr \xreg, [\xreg]
#endif
.endm .endm
.macro GLD_ADDR xreg, label // Get a global address .macro GLD_ADDR xreg, label // Get a global address
#if defined(__APPLE__)
adrp \xreg, _\label@GOTPAGE adrp \xreg, _\label@GOTPAGE
add \xreg, \xreg, _\label@GOTPAGEOFF add \xreg, \xreg, _\label@GOTPAGEOFF
.endm #else
// This macro loads the address of a nearby label.
.macro LLD_ADDR xreg, label // Load a local address
adrp \xreg, \label@PAGE
add \xreg, \xreg, \label@PAGEOFF
.endm
.macro GLABEL label
.global _\label
.endm
.macro MAIN
_main:
.endm
.macro CRT label
bl _\label
.endm
#else // LINUX
.macro GLABEL label
.global \label
.endm
.macro MAIN
main:
.endm
.macro CRT label
bl \label
.endm
// This macro treats label as a pointer and dereferences it.
// That is, it puts into the xreg what is found at the address
// of the label.
.macro GLD_PTR xreg, label // Dereference a global *
ldr \xreg, =\label ldr \xreg, =\label
ldr \xreg, [\xreg] #endif
.endm .endm
// This macro loads the address of a nearby label.
.macro LLD_ADDR xreg, label .macro LLD_ADDR xreg, label
#if defined(__APPLE__)
adrp \xreg, \label@PAGE
add \xreg, \xreg, \label@PAGEOFF
#else
ldr \xreg, =\label ldr \xreg, =\label
#endif
.endm .endm
.macro LLD_DBL xreg, dreg, label
#if defined(__APPLE__)
adrp \xreg, \label@PAGE
add \xreg, \xreg, \label@PAGEOFF
ldur \dreg, [\xreg]
// fmov \dreg, \xreg
#else
ldr \xreg, =\label
ldur \dreg, [\xreg]
#endif #endif
.endm
.macro LLD_FLT xreg, sreg, label
#if defined(__APPLE__)
adrp \xreg, \label@PAGE
add \xreg, \xreg, \label@PAGEOFF
ldur \sreg, [\xreg]
#else
ldr \xreg, =\label
ldur \sreg, [\xreg]
#endif
.endm
.macro GLABEL label
#if defined(__APPLE__)
.global _\label
#else
.global \label
#endif
.endm
.macro MAIN
#if defined(__APPLE__)
_main:
#else
main:
#endif
.endm
.macro CRT label
#if defined(__APPLE__)
bl _\label
#else
bl \label
#endif
.endm
.macro START_PROC // after starting label .macro START_PROC // after starting label
.cfi_startproc .cfi_startproc

29
macros/double.S Normal file
View file

@ -0,0 +1,29 @@
#include "apple-linux-convergence.S"
.text
.align 2
GLABEL main
MAIN
START_PROC
PUSH_P x29, x30
mov x29, sp
LLD_ADDR x0, fmt
LLD_DBL x1, d0, dbl
#if defined(__APPLE__)
PUSH_R d0
CRT printf
add sp, sp, 16
#else
CRT printf
#endif
POP_P x29, x30
mov w0, wzr
ret
END_PROC
dbl: .double -0.55
flt: .float 0.125
fmt: .asciz "%f\n"
.end

31
macros/float.S Normal file
View file

@ -0,0 +1,31 @@
#include "apple-linux-convergence.S"
.text
.align 2
GLABEL main
MAIN
START_PROC
PUSH_P x29, x30
mov x29, sp
LLD_ADDR x0, fmt
LLD_FLT x1, s0, flt
#if defined(__APPLE__)
fcvt d0, s0
fmov x1, d0
PUSH_R x1
CRT printf
add sp, sp, 16
#else
fcvt d0, s0
CRT printf
#endif
POP_P x29, x30
mov w0, wzr
ret
END_PROC
flt: .float 0.125
fmt: .asciz "%f\n"
.end