mirror of
https://github.com/pkivolowitz/asm_book.git
synced 2026-06-23 23:46:48 +08:00
typo found by Katie
This commit is contained in:
parent
8382853043
commit
e7a99b1072
3 changed files with 104 additions and 63 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -49,6 +49,7 @@
|
||||||
"Rypo",
|
"Rypo",
|
||||||
"SIZD",
|
"SIZD",
|
||||||
"SIZF",
|
"SIZF",
|
||||||
|
"amining",
|
||||||
"bitfields",
|
"bitfields",
|
||||||
"dless",
|
"dless",
|
||||||
"dmore",
|
"dmore",
|
||||||
|
|
@ -56,12 +57,14 @@
|
||||||
"fcvtps",
|
"fcvtps",
|
||||||
"fcvtta",
|
"fcvtta",
|
||||||
"foov",
|
"foov",
|
||||||
|
"iant",
|
||||||
"ndless",
|
"ndless",
|
||||||
"ndmore",
|
"ndmore",
|
||||||
"nvless",
|
"nvless",
|
||||||
"nvmore",
|
"nvmore",
|
||||||
"onditionally",
|
"onditionally",
|
||||||
"onsole",
|
"onsole",
|
||||||
|
"rint",
|
||||||
"rotypo",
|
"rotypo",
|
||||||
"rwtypo",
|
"rwtypo",
|
||||||
"slen",
|
"slen",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
## Overview
|
## 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
|
## 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
|
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`)
|
### `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
|
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
|
### Example
|
||||||
|
|
||||||
Let's look at this program:
|
Let's look at this program:
|
||||||
|
|
||||||
```asm
|
```asm
|
||||||
.global main // 1
|
.global main // 1
|
||||||
.text // 2
|
.text // 2
|
||||||
.align 2 // 3
|
.align 2 // 3
|
||||||
// 4
|
// 4
|
||||||
main: mov x0, xzr // 5
|
main: mov x0, xzr // 5
|
||||||
ldr x1, =ram // 6
|
ldr x1, =ram // 6
|
||||||
strb w0, [x1] // 7
|
strb w0, [x1] // 7
|
||||||
strh w0, [x1] // 8
|
strh w0, [x1] // 8
|
||||||
str w0, [x1] // 9
|
str w0, [x1] // 9
|
||||||
str x0, [x1] // 10
|
str x0, [x1] // 10
|
||||||
ret // 11
|
ret // 11
|
||||||
// 12
|
// 12
|
||||||
.data // 13
|
.data // 13
|
||||||
ram: .quad 0xFFFFFFFFFFFFFFFF // 14
|
ram: .quad 0xFFFFFFFFFFFFFFFF // 14
|
||||||
// 15
|
// 15
|
||||||
.end // 16
|
.end // 16
|
||||||
// 17
|
// 17
|
||||||
```
|
```
|
||||||
|
|
||||||
`Line 14` puts an identifiable pattern into 8 bytes of RAM and gives them the symbol `ram`.
|
`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
|
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
|
```text
|
||||||
(gdb) p/x $x0 // 8
|
(gdb) p/x $x0 // 8
|
||||||
$1 = 0x1 // 9
|
$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
|
```text
|
||||||
(gdb) n // 10
|
(gdb) n // 10
|
||||||
|
|
@ -105,85 +117,98 @@ After putting zero into `x0`, we confirm its contents.
|
||||||
$3 = 0xfffffffff028 // 15
|
$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
|
```text
|
||||||
(gdb) n // 16
|
(gdb) n // 16
|
||||||
7 strb w0, [x1] // 17
|
7 strb w0, [x1] // 17
|
||||||
(gdb) p/x $x1 // 18
|
(gdb) p/x $x1 // 18
|
||||||
$4 = 0xaaaaaaab1010 // 19
|
$4 = 0xaaaaaaab1010 // 19
|
||||||
```
|
```
|
||||||
|
|
||||||
After loading the address of `ram` into `x1`, we confirm its contents.
|
After loading the address of `ram` into `x1`, we confirm its contents.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
(gdb) p/x &ram // 20
|
(gdb) p/x &ram // 20
|
||||||
$5 = 0xaaaaaaab1010 // 21
|
$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
|
```text
|
||||||
(gdb) x/x &ram // 22
|
(gdb) x/x &ram // 22
|
||||||
0xaaaaaaab1010: 0xffffffff // 23
|
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
|
```text
|
||||||
(gdb) x/gx &ram // 24
|
(gdb) x/gx &ram // 24
|
||||||
0xaaaaaaab1010: 0xffffffffffffffff // 25
|
0xaaaaaaab1010: 0xffffffffffffffff // 25
|
||||||
```
|
```
|
||||||
|
|
||||||
Adding the `g` (for `g`iant) we can see all 8 bytes.
|
Adding the `g` (for `g`iant) we can see all 8 bytes.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
(gdb) n // 26
|
(gdb) n // 26
|
||||||
8 strh w0, [x1] // 27
|
8 strh w0, [x1] // 27
|
||||||
(gdb) x/gx &ram // 28
|
(gdb) x/gx &ram // 28
|
||||||
0xaaaaaaab1010: 0xffffffffffffff00 // 29
|
0xaaaaaaab1010: 0xffffffffffffff00 // 29
|
||||||
```
|
```
|
||||||
|
|
||||||
We just did a `strb` and looking at memory, we see one byte's worth of zeros.
|
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
|
```text
|
||||||
(gdb) n // 30
|
(gdb) n // 30
|
||||||
9 str w0, [x1] // 31
|
9 str w0, [x1] // 31
|
||||||
(gdb) x/gx &ram // 32
|
(gdb) x/gx &ram // 32
|
||||||
0xaaaaaaab1010: 0xffffffffffff0000 // 33
|
0xaaaaaaab1010: 0xffffffffffff0000 // 33
|
||||||
```
|
```
|
||||||
|
|
||||||
After storing a `short`.
|
After storing a `short`.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
(gdb) n // 34
|
(gdb) n // 34
|
||||||
10 str x0, [x1] // 35
|
10 str x0, [x1] // 35
|
||||||
(gdb) x/gx &ram // 36
|
(gdb) x/gx &ram // 36
|
||||||
0xaaaaaaab1010: 0xffffffff00000000 // 37
|
0xaaaaaaab1010: 0xffffffff00000000 // 37
|
||||||
```
|
```
|
||||||
|
|
||||||
After storing an `int`.
|
After storing an `int`.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
(gdb) n // 38
|
(gdb) n // 38
|
||||||
11 ret // 39
|
11 ret // 39
|
||||||
(gdb) x/gx &ram // 40
|
(gdb) x/gx &ram // 40
|
||||||
0xaaaaaaab1010: 0x0000000000000000 // 41
|
0xaaaaaaab1010: 0x0000000000000000 // 41
|
||||||
(gdb) quit // 42
|
(gdb) quit // 42
|
||||||
```
|
```
|
||||||
|
|
||||||
And finally, after storing a `long`.
|
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
|
```text
|
||||||
(gdb) x/gx &ram // 28
|
(gdb) x/gx &ram // 28
|
||||||
0xaaaaaaab1010: 0xffffffffffffff00 // 29
|
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?
|
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
|
### 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
|
```asm
|
||||||
.global main // 1
|
.global main // 1
|
||||||
|
|
@ -219,34 +245,46 @@ ram: .quad 0xAABBCCDDEEFF0011 // 9
|
||||||
.end // 10
|
.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
|
```text
|
||||||
(gdb) x/gx &ram
|
(gdb) x/gx &ram
|
||||||
0x11010: 0xaabbccddeeff0011
|
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
|
```text
|
||||||
(gdb) x/8bx &ram
|
(gdb) x/8bx &ram
|
||||||
0x11010: 0x11 0x00 0xff 0xee 0xdd 0xcc 0xbb 0xaa
|
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 a `long` the least significant `int` comes first
|
||||||
* within an `int`, the least significant `short` comes first
|
* within an `int`, the least significant `short` comes first
|
||||||
* within a `short` the least significant byte 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?
|
### 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 `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.
Loading…
Reference in a new issue