mirror of
https://github.com/pkivolowitz/asm_book.git
synced 2026-06-23 02:46:48 +08:00
added discussion of VA size and added figures for pictures
This commit is contained in:
parent
46ec454c70
commit
8601121e6f
1 changed files with 106 additions and 78 deletions
|
|
@ -2,34 +2,34 @@
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
In this chapter we examine the difference between loading the address of (a pointer to)
|
In this chapter we examine the difference between loading the address of
|
||||||
a data label versus loading the data at the label. Both use the `ldr` instruction
|
(a pointer to) a data label versus loading the data at the label. Both
|
||||||
however, the assembler actually does some trickery behind the scenes to accomplish
|
use the `ldr` instruction however, the assembler actually does some
|
||||||
the loads.
|
trickery behind the scenes to accomplish the loads.
|
||||||
|
|
||||||
## Length of Instructions
|
## Length of Instructions
|
||||||
|
|
||||||
All AARCH64 instructions are 4 bytes in width.
|
**All** AARCH64 instructions are 4 bytes in width.
|
||||||
|
|
||||||
## Length of Pointers
|
## Length of Pointers
|
||||||
|
|
||||||
All AARCH64 pointers are 8 bytes in width.
|
**All** AARCH64 pointers are 8 bytes in width.
|
||||||
|
|
||||||
## How to Specify an Address Too Big to Fit in an Instruction?
|
## How to Specify an Address Too Big to Fit in an Instruction?
|
||||||
|
|
||||||
The title of this section sets the table for the need for trickery. All labels
|
The title of this section sets the table for the need for trickery. All
|
||||||
refer to addresses. Addresses are 8 bytes in width but all instructions are 4
|
labels refer to addresses. Addresses are 8 bytes in width but all
|
||||||
bytes in width. Clearly, we cannot fit the full address of a label in an
|
instructions are 4 bytes in width. Clearly, we cannot fit the full
|
||||||
instruction.
|
address of a label in an instruction.
|
||||||
|
|
||||||
Some ISA's (not ARM) have variable length instructions. The instruction may be
|
Some ISAs (not ARM) have variable length instructions. The instruction
|
||||||
four bytes wide but it tells the CPU that the next eight bytes are an operand
|
may be four bytes wide but it tells the CPU that the next eight bytes
|
||||||
of the instruction. Thus the true instruction width is 12 bytes. This is not
|
are an operand of the instruction. Thus the true instruction width is 12
|
||||||
true of the ARM ISA.
|
bytes. This is not true of the ARM ISA.
|
||||||
|
|
||||||
**All instructions are 4 bytes wide. All of them.**
|
**All instructions are 4 bytes wide. All of them.**
|
||||||
|
|
||||||
## "`ldr` xregister, =label" is a Pseudo Instruction
|
## "`ldr` x_register, =label" is a Pseudo Instruction
|
||||||
|
|
||||||
When you assemble an instruction looking like:
|
When you assemble an instruction looking like:
|
||||||
|
|
||||||
|
|
@ -37,21 +37,22 @@ When you assemble an instruction looking like:
|
||||||
ldr x1, =label
|
ldr x1, =label
|
||||||
```
|
```
|
||||||
|
|
||||||
the assembler puts the address of the label into a special region of memory
|
the assembler puts the address of the label into a special region of
|
||||||
fancily called a "literal pool." What matters is this region of memory is placed
|
memory fancily called a "literal pool." What matters is this region of
|
||||||
immediately after (therefore nearby) your code.
|
memory is placed immediately after (therefore nearby) your code.
|
||||||
|
|
||||||
Then, the assembler computes the difference between the address of the current
|
Then, the assembler computes the difference between the address of the
|
||||||
instruction (the `ldr` itself) and the address of the data in the literal pool
|
current instruction (the `ldr` itself) and the address of the data in
|
||||||
made from the labeled data.
|
the literal pool made from the labeled data.
|
||||||
|
|
||||||
The assembler generates a different `ldr` instruction which uses the difference
|
The assembler generates a different `ldr` instruction which uses the
|
||||||
(or offset) of the data relative to the program counter (`pc`). The `pc` is
|
difference (or offset) of the data relative to the program counter
|
||||||
non-other the address of the current instruction.
|
(`pc`). The `pc` is non-other the address of the current instruction.
|
||||||
|
|
||||||
Because the literal pool for your code is located nearby your code, the offset
|
Because the literal pool for your code is located nearby your code, the
|
||||||
from the current instruction to the data in the pool is a relatively **small**
|
offset from the current instruction to the data in the pool is a
|
||||||
number. Small enough, to fit inside a four byte `ldr` instruction.
|
relatively **small** number. Small enough, to fit inside a four byte
|
||||||
|
`ldr` instruction.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
ldr x1, [pc, offset to data in literal pool]
|
ldr x1, [pc, offset to data in literal pool]
|
||||||
|
|
@ -66,7 +67,7 @@ between:
|
||||||
ldr x1, =q
|
ldr x1, =q
|
||||||
```
|
```
|
||||||
|
|
||||||
and
|
and
|
||||||
|
|
||||||
```text
|
```text
|
||||||
ldr x1, q
|
ldr x1, q
|
||||||
|
|
@ -112,32 +113,32 @@ above source code will include:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
0000000000007a0 <main>:
|
0000000000007a0 <main>:
|
||||||
7a0: f81f0ffe str x30, [sp, #-16]!
|
7a0: f81f0ffe str x30, [sp, #-16]!
|
||||||
7a4: 58000160 ldr x0, 7d0 <main+0x30>
|
7a4: 58000160 ldr x0, 7d0 <main+0x30>
|
||||||
7a8: 58000181 ldr x1, 7d8 <main+0x38>
|
7a8: 58000181 ldr x1, 7d8 <main+0x38>
|
||||||
7ac: f9400022 ldr x2, [x1]
|
7ac: f9400022 ldr x2, [x1]
|
||||||
7b0: 97ffffb4 bl 680 <printf@plt>
|
7b0: 97ffffb4 bl 680 <printf@plt>
|
||||||
7b4: 580000e0 ldr x0, 7d0 <main+0x30>
|
7b4: 580000e0 ldr x0, 7d0 <main+0x30>
|
||||||
7b8: 580842c1 ldr x1, 11010 <q>
|
7b8: 580842c1 ldr x1, 11010 <q>
|
||||||
7bc: f9400022 ldr x2, [x1]
|
7bc: f9400022 ldr x2, [x1]
|
||||||
7c0: 97ffffb0 bl 680 <printf@plt>
|
7c0: 97ffffb0 bl 680 <printf@plt>
|
||||||
7c4: f84107fe ldr x30, [sp], #16
|
7c4: f84107fe ldr x30, [sp], #16
|
||||||
7c8: 2a1f03e0 mov w0, wzr
|
7c8: 2a1f03e0 mov w0, wzr
|
||||||
7cc: d65f03c0 ret
|
7cc: d65f03c0 ret
|
||||||
```
|
```
|
||||||
|
|
||||||
and
|
and
|
||||||
|
|
||||||
```text
|
```text
|
||||||
000000000011010 <q>:
|
000000000011010 <q>:
|
||||||
11010: 55667788
|
11010: 55667788
|
||||||
11014: 11223344
|
11014: 11223344
|
||||||
```
|
```
|
||||||
|
|
||||||
Let's examine the second snippet first.
|
Let's examine the second snippet first.
|
||||||
|
|
||||||
It says `000000000011010 <q>:`. This means that what comes next is the data
|
It says `000000000011010 <q>:`. This means that what comes next is the
|
||||||
corresponding to what is labeled `q` in our source code. Notice the
|
data corresponding to what is labeled `q` in our source code. Notice the
|
||||||
relocatable address of `11010`. We will explain "relocatable address"
|
relocatable address of `11010`. We will explain "relocatable address"
|
||||||
below.
|
below.
|
||||||
|
|
||||||
|
|
@ -160,33 +161,45 @@ to accomplish their nefarious purposes.
|
||||||
|
|
||||||
This image shows `gdb` in `layout regs` at the time our program is loaded.
|
This image shows `gdb` in `layout regs` at the time our program is loaded.
|
||||||
|
|
||||||

|
<figure>
|
||||||
|
<img src="././1_prior_to_running.png" style="width:80%;">
|
||||||
|
<figcaption>Prior to launchr</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
Notice that all of the addresses match the disassemblies given above.
|
Notice that all of the addresses match the disassemblies given above.
|
||||||
For example `main()` starts at `7a0`.
|
For example `main()` starts at `7a0`.
|
||||||
|
|
||||||
Now watch what happens the the program is actually launched:
|
Now watch what happens the the program is actually launched:
|
||||||
|
|
||||||

|
<figure>
|
||||||
|
<img src="./2_after_b_and_run.png" style="width:80%;">
|
||||||
NOTE NOTE NOTE NOTE NOTE
|
<figcaption>After breakpoint and launch</figcaption>
|
||||||
|
</figure>
|
||||||
THERE IS MUCH HERE THAT SHOULD BE REWRITTEN!!!
|
|
||||||
|
|
||||||
COME BACK TO THIS!!!
|
|
||||||
|
|
||||||
Suddenly all the address change to much larger values.
|
Suddenly all the address change to much larger values.
|
||||||
|
|
||||||
**In fact, the addresses all seem to be six bytes long! OK, so they aren't
|
**In fact, the addresses all seem to be six bytes long!**
|
||||||
eight bytes long but this can be explained by choices about how much of the
|
|
||||||
full "virtual" address space that will be used. The salient point is that
|
|
||||||
even six bytes is far too large to fit in a four byte instruction. GDB is
|
|
||||||
masking the pseudo instruction and showing what the effective addresses are.**
|
|
||||||
|
|
||||||
Now lets step forward to see the results of the first `ldr` of the
|
Why are these addresses only six bytes long when all pointers are
|
||||||
|
8 bytes long?
|
||||||
|
|
||||||
|
Sixty four bit ARM Linux kernels allocate 39, 42 or 48 bits for the size
|
||||||
|
of a process's virtual address space. Notice 42 and 48 bit values
|
||||||
|
require 6 bytes to hold them. A virtual address space is all of the
|
||||||
|
addresses a process can generate / use. Further, all addresses used
|
||||||
|
by processes are virtual addresses.
|
||||||
|
|
||||||
|
The salient point is that even six bytes is far too large to fit in a
|
||||||
|
four byte instruction. GDB is masking the pseudo instruction and showing
|
||||||
|
what the effective addresses are.**
|
||||||
|
|
||||||
|
Now lets step forward to see the results of the first `ldr` of the
|
||||||
`printf()` template / format string into `x0`.
|
`printf()` template / format string into `x0`.
|
||||||
|
|
||||||

|
<figure>
|
||||||
|
<img src="./3_results_of_first_ldr.png" style="width:80%;">
|
||||||
|
<figcaption>Results of first ldr</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
There is a pointer in `x0` ending in `b018`. Notice this is **NOT**
|
There is a pointer in `x0` ending in `b018`. Notice this is **NOT**
|
||||||
the value encoded in the instruction ending in `a7d0`.
|
the value encoded in the instruction ending in `a7d0`.
|
||||||
|
|
@ -195,31 +208,45 @@ has been modified to use some calculated offset from the `pc`.
|
||||||
|
|
||||||
To finish, here is how we confirm `x0` is indeed correct.
|
To finish, here is how we confirm `x0` is indeed correct.
|
||||||
|
|
||||||

|
<figure>
|
||||||
|
<img src="./4_confirm_x0_is_correct.png" style="width:80%;">
|
||||||
|
<figcaption>Confirming x0 is correct</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
Notice down below the `x/s $x0` prints the value in memory
|
Notice down below the `x/s $x0` prints the value in memory
|
||||||
corresponding to the address contained in `x0`.
|
corresponding to the address contained in `x0`.
|
||||||
|
|
||||||
Finally:
|
Finally:
|
||||||
|
|
||||||

|
<figure>
|
||||||
|
<img src="./4_confirm_x0_is_correct.png" style="width:80%;">
|
||||||
|
<figcaption>Confirming x2 is correct</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
At the outset of this discussion we said that this program will crash on source code `line 15`.
|
At the outset of this discussion we said that this program will crash on
|
||||||
See if you can work out why. Take a moment before reading further.
|
source code `line 15`. See if you can work out why. Take a moment before
|
||||||
|
reading further.
|
||||||
|
|
||||||
Now that you have a hypothesis in mind, take a look at this screenshot showing
|
Now that you have a hypothesis in mind, take a look at this screenshot
|
||||||
the state of `x1` after this instruction: `ldr x1, q` is executed.
|
showing the state of `x1` after this instruction: `ldr x1, q` is
|
||||||
|
executed.
|
||||||
|
|
||||||

|
<figure>
|
||||||
|
<img src="./after_bad_load.png" style="width:80%;">
|
||||||
|
<figcaption>After bad load</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
Notice that what is in `x1` this time looks very different from the previous attempt
|
Notice that what is in `x1` this time looks very different from the
|
||||||
at printing. Notice still more that the value now in `x1` is the value of `q`, not
|
previous attempt at printing. Notice still more that the value now in
|
||||||
its address.
|
`x1` is the value of `q`, not its address.
|
||||||
|
|
||||||
Naturally, the next instruction which tries to dereference the value of `q` rather
|
Naturally, the next instruction which tries to dereference the value of
|
||||||
than its address, causes a crash.
|
`q` rather than its address, causes a crash.
|
||||||
|
|
||||||

|
<figure>
|
||||||
|
<img src="./after_crash.png" style="width:80%;">
|
||||||
|
<figcaption>After crash</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
|
|
@ -232,13 +259,14 @@ memory at those labels can be retrieved.
|
||||||
| ldr r, =label | Load the address of the label into r |
|
| ldr r, =label | Load the address of the label into r |
|
||||||
| ldr r, label | Load the value found at the label into r |
|
| ldr r, label | Load the value found at the label into r |
|
||||||
|
|
||||||
In both cases, the assembler will likely do some magical translation of your
|
In both cases, the assembler will likely do some magical translation of
|
||||||
simple `ldr` instruction into something involving offsets so that the resulting
|
your simple `ldr` instruction into something involving offsets so that
|
||||||
offset can fit into an instruction where the full address cannot.
|
the resulting offset can fit into an instruction where the full address
|
||||||
|
cannot.
|
||||||
|
|
||||||
To store a value back to memory at the address given by a label, the address
|
To store a value back to memory at the address given by a label, the
|
||||||
corresponding to the label will have first been loaded as
|
address corresponding to the label will have first been loaded as is
|
||||||
is described above. Then, once the address is in a register, an `str`
|
described above. Then, once the address is in a register, an `str`
|
||||||
instruction can be used to properly locate the values to be written.
|
instruction can be used to properly locate the values to be written.
|
||||||
|
|
||||||
## Questions
|
## Questions
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue