typo found by Katie

This commit is contained in:
Perry Kivolowitz 2023-02-23 14:05:29 -06:00
parent 8382853043
commit e7a99b1072
3 changed files with 104 additions and 63 deletions

View file

@ -49,6 +49,7 @@
"Rypo",
"SIZD",
"SIZF",
"amining",
"bitfields",
"dless",
"dmore",
@ -56,12 +57,14 @@
"fcvtps",
"fcvtta",
"foov",
"iant",
"ndless",
"ndmore",
"nvless",
"nvmore",
"onditionally",
"onsole",
"rint",
"rotypo",
"rwtypo",
"slen",

View file

@ -2,7 +2,9 @@
## Overview
In each of the various sets of registers, each register can be referred to by different synonyms which determine how wide the register operation will be.
In each of the various sets of registers, each register can be referred
to by different synonyms which determine how wide the register operation
will be.
## General Purpose Registers
@ -22,7 +24,13 @@ In each of the various sets of registers, each register can be referred to by di
ldrb w0, [sp] // load 1 byte from address specified by sp
```
The address from which a load is taking must match the alignment of what is being loaded.
The address from which a load is taking *should* match the alignment of
what is being loaded. That is, a long *should* be found only at
addresses which are a multiple of 8 (the size of a long).
**When misaligned accesses to RAM are made, the processor must slow down
and access each byte individually. This is a big performance hit.
Properly aligned access is critical to performance.**
### `str` (and `stp`)
@ -33,30 +41,30 @@ The address from which a load is taking must match the alignment of what is bein
strb w0, [sp] // store 1 byte to address specified by sp
```
The address to which a store is made must match the alignment of what is being stored.
See above for comments about misaligned memory access.
### Example
Let's look at this program:
```asm
.global main // 1
.text // 2
.align 2 // 3
// 4
main: mov x0, xzr // 5
ldr x1, =ram // 6
strb w0, [x1] // 7
strh w0, [x1] // 8
str w0, [x1] // 9
str x0, [x1] // 10
ret // 11
// 12
.data // 13
ram: .quad 0xFFFFFFFFFFFFFFFF // 14
// 15
.end // 16
// 17
.global main // 1
.text // 2
.align 2 // 3
// 4
main: mov x0, xzr // 5
ldr x1, =ram // 6
strb w0, [x1] // 7
strh w0, [x1] // 8
str w0, [x1] // 9
str x0, [x1] // 10
ret // 11
// 12
.data // 13
ram: .quad 0xFFFFFFFFFFFFFFFF // 14
// 15
.end // 16
// 17
```
`Line 14` puts an identifiable pattern into 8 bytes of RAM and gives them the symbol `ram`.
@ -82,14 +90,18 @@ Breakpoint 1, main () at align.s:5 // 6
5 main: mov x0, xzr // 7
```
We launched the program and `gdb` stops its execution upon reaching the breakpoint.
We launched the program and `gdb` stops its execution upon reaching the
breakpoint.
```text
(gdb) p/x $x0 // 8
$1 = 0x1 // 9
```
Before putting zero into `x0`, let's see what it currently holds... the value 1. Recall this is `argc`. The `p` command means `print` and is used to print the values in registers. The modifier `/x` says to print in hexadecimal.
Before putting zero into `x0`, let's see what it currently holds... the
value 1. Recall this is `argc`. The `p` command means `print` and is
used to print the values in registers. The modifier `/x` says to print
in hexadecimal.
```text
(gdb) n // 10
@ -105,85 +117,98 @@ After putting zero into `x0`, we confirm its contents.
$3 = 0xfffffffff028 // 15
```
Prior to loading the address of 8 bytes found with the label `ram`, we print out the value already sitting in `x1`. The address it contains will be the address of the `C`-string containing the name of the program being run.
Prior to loading the address of 8 bytes found with the label `ram`, we
print out the value already sitting in `x1`. The address it contains
will be the address of the `C`-string containing the name of the program
being run. Notice this value is 6-bytes long and not 8 as we might have
expected. Why? The answer relates to the size of the virtual address
each program is allowed. A full 64-bit virtual address space would make
certain OS data structures too large for efficiency.
```text
(gdb) n // 16
7 strb w0, [x1] // 17
(gdb) p/x $x1 // 18
$4 = 0xaaaaaaab1010 // 19
(gdb) n // 16
7 strb w0, [x1] // 17
(gdb) p/x $x1 // 18
$4 = 0xaaaaaaab1010 // 19
```
After loading the address of `ram` into `x1`, we confirm its contents.
```text
(gdb) p/x &ram // 20
$5 = 0xaaaaaaab1010 // 21
(gdb) p/x &ram // 20
$5 = 0xaaaaaaab1010 // 21
```
Just for kicks, we confirm that the previous instruction really did get the address correctly.
Just for kicks, we confirm that the previous instruction really did get
the address correctly.
```text
(gdb) x/x &ram // 22
0xaaaaaaab1010: 0xffffffff // 23
(gdb) x/x &ram // 22
0xaaaaaaab1010: 0xffffffff // 23
```
We shift from `p`rint to e`x`amine to reach into memory and see what is found at `ram`.
We shift from `p`rint to e`x`amine to reach into memory and see what is
found at `ram`.
```text
(gdb) x/gx &ram // 24
0xaaaaaaab1010: 0xffffffffffffffff // 25
(gdb) x/gx &ram // 24
0xaaaaaaab1010: 0xffffffffffffffff // 25
```
Adding the `g` (for `g`iant) we can see all 8 bytes.
```text
(gdb) n // 26
8 strh w0, [x1] // 27
(gdb) x/gx &ram // 28
0xaaaaaaab1010: 0xffffffffffffff00 // 29
(gdb) n // 26
8 strh w0, [x1] // 27
(gdb) x/gx &ram // 28
0xaaaaaaab1010: 0xffffffffffffff00 // 29
```
We just did a `strb` and looking at memory, we see one byte's worth of zeros.
*Note: this brings up an interesting question... which byte is actually sitting at the address of `ram`? We will have to look into this more later.*
*Note: this brings up an interesting question... which byte is actually
sitting at the address of `ram`? We will have to look into this more
later.*
```text
(gdb) n // 30
9 str w0, [x1] // 31
(gdb) x/gx &ram // 32
0xaaaaaaab1010: 0xffffffffffff0000 // 33
(gdb) n // 30
9 str w0, [x1] // 31
(gdb) x/gx &ram // 32
0xaaaaaaab1010: 0xffffffffffff0000 // 33
```
After storing a `short`.
```text
(gdb) n // 34
10 str x0, [x1] // 35
(gdb) x/gx &ram // 36
0xaaaaaaab1010: 0xffffffff00000000 // 37
(gdb) n // 34
10 str x0, [x1] // 35
(gdb) x/gx &ram // 36
0xaaaaaaab1010: 0xffffffff00000000 // 37
```
After storing an `int`.
```text
(gdb) n // 38
11 ret // 39
(gdb) x/gx &ram // 40
0xaaaaaaab1010: 0x0000000000000000 // 41
(gdb) quit // 42
(gdb) n // 38
11 ret // 39
(gdb) x/gx &ram // 40
0xaaaaaaab1010: 0x0000000000000000 // 41
(gdb) quit // 42
```
And finally, after storing a `long`.
Let's circle back to the question asked above: Which byte is actually at the address `ram`? When we examined the `long` just after putting in one byte of zero, we saw this:
Let's circle back to the question asked above: Which byte is actually at
the address `ram`? When we examined the `long` just after putting in one
byte of zero, we saw this:
```text
(gdb) x/gx &ram // 28
0xaaaaaaab1010: 0xffffffffffffff00 // 29
```
Notice the zeros come at the end. Keep in mind, these bytes are printed as a `long`.
Notice the zeros come at the end. Keep in mind, these bytes are printed
as a `long`.
But what if we look at these 8 bytes individually?
@ -204,7 +229,8 @@ The following image is from [here](https://medium.com/worldsensing-techblog/big-
### Little Endian in More Detail
Given this program (not intended for meaningful execution... just e`x`aminging memory):
Given this program (not intended for meaningful execution... just
e`x`amining memory):
```asm
.global main // 1
@ -219,34 +245,46 @@ ram: .quad 0xAABBCCDDEEFF0011 // 9
.end // 10
```
let's take a look at the memory at location `ram` in two ways. Once interpreted as a `long`:
let's take a look at the memory at location `ram` in two ways. Once
interpreted as a `long`:
```text
(gdb) x/gx &ram
0x11010: 0xaabbccddeeff0011
```
and then intrepreted as 8 bytes appearing in the order of lowest address to highest:
and then interpreted as 8 bytes appearing in the order of lowest address
to highest:
```text
(gdb) x/8bx &ram
0x11010: 0x11 0x00 0xff 0xee 0xdd 0xcc 0xbb 0xaa
```
Compare the order of the bytes. They are least significant to most significant. Specifically:
Compare the order of the bytes. They are least significant to most
significant. Specifically:
* within a `long` the least significant `int` comes first
* within an `int`, the least significant `short` comes first
* within a `short` the least significant byte comes first
Endiannes isn't an issue unless you're exchanging data with a computer that has a different endedness and then only if the data being transferred is longer in native width than 1 byte. Text, expressed in single bytes, is immune from endedness issues - text is an array of bytes and is the same on all platforms.
Endiannes isn't an issue unless you're exchanging data with a computer
that has a different endedness and then only if the data being
transferred is longer in native width than 1 byte. Text, expressed in
single bytes, is immune from endedness issues - text is an array of
bytes and is the same on all platforms.
### What Happens to the Rest of a Register When Only a Portion is Affected?
Whenever a narrower portion of a register is written to, the remainder of the registe is zero'd out. That is: `strb` overwrites the least significant byte of an `x` register and zeros out the upper 7 bytes.
Whenever a narrower portion of a register is written to, the remainder
of the register is zero'd out. That is: `ldrb` overwrites the least
significant byte of an `x` register and zeros out the upper 7 bytes.
*There are dedicated instructions for manipulating bits in the middle of registers*.
*There are dedicated instructions for manipulating bits in the middle of
registers*.
### Casting Between `int` Type
Casting between integer types is in some cases accomplished by `anding` with `255` and `65535` (for `char` and `short`). Otherwise, see the previous section (What Happens to the Rest of a Register...).
Casting between integer types is in some cases accomplished by `anding`
with `255` and `65535` (for `char` and `short`). Otherwise, see the
previous section (What Happens to the Rest of a Register...).

Binary file not shown.