Updated DS refs
@@ -0,0 +1,186 @@
|
||||
# Week 5 Quiz: Integers, Floats, Doubles, and IEEE 754
|
||||
|
||||
## Instructions
|
||||
Choose the best answer for each question. There is only one correct answer per question.
|
||||
|
||||
---
|
||||
|
||||
## Questions
|
||||
|
||||
### Question 1
|
||||
What is the valid value range of `int8_t` (a signed 8-bit integer)?
|
||||
|
||||
A) 0 to 255
|
||||
B) 0 to 127
|
||||
C) -128 to 127
|
||||
D) -256 to 255
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 1 – "Signed vs Unsigned Integers" (table: `int8_t` range is -128 to 127)
|
||||
|
||||
**Correct Answer: C**
|
||||
|
||||
---
|
||||
|
||||
### Question 2
|
||||
How is the value `-42` stored in a single byte using two's complement?
|
||||
|
||||
A) `0x2A` — the sign is tracked separately by the CPU
|
||||
B) `0xD6` — the CPU flips all bits of `42` (`0x2A`) and adds `1`
|
||||
C) `0xAA` — negative values always have the pattern `1010...` in binary
|
||||
D) `0x42` — the value is stored identically to positive `42`
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 1 – "The Integer Variables" (two's complement: flip bits of `0x2A` and add 1 = `0xD6`)
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 3
|
||||
In IEEE 754 single-precision (32-bit float), how are the 32 bits divided among sign, exponent, and mantissa?
|
||||
|
||||
A) 1 sign bit, 11 exponent bits, 20 mantissa bits
|
||||
B) 1 sign bit, 8 exponent bits, 23 mantissa bits
|
||||
C) 2 sign bits, 8 exponent bits, 22 mantissa bits
|
||||
D) 1 sign bit, 10 exponent bits, 21 mantissa bits
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 2 – "What is a Float?" (IEEE 754 Single-Precision diagram: 1 sign, 8 exponent, 23 mantissa)
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 4
|
||||
Why does `printf` receive a 64-bit `double` even when the source code declares a `float` variable?
|
||||
|
||||
A) The Pico 2's ARM Cortex-M33 does not have a floating-point unit
|
||||
B) Ghidra automatically converts floats to doubles during analysis
|
||||
C) The C standard requires `float` arguments to variadic functions like `printf` to be promoted to `double`
|
||||
D) The `%f` format specifier forces the compiler to use 64-bit precision
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 2.7, Step 14 – "Understand the Float Encoding" (C standard requires float arguments to variadic functions are promoted to double)
|
||||
|
||||
**Correct Answer: C**
|
||||
|
||||
---
|
||||
|
||||
### Question 5
|
||||
What is the exponent bias for IEEE 754 double-precision, and why is it 1023?
|
||||
|
||||
A) 127 — because the exponent field is 8 bits and $(2^8 / 2) - 1 = 127$
|
||||
B) 1023 — because the exponent field is 11 bits and $(2^{11} / 2) - 1 = 1023$
|
||||
C) 1024 — because $2^{10} = 1024$ and the exponent uses 10 bits
|
||||
D) 2047 — because $2^{11} - 1 = 2047$ is the maximum 11-bit value
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 2.7, Step 15 – "Why 1023?" callout (exponent is 11 bits, $2^{11} = 2048$, midpoint = $(2048 / 2) - 1 = 1023$)
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 6
|
||||
On the ARM Cortex-M33, how is a 64-bit double passed to a function like `printf`?
|
||||
|
||||
A) In a single 64-bit register `r0`
|
||||
B) On the stack as an 8-byte value
|
||||
C) In two 32-bit registers: `r2` (low 32 bits) and `r3` (high 32 bits)
|
||||
D) In the floating-point register `d0`
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 2.7, Step 14 – "A 64-bit double is passed in two 32-bit registers" (table: r2 = low, r3 = high)
|
||||
|
||||
**Correct Answer: C**
|
||||
|
||||
---
|
||||
|
||||
### Question 7
|
||||
What does the `mcrr p0, #4, r4, r5, c0` instruction do on the RP2350?
|
||||
|
||||
A) It reads the current GPIO pin state into registers r4 and r5
|
||||
B) It writes to the GPIO coprocessor to set a pin's output value (r4 = pin, r5 = value)
|
||||
C) It configures the GPIO function select register for SIO mode
|
||||
D) It copies data between two ARM general-purpose registers
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 1 – "The Blink Loop with Inline Assembly" (coprocessor register `c0` controls output value, r5 = 1 drives HIGH, r5 = 0 drives LOW)
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 8
|
||||
When configuring a GPIO pin with inline assembly, what value is written to the FUNCSEL field to select SIO (Single-cycle I/O) mode?
|
||||
|
||||
A) `0` — default reset value
|
||||
B) `3` — UART function
|
||||
C) `5` — SIO function
|
||||
D) `31` — null function (disabled)
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 1 – "GPIO Initialization with Inline Assembly" (Step 2: clears FUNCSEL bits and sets to `5` for SIO)
|
||||
|
||||
**Correct Answer: C**
|
||||
|
||||
---
|
||||
|
||||
### Question 9
|
||||
What is the key difference between a `float` (32-bit) and a `double` (64-bit) in terms of decimal precision?
|
||||
|
||||
A) A float has ~15 digits precision; a double has ~7 digits precision
|
||||
B) A float has ~7 digits precision; a double has ~15 digits precision
|
||||
C) Both have the same precision; doubles just have a larger range
|
||||
D) A float has exact precision; a double introduces rounding errors
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 3 – "Float vs Double - Key Differences" (table: float ~7 decimal digits, double ~15 decimal digits)
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
### Question 10
|
||||
When patching the double `42.5` to `99.0` in Ghidra, only the high word (`r3`) needed to change. When patching `42.52525` to `99.99`, **both** words needed to change. Why?
|
||||
|
||||
A) The value `99.99` is larger than `99.0`, so it needs more bits to store
|
||||
B) The value `99.0` has a clean fractional part (`.0`) so the low word is all zeros, but `99.99` has a repeating binary fraction that requires non-zero bits in the low 32 bits
|
||||
C) Ghidra encodes doubles differently depending on the number of decimal places
|
||||
D) The compiler uses a different instruction format for values with more decimal digits
|
||||
|
||||
> 📖 **Reference:** Week 5, Part 3.95 – "Key takeaway" (clean values like 42.5 only need one patch; messy fractions like 42.52525 need two)
|
||||
|
||||
**Correct Answer: B**
|
||||
|
||||
---
|
||||
|
||||
## Answer Key
|
||||
|
||||
1. C - `int8_t` is a signed 8-bit integer with range -128 to 127
|
||||
2. B - Two's complement: flip all bits of `0x2A` (42) and add 1 → `0xD6`
|
||||
3. B - IEEE 754 single-precision: 1 sign bit, 8 exponent bits, 23 mantissa bits
|
||||
4. C - The C standard requires `float` arguments to variadic functions (`printf`) to be promoted to `double`
|
||||
5. B - The 11-bit exponent gives 2048 values; the midpoint $(2^{11} / 2) - 1 = 1023$ is the bias
|
||||
6. C - 64-bit doubles are split across `r2` (low 32 bits) and `r3` (high 32 bits) on ARM Cortex-M33
|
||||
7. B - `mcrr p0, #4, r4, r5, c0` writes to the GPIO coprocessor's output register (c0), setting pin r4 to value r5
|
||||
8. C - FUNCSEL = 5 selects SIO mode for software-controlled GPIO
|
||||
9. B - Float has ~7 decimal digits precision; double has ~15 decimal digits precision
|
||||
10. B - Clean fractions (like `.0`) produce a zero low word; repeating binary fractions (like `.99`) need all 52 mantissa bits, making both words non-zero
|
||||
|
||||
---
|
||||
|
||||
## Scoring Guide
|
||||
|
||||
- **10 correct**: Excellent! You have a strong grasp of Week 5 concepts
|
||||
- **8-9 correct**: Very good! Review the topics you missed
|
||||
- **6-7 correct**: Good start. Go back and review the key concepts
|
||||
- **5 or fewer**: Review the Week 5 material again and try the practice exercises
|
||||
|
||||
---
|
||||
|
||||
## Topics Covered
|
||||
|
||||
This quiz tests your understanding of:
|
||||
- Signed vs unsigned integers: `uint8_t` and `int8_t` ranges
|
||||
- Two's complement encoding of negative numbers
|
||||
- IEEE 754 single-precision (32-bit) field layout
|
||||
- Float-to-double promotion in C variadic functions
|
||||
- IEEE 754 double-precision exponent bias (1023) and its derivation
|
||||
- ARM Cortex-M33 register pairs (`r2:r3`) for 64-bit doubles
|
||||
- GPIO coprocessor instruction `mcrr` for pin output control
|
||||
- FUNCSEL field and SIO mode selection
|
||||
- Float vs double precision differences
|
||||
- Patching strategy: clean fractions (one word) vs repeating fractions (two words)
|
||||
@@ -0,0 +1,63 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 1 Solution: Analyze the Float Binary in Ghidra
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Main Function Analysis
|
||||
|
||||
| Item | Value | Notes |
|
||||
|--------------------------|------------------------|------------------------------------|
|
||||
| Main function address | 0x10000234 | Entry point of program |
|
||||
| Float value (original) | 42.5 | Declared as `float` |
|
||||
| Double hex encoding | 0x4045400000000000 | Promoted to double for printf |
|
||||
| r3 (high word) | 0x40454000 | Sign + exponent + top mantissa |
|
||||
| r2 (low word) | 0x00000000 | All zeros (clean fractional part) |
|
||||
| Exponent (stored) | 1028 | Biased value |
|
||||
| Exponent (real) | 5 | After subtracting bias 1023 |
|
||||
| Format string | "fav_num: %f\r\n" | Located at 0x100034a8 |
|
||||
| stdio_init_all address | 0x10002f5c | I/O initialization |
|
||||
| printf address | 0x100030ec | Standard library function |
|
||||
|
||||
##### IEEE 754 Decoding of 0x4045400000000000
|
||||
|
||||
```
|
||||
r3 = 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
|
||||
r2 = 0x00000000 = 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
|
||||
Sign bit (bit 63): 0 → Positive
|
||||
Exponent (bits 62-52): 10000000100 = 1028 → 1028 - 1023 = 5
|
||||
Mantissa (bits 51-0): 0101010000...0 → 1.010101 (with implied 1)
|
||||
|
||||
Value = 1.010101₂ × 2⁵ = 101010.1₂ = 32 + 8 + 2 + 0.5 = 42.5 ✓
|
||||
```
|
||||
|
||||
##### Decompiled main() After Renaming
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
stdio_init_all();
|
||||
do {
|
||||
__wrap_printf("fav_num: %f\r\n", /* r2:r3 = 0x4045400000000000 = 42.5 */);
|
||||
} while (true);
|
||||
}
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does the compiler promote a `float` to a `double` when passing it to `printf`?**
|
||||
The C standard (§6.5.2.2) specifies **default argument promotions** for variadic functions like `printf`. When a `float` is passed to a variadic parameter (the `...` part), it is automatically promoted to `double`. This is because historically, floating-point hardware and calling conventions operated more efficiently with double precision. The `printf` function with `%f` always expects a 64-bit `double` on the stack or in the register pair `r2:r3`, never a 32-bit `float`.
|
||||
|
||||
2. **The low word (`r2`) is `0x00000000`. What does this tell you about the fractional part of `42.5`?**
|
||||
It means the fractional part of 42.5 can be represented exactly with very few mantissa bits. The value 0.5 is exactly 2⁻¹ in binary—a single bit. After normalization, the mantissa is `010101000...` which only needs 6 significant bits. All remaining 46 bits (including the entire low 32-bit word) are zero. Values like 0.5, 0.25, 0.125 (negative powers of 2) and their sums always produce clean low words, while values like 0.1 or 0.3 produce repeating binary fractions that fill both words.
|
||||
|
||||
3. **What is the purpose of the exponent bias (1023) in IEEE 754 double-precision?**
|
||||
The bias allows the exponent field to represent both positive and negative exponents using only unsigned integers. The 11-bit exponent field stores values 0–2047. By subtracting the bias (1023), the actual exponent range is −1022 to +1023. This avoids needing a separate sign bit for the exponent and simplifies hardware comparison—doubles can be compared as unsigned integers (for positive values) because larger exponents produce larger bit patterns. The bias value 1023 = 2¹⁰ − 1 is chosen to center the range symmetrically.
|
||||
|
||||
4. **If the sign bit (bit 63) were `1` instead of `0`, what value would the double represent?**
|
||||
The value would be **−42.5**. The sign bit in IEEE 754 is independent of all other fields: flipping bit 63 from 0 to 1 simply negates the value. The hex encoding would change from `0x4045400000000000` to `0xC045400000000000`—only the most significant nibble changes from `4` (`0100`) to `C` (`1100`), with bit 31 of r3 changing from 0 to 1.
|
||||
@@ -0,0 +1,271 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 1: Analyze the Float Binary in Ghidra
|
||||
|
||||
#### Objective
|
||||
Import and analyze the `0x000e_floating-point-data-type.bin` binary in Ghidra to understand how the compiler handles floating-point variables, discover float-to-double promotion, and decode the IEEE 754 double-precision encoding of `42.5` from two 32-bit registers.
|
||||
|
||||
#### Prerequisites
|
||||
- Ghidra installed and configured
|
||||
- `0x000e_floating-point-data-type.bin` binary available in your build directory
|
||||
- Understanding of IEEE 754 encoding from Week 5 Part 2
|
||||
- Basic Ghidra navigation skills from Weeks 3 and 4
|
||||
|
||||
#### Task Description
|
||||
You will import the float binary into Ghidra, configure it for ARM Cortex-M33, resolve function names, discover that the compiler promotes `float` to `double` when passing to `printf`, and manually decode the 64-bit double `0x4045400000000000` field by field to confirm it represents `42.5`.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Start Ghidra and Create New Project
|
||||
|
||||
```powershell
|
||||
ghidraRun
|
||||
```
|
||||
|
||||
1. Click **File** ? **New Project**
|
||||
2. Select **Non-Shared Project**
|
||||
3. Click **Next**
|
||||
4. Enter Project Name: `week05-ex01-floating-point`
|
||||
5. Choose a project directory
|
||||
6. Click **Finish**
|
||||
|
||||
##### Step 2: Import the Binary
|
||||
|
||||
1. Navigate to your file explorer
|
||||
2. Find `Embedded-Hacking\0x000e_floating-point-data-type\build\0x000e_floating-point-data-type.bin`
|
||||
3. **Drag and drop** the `.bin` file into Ghidra's project window
|
||||
|
||||
##### Step 3: Configure Import Settings
|
||||
|
||||
When the import dialog appears:
|
||||
|
||||
1. Click the three dots (**…**) next to **Language**
|
||||
2. Search for: `Cortex`
|
||||
3. Select: **ARM Cortex 32 little endian default**
|
||||
4. Click **OK**
|
||||
|
||||
Now click **Options…** button:
|
||||
1. Change **Block Name** to: `.text`
|
||||
2. Change **Base Address** to: `10000000` (XIP flash base)
|
||||
3. Click **OK**
|
||||
|
||||
Then click **OK** on the main import dialog.
|
||||
|
||||
##### Step 4: Analyze the Binary
|
||||
|
||||
1. Double-click the imported file in the project window
|
||||
2. When prompted "Analyze now?" click **Yes**
|
||||
3. Leave all default analysis options selected
|
||||
4. Click **Analyze**
|
||||
5. Wait for analysis to complete (watch bottom-right progress bar)
|
||||
|
||||
##### Step 5: Locate and Rename the Main Function
|
||||
|
||||
Look at the **Symbol Tree** panel on the left. Expand **Functions**.
|
||||
|
||||
From previous weeks, we know the boot sequence leads to `main()`:
|
||||
|
||||
1. Click on `FUN_10000234`
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change to: `int main(void)`
|
||||
4. Click **OK**
|
||||
|
||||
##### Step 6: Resolve stdio_init_all and printf
|
||||
|
||||
**Rename stdio_init_all:**
|
||||
1. Click on `FUN_10002f5c` in the decompile window
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change to: `bool stdio_init_all(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Rename printf:**
|
||||
1. Click on `FUN_100030ec`
|
||||
2. Right-click ? **Edit Function Signature**
|
||||
3. Change to: `int __wrap_printf(char *format,...)`
|
||||
4. Check the **Varargs** checkbox
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 7: Observe the Decompiled Code
|
||||
|
||||
After resolving, the decompiled `main` should look like:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
undefined4 uVar1;
|
||||
undefined4 extraout_r1;
|
||||
undefined4 uVar2;
|
||||
undefined4 extraout_r1_00;
|
||||
|
||||
stdio_init_all();
|
||||
uVar1 = DAT_1000024c;
|
||||
uVar2 = extraout_r1;
|
||||
do {
|
||||
__wrap_printf(DAT_10000250,uVar2,0,uVar1);
|
||||
uVar2 = extraout_r1_00;
|
||||
} while( true );
|
||||
}
|
||||
```
|
||||
|
||||
**Critical observation:** Where is `float fav_num = 42.5`? The compiler optimized it into constants!
|
||||
|
||||
##### Step 8: Identify the Register Pair
|
||||
|
||||
Look at the **Listing** window (assembly view) for `main`:
|
||||
|
||||
```assembly
|
||||
1000023a 00 24 movs r4, #0x0
|
||||
1000023c 03 4d ldr r5, [DAT_1000024c] = 40454000h
|
||||
```
|
||||
|
||||
Two values are being passed to `printf`:
|
||||
- `r2 = 0x00000000` (low 32 bits)
|
||||
- `r3 = 0x40454000` (high 32 bits)
|
||||
|
||||
Together they form a 64-bit double: `0x4045400000000000`
|
||||
|
||||
**Why a double?** The C standard requires that `float` arguments to variadic functions like `printf` are **promoted to `double`**. So even though our variable is declared as `float fav_num = 42.5`, `printf` always receives a 64-bit double.
|
||||
|
||||
##### Step 9: Write Out the Binary Layout
|
||||
|
||||
Convert both registers to binary:
|
||||
|
||||
```
|
||||
r3 (high 32 bits): 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
|
||||
r2 (low 32 bits): 0x00000000 = 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
```
|
||||
|
||||
Map the 64-bit IEEE 754 fields:
|
||||
|
||||
```
|
||||
Bit 63 (sign): 0
|
||||
Bits 62–52 (exponent): 10000000100
|
||||
Bits 51–0 (mantissa): 0101010000000000...0000
|
||||
```
|
||||
|
||||
##### Step 10: Decode the Sign Bit
|
||||
|
||||
Bit 63 of the double = bit 31 of r3:
|
||||
|
||||
```
|
||||
r3 = 0x40454000 = 0100 0000 0100 0101 0100 0000 0000 0000
|
||||
^
|
||||
bit 31 = 0 ? Positive number
|
||||
```
|
||||
|
||||
IEEE 754 sign rule: `0` = Positive, `1` = Negative.
|
||||
|
||||
##### Step 11: Decode the Exponent
|
||||
|
||||
Extract bits 30–20 from r3:
|
||||
|
||||
```
|
||||
0x40454000: 0 10000000100 01010100000000000000
|
||||
^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
|
||||
sign exponent mantissa (top 20)
|
||||
```
|
||||
|
||||
Exponent bits: `10000000100` = 2¹° + 2² = 1024 + 4 = **1028**
|
||||
|
||||
Subtract the double-precision bias (1023):
|
||||
|
||||
$$\text{real exponent} = 1028 - 1023 = \mathbf{5}$$
|
||||
|
||||
##### Step 12: Decode the Mantissa
|
||||
|
||||
High 20 bits of mantissa (from r3 bits 19–0):
|
||||
```
|
||||
0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
Low 32 bits of mantissa (from r2):
|
||||
```
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
```
|
||||
|
||||
With the implied leading `1`:
|
||||
```
|
||||
1.010101 00000...
|
||||
```
|
||||
|
||||
##### Step 13: Reconstruct the Final Value
|
||||
|
||||
$$1.010101_2 \times 2^5 = 101010.1_2$$
|
||||
|
||||
Convert to decimal:
|
||||
|
||||
| Bit | Power | Value |
|
||||
|-----|-------|-------|
|
||||
| 1 | 25 | 32 |
|
||||
| 0 | 24 | 0 |
|
||||
| 1 | 2³ | 8 |
|
||||
| 0 | 2² | 0 |
|
||||
| 1 | 2¹ | 2 |
|
||||
| 0 | 2° | 0 |
|
||||
| 1 | 2?¹ | 0.5 |
|
||||
|
||||
$$32 + 8 + 2 + 0.5 = \mathbf{42.5} ?$$
|
||||
|
||||
##### Step 14: Find the Format String
|
||||
|
||||
In the Listing view, click on the data reference to locate:
|
||||
|
||||
```
|
||||
s_fav_num:_%f_100034a8 ds "fav_num: %f\r\n"
|
||||
```
|
||||
|
||||
Note that the format specifier is `%f`, confirming this is a floating-point print call.
|
||||
|
||||
##### Step 15: Document Your Findings
|
||||
|
||||
Create a table of your observations:
|
||||
|
||||
| Item | Value | Notes |
|
||||
| ------------------------- | ------------------ | ---------------------------------- |
|
||||
| Main function address | `0x10000234` | Entry point of program |
|
||||
| Float value (original) | `42.5` | Declared as `float` |
|
||||
| Double hex encoding | `0x4045400000000000` | Promoted to double for printf |
|
||||
| r3 (high word) | `0x40454000` | Contains sign + exponent + mantissa top bits |
|
||||
| r2 (low word) | `0x00000000` | All zeros — clean fractional part |
|
||||
| Exponent (stored) | 1028 | Biased value |
|
||||
| Exponent (real) | 5 | After subtracting bias 1023 |
|
||||
| Format string | `"fav_num: %f\r\n"` | Located at `0x100034a8` |
|
||||
| Float-to-double promotion | Yes | C standard for variadic functions |
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should be able to:
|
||||
- Import and configure ARM binaries in Ghidra for float analysis
|
||||
- Explain why `printf` receives a `double` even when the variable is a `float`
|
||||
- Identify the register pair `r2:r3` that holds a 64-bit double
|
||||
- Manually decode an IEEE 754 double from hex to decimal
|
||||
- Locate format strings in the binary
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does the compiler promote a `float` to a `double` when passing it to `printf`?
|
||||
|
||||
###### Question 2: The low word (`r2`) is `0x00000000`. What does this tell you about the fractional part of `42.5`?
|
||||
|
||||
###### Question 3: What is the purpose of the exponent bias (1023) in IEEE 754 double-precision?
|
||||
|
||||
###### Question 4: If the sign bit (bit 63) were `1` instead of `0`, what value would the double represent?
|
||||
|
||||
#### Tips and Hints
|
||||
- The **Listing** window shows raw assembly; the **Decompile** window shows reconstructed C
|
||||
- Double-click on a `DAT_` reference to jump to the data constant
|
||||
- Use Python to verify: `import struct; struct.pack('>d', 42.5).hex()` gives `4045400000000000`
|
||||
- Remember: r3 = high 32 bits (sign + exponent + top mantissa), r2 = low 32 bits (bottom mantissa)
|
||||
- The bias for doubles is always 1023; for floats it's 127
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 2 to patch this float value in Ghidra
|
||||
- Try computing the IEEE 754 encoding of other values like `3.14` or `100.0` by hand
|
||||
- Compare the 32-bit float encoding `0x422A0000` with the 64-bit double encoding `0x4045400000000000` — both represent `42.5`
|
||||
|
||||
#### Additional Challenge
|
||||
Find the data constant `DAT_1000024c` in the Listing view. What raw bytes are stored there? Remember that ARM is little-endian — the bytes in memory are in reverse order. Write out the byte order as it appears in memory vs. as a 32-bit value.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 2 Solution: Patch the Float Binary — Changing 42.5 to 99.0
|
||||
|
||||
#### Answers
|
||||
|
||||
##### IEEE 754 Encoding of 99.0
|
||||
|
||||
```
|
||||
Integer: 99 = 1100011₂
|
||||
Fractional: .0 = .0₂
|
||||
Combined: 1100011.0₂
|
||||
Normalized: 1.100011₂ × 2⁶
|
||||
|
||||
Sign: 0 (positive)
|
||||
Exponent: 6 + 1023 = 1029 = 10000000101₂
|
||||
Mantissa: 100011 followed by 46 zeros
|
||||
|
||||
Full double: 0x4058C00000000000
|
||||
```
|
||||
|
||||
##### Patch Summary
|
||||
|
||||
| Register | Old Value (42.5) | New Value (99.0) | Changed? |
|
||||
|----------|-----------------|------------------|----------|
|
||||
| r2 | 0x00000000 | 0x00000000 | No |
|
||||
| r3 | 0x40454000 | 0x4058C000 | **Yes** |
|
||||
|
||||
##### Ghidra Patch
|
||||
|
||||
```
|
||||
DAT_1000024c:
|
||||
Before (little-endian): 00 40 45 40 → 0x40454000
|
||||
After (little-endian): 00 C0 58 40 → 0x4058C000
|
||||
```
|
||||
|
||||
##### Serial Output
|
||||
|
||||
```
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
...
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why did we only need to patch r3 (the high word) and not r2 (the low word)?**
|
||||
Both 42.5 and 99.0 have "clean" fractional parts that can be exactly represented with few mantissa bits. For 42.5, the mantissa is `010101000...0`; for 99.0, it's `100011000...0`. In both cases, all significant mantissa bits fit within the top 20 bits (stored in r3 bits 19–0), leaving the bottom 32 bits (r2) as all zeros. Only values with complex or repeating binary fractions (like 42.52525 or 99.99) need non-zero low words.
|
||||
|
||||
2. **What would the high word be if we wanted to patch the value to `-99.0` instead?**
|
||||
Flip bit 31 of r3 (the sign bit). The current r3 = `0x4058C000` = `0100 0000 0101 1000 1100...`. Setting bit 31 to 1: `0xC058C000` = `1100 0000 0101 1000 1100...`. The full double encoding of −99.0 is `0xC058C00000000000`. Only the most significant nibble changes from `4` to `C`.
|
||||
|
||||
3. **Walk through the encoding of `100.0` as a double. What are the high and low words?**
|
||||
```
|
||||
100 = 1100100₂
|
||||
100.0 = 1100100.0₂ = 1.1001₂ × 2⁶
|
||||
Sign: 0
|
||||
Exponent: 6 + 1023 = 1029 = 10000000101₂
|
||||
Mantissa: 1001 followed by 48 zeros
|
||||
|
||||
Full 64-bit: 0 10000000101 1001000000...0
|
||||
High word (r3): 0x40590000
|
||||
Low word (r2): 0x00000000
|
||||
```
|
||||
Verification: `struct.pack('>d', 100.0).hex()` → `4059000000000000` ✓
|
||||
|
||||
4. **Why do we need the `--family 0xe48bff59` flag when converting to UF2?**
|
||||
The `--family` flag specifies the target chip family in the UF2 file header. `0xe48bff59` is the registered family ID for the RP2350. The bootloader reads this field to verify the firmware is intended for the correct chip before flashing. If the family ID doesn't match (e.g., using the RP2040 ID `0xe48bff56`), the bootloader may reject the firmware or write it incorrectly. This prevents accidentally flashing RP2040 firmware onto an RP2350 (or vice versa), which could cause undefined behavior since the chips have different architectures (Cortex-M0+ vs Cortex-M33).
|
||||
@@ -0,0 +1,173 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 2: Patch the Float Binary — Changing 42.5 to 99.0
|
||||
|
||||
#### Objective
|
||||
Calculate the IEEE 754 double-precision encoding of `99.0`, patch the float binary in Ghidra to change the printed value from `42.5` to `99.0`, export the patched binary, convert it to UF2 format, and flash it to the Pico 2 to verify the change.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercise 1 (float binary imported and analyzed in Ghidra)
|
||||
- Understanding of IEEE 754 double-precision encoding from Week 5 Part 2.7
|
||||
- Python installed for UF2 conversion
|
||||
- `uf2conv.py` script available in your project directory
|
||||
- Raspberry Pi Pico 2 connected via USB
|
||||
- Serial monitor software (PuTTY, minicom, or screen)
|
||||
|
||||
#### Task Description
|
||||
You will convert `99.0` to its IEEE 754 double-precision encoding by hand (integer-to-binary conversion, normalization, field extraction), determine which register words need to change, patch the data constant in Ghidra, and verify on hardware that the serial output now prints `99.000000`.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Convert 99 to Binary
|
||||
|
||||
Use repeated division by 2:
|
||||
|
||||
| Division | Quotient | Remainder |
|
||||
|----------|----------|-----------|
|
||||
| 99 ÷ 2 | 49 | **1** |
|
||||
| 49 ÷ 2 | 24 | **1** |
|
||||
| 24 ÷ 2 | 12 | **0** |
|
||||
| 12 ÷ 2 | 6 | **0** |
|
||||
| 6 ÷ 2 | 3 | **0** |
|
||||
| 3 ÷ 2 | 1 | **1** |
|
||||
| 1 ÷ 2 | 0 | **1** |
|
||||
|
||||
Read remainders bottom-to-top: $99_{10} = 1100011_2$
|
||||
|
||||
##### Step 2: Handle the Fractional Part
|
||||
|
||||
The fractional part of `99.0` is `.0` — exactly zero. There are no fractional bits.
|
||||
|
||||
$$99.0_{10} = 1100011.0_2$$
|
||||
|
||||
##### Step 3: Normalize to IEEE 754 Form
|
||||
|
||||
Move the binary point so there is exactly one `1` before it:
|
||||
|
||||
$$1100011.0_2 = 1.100011_2 \times 2^6$$
|
||||
|
||||
We shifted the binary point 6 places left, so the exponent is **6**.
|
||||
|
||||
##### Step 4: Extract the IEEE 754 Fields
|
||||
|
||||
1. **Sign:** `0` (positive)
|
||||
2. **Exponent:** $6 + 1023 = 1029 = 10000000101_2$
|
||||
3. **Mantissa:** `100011` followed by 46 zeros (everything after the `1.`, padded to 52 bits)
|
||||
4. **Full double:** `0x4058C00000000000`
|
||||
|
||||
Split into register words:
|
||||
- **r3 (high word):** `0x4058C000`
|
||||
- **r2 (low word):** `0x00000000`
|
||||
|
||||
##### Step 5: Determine What to Patch
|
||||
|
||||
Compare old vs. new:
|
||||
|
||||
| Register | Old Value | New Value | Changed? |
|
||||
| -------- | ------------ | ------------ | -------- |
|
||||
| `r2` | `0x00000000` | `0x00000000` | No |
|
||||
| `r3` | `0x40454000` | `0x4058C000` | **Yes** |
|
||||
|
||||
Since `r2` stays all zeros, we only need to patch the high word in `r3`.
|
||||
|
||||
##### Step 6: Locate the Data Constant in Ghidra
|
||||
|
||||
Open your Ghidra project from Exercise 1. In the Listing view, find the data constant that loads into `r3`:
|
||||
|
||||
```
|
||||
DAT_1000024c
|
||||
10000248 00 40 45 40 undefined4 40454000h
|
||||
```
|
||||
|
||||
This is the 32-bit constant `0x40454000` — the high word of the double `42.5`.
|
||||
|
||||
##### Step 7: Patch the Constant
|
||||
|
||||
1. Click on **Window** → **Bytes** to open the Bytes Editor
|
||||
2. Click the **Pencil Icon** to enable editing
|
||||
3. Navigate to the data at `DAT_1000024c`
|
||||
4. The bytes in memory (little-endian) read: `00 40 45 40`
|
||||
5. Change them to: `00 C0 58 40` (which is `0x4058C000` in little-endian)
|
||||
6. Press **Enter**
|
||||
|
||||
**Verify** in the Listing view — the data should now show `4058C000h`.
|
||||
|
||||
##### Step 8: Verify the Patch in the Decompile Window
|
||||
|
||||
The decompiled code should now reference the new constant. The value loaded into `r3` should be `0x4058C000`.
|
||||
|
||||
##### Step 9: Export the Patched Binary
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Set **Format** to **Raw Bytes**
|
||||
3. Navigate to your build directory
|
||||
4. Name the file: `0x000e_floating-point-data-type-h.bin`
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 10: Convert to UF2 Format
|
||||
|
||||
Open a terminal and navigate to your project directory:
|
||||
|
||||
```powershell
|
||||
cd Embedded-Hacking-main\0x000e_floating-point-data-type
|
||||
```
|
||||
|
||||
Run the conversion:
|
||||
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x000e_floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 11: Flash and Verify
|
||||
|
||||
1. Hold **BOOTSEL** and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**Expected output:**
|
||||
|
||||
```
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
fav_num: 99.000000
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **Success!** The value changed from `42.5` to `99.0`!
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should:
|
||||
- See `fav_num: 99.000000` printing instead of `fav_num: 42.500000`
|
||||
- Have a patched binary file (`0x000e_floating-point-data-type-h.bin`)
|
||||
- Have a UF2 file (`hacked.uf2`)
|
||||
- Understand the complete IEEE 754 encoding and patching workflow for floats
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why did we only need to patch r3 (the high word) and not r2 (the low word)?
|
||||
|
||||
###### Question 2: What would the high word be if we wanted to patch the value to `-99.0` instead? (Hint: which bit controls the sign?)
|
||||
|
||||
###### Question 3: Walk through the encoding of `100.0` as a double. What are the high and low words?
|
||||
|
||||
###### Question 4: Why do we need the `--family 0xe48bff59` flag when converting to UF2?
|
||||
|
||||
#### Tips and Hints
|
||||
- Always verify your encoding with Python: `import struct; struct.pack('>d', 99.0).hex()`
|
||||
- Little-endian means the bytes in memory are reversed: `0x4058C000` is stored as `00 C0 58 40`
|
||||
- If you patch the wrong bytes, use **File** → **Undo** in Ghidra (or re-import the original binary)
|
||||
- The bias for double-precision is always 1023; for single-precision it's 127
|
||||
- A clean fractional part (like `.0` or `.5`) means the low word (`r2`) is all zeros
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 3 to analyze the double-precision binary
|
||||
- Try patching to different values: `3.14`, `100.0`, `255.0`
|
||||
- Compare how many register words change for clean vs. messy fractions
|
||||
|
||||
#### Additional Challenge
|
||||
Patch the float to `3.14` instead of `99.0`. Since `3.14` has a repeating binary fraction, the low word will **not** be zero. This means you need to modify the assembly to load a non-zero value into `r2` as well. Can you figure out where `r2` gets its zero value (`movs r4, #0x0`) and change it?
|
||||
@@ -0,0 +1,70 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 3 Solution: Analyze the Double Binary in Ghidra
|
||||
|
||||
#### Answers
|
||||
|
||||
##### Register Pair for 42.52525
|
||||
|
||||
| Register | Value | Role |
|
||||
|----------|-------------|---------------|
|
||||
| r2 | 0x645A1CAC | Low 32 bits |
|
||||
| r3 | 0x4045433B | High 32 bits |
|
||||
|
||||
Full double: **0x4045433B645A1CAC**
|
||||
|
||||
##### IEEE 754 Decoding
|
||||
|
||||
```
|
||||
r3 = 0x4045433B = 0100 0000 0100 0101 0100 0011 0011 1011
|
||||
r2 = 0x645A1CAC = 0110 0100 0101 1010 0001 1100 1010 1100
|
||||
|
||||
Sign bit (bit 63): 0 → Positive
|
||||
Exponent (bits 62-52): 10000000100 = 1028 → 1028 - 1023 = 5
|
||||
Mantissa (bits 51-0): 0101010000110011101101100100010110100001110010101100
|
||||
|
||||
Value = 1.0101010000110011...₂ × 2⁵ = 101010.10000110011...₂
|
||||
Integer part: 101010₂ = 32 + 8 + 2 = 42
|
||||
Fractional part: .10000110011... ≈ 0.52525
|
||||
Result: 42.52525 ✓
|
||||
```
|
||||
|
||||
##### Float vs Double Comparison
|
||||
|
||||
| Item | Float (42.5) | Double (42.52525) |
|
||||
|--------------------------|---------------------|------------------------|
|
||||
| r2 (low word) | 0x00000000 | 0x645A1CAC |
|
||||
| r3 (high word) | 0x40454000 | 0x4045433B |
|
||||
| Low word is zero? | Yes | **No** |
|
||||
| Words to patch | 1 (r3 only) | **2 (both r2 and r3)** |
|
||||
| Format specifier | %f | %lf |
|
||||
| Assembly load instruction| movs + ldr | ldrd (load double) |
|
||||
|
||||
##### Key Assembly
|
||||
|
||||
```assembly
|
||||
10000238 push {r3,r4,r5,lr}
|
||||
1000023a adr r5, [0x10000254]
|
||||
1000023c ldrd r4, r5, [r5, #0x0] ; r4 = 0x645A1CAC, r5 = 0x4045433B
|
||||
10000240 bl stdio_init_all
|
||||
10000244 mov r2, r4 ; r2 = low word
|
||||
10000246 mov r3, r5 ; r3 = high word
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why does `42.5` have a zero low word but `42.52525` does not?**
|
||||
The fractional part determines whether the low word is zero. 0.5 in binary is exactly 2⁻¹ = `0.1₂`—a single bit. After normalization, the mantissa for 42.5 is `010101000...0`, needing only 6 significant bits, all fitting in the top 20 mantissa bits within r3. In contrast, 0.52525 is a **repeating binary fraction** that cannot be represented exactly—it requires all 52 mantissa bits to approximate as closely as possible. The lower 32 bits in r2 (`0x645A1CAC`) carry the additional precision needed for this approximation.
|
||||
|
||||
2. **The assembly uses `ldrd r4, r5, [r5, #0x0]` instead of two separate `ldr` instructions. What is the advantage?**
|
||||
`ldrd` (Load Register Double) loads two consecutive 32-bit words from memory in a single instruction, completing in one memory access cycle (or two back-to-back aligned accesses on the bus). Using two separate `ldr` instructions would require two instruction fetches, two decode cycles, and two memory accesses. `ldrd` reduces code size by 4 bytes (one 4-byte instruction vs. two) and improves performance by allowing the memory controller to pipeline both loads. For 64-bit doubles that are always loaded in pairs, `ldrd` is the optimal choice.
|
||||
|
||||
3. **Both the float and double programs have the same exponent (stored as 1028, real exponent 5). Why?**
|
||||
Both 42.5 and 42.52525 fall in the same range: between 32 (2⁵) and 64 (2⁶). Normalization produces `1.xxx × 2⁵` for both values. The exponent is determined solely by the magnitude (which power of 2 the number falls between), not by the fractional precision. Any number from 32.0 to 63.999... would have real exponent 5 (stored as 1028). The mantissa captures the differences—42.5 has mantissa `010101000...` while 42.52525 has `0101010000110011...`.
|
||||
|
||||
4. **If you were patching this double, how many data constants would you need to modify compared to the float exercise?**
|
||||
**Two** data constants—both `DAT_10000254` (low word, r2) and `DAT_10000258` (high word, r3). In the float exercise (42.5), only one constant needed patching because r2 was zero and stayed zero when patching to 99.0. For the double 42.52525, since the low word is already non-zero (`0x645A1CAC`), any new value with a different repeating fraction will require changing both words. The only exception would be patching to a value whose low word happens to also be `0x645A1CAC` (virtually impossible for an arbitrary target value).
|
||||
@@ -0,0 +1,277 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 3: Analyze the Double Binary in Ghidra
|
||||
|
||||
#### Objective
|
||||
Import and analyze the `0x0011_double-floating-point-data-type.bin` binary in Ghidra to understand how doubles differ from floats at the binary level, observe that **both** register words carry non-zero data when the fractional part is complex, and decode the IEEE 754 double-precision encoding of `42.52525` from two 32-bit registers.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercises 1 and 2 (float analysis and patching)
|
||||
- Understanding of IEEE 754 double-precision format from Week 5 Part 3
|
||||
- Understanding of register pairs (`r2:r3`) from Exercise 1
|
||||
- Basic Ghidra navigation skills
|
||||
|
||||
#### Task Description
|
||||
You will import the double binary into Ghidra, resolve function names, identify that `42.52525` requires non-zero data in **both** r2 and r3 (unlike `42.5` which had r2 = 0), and decode the full 64-bit double `0x4045433B645A1CAC` field by field to confirm it represents `42.52525`.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Flash the Original Binary
|
||||
|
||||
Before analysis, verify the program works:
|
||||
|
||||
1. Hold **BOOTSEL** and plug in your Pico 2
|
||||
2. Flash `0x0011_double-floating-point-data-type.uf2` to the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
fav_num: 42.525250
|
||||
fav_num: 42.525250
|
||||
fav_num: 42.525250
|
||||
...
|
||||
```
|
||||
|
||||
##### Step 2: Create a New Ghidra Project
|
||||
|
||||
1. Launch Ghidra: `ghidraRun`
|
||||
2. Click **File** → **New Project**
|
||||
3. Select **Non-Shared Project**
|
||||
4. Project Name: `week05-ex03-double-analysis`
|
||||
5. Click **Finish**
|
||||
|
||||
##### Step 3: Import and Configure the Binary
|
||||
|
||||
1. Drag and drop `0x0011_double-floating-point-data-type.bin` into Ghidra
|
||||
2. Set Language: **ARM Cortex 32 little endian default**
|
||||
3. Click **Options…**
|
||||
- Block Name: `.text`
|
||||
- Base Address: `10000000`
|
||||
4. Click **OK** on all dialogs
|
||||
5. Double-click the file and click **Yes** to analyze
|
||||
|
||||
##### Step 4: Locate and Rename Functions
|
||||
|
||||
Identify the main function and standard library calls:
|
||||
|
||||
**Rename main:**
|
||||
1. Click on `FUN_10000238`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change to: `int main(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Rename stdio_init_all:**
|
||||
1. Click on `FUN_10002f64`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change to: `bool stdio_init_all(void)`
|
||||
4. Click **OK**
|
||||
|
||||
**Rename printf:**
|
||||
1. Click on `FUN_100030f4`
|
||||
2. Right-click → **Edit Function Signature**
|
||||
3. Change to: `int printf(char *format,...)`
|
||||
4. Check the **Varargs** checkbox
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 5: Observe the Decompiled Code
|
||||
|
||||
After renaming, the decompiled `main` should look like:
|
||||
|
||||
```c
|
||||
int main(void)
|
||||
{
|
||||
undefined4 uVar1;
|
||||
undefined4 uVar2;
|
||||
undefined4 extraout_r1;
|
||||
undefined4 uVar3;
|
||||
undefined4 extraout_r1_00;
|
||||
|
||||
uVar2 = DAT_10000258;
|
||||
uVar1 = DAT_10000254;
|
||||
stdio_init_all();
|
||||
uVar3 = extraout_r1;
|
||||
do {
|
||||
printf(DAT_10000250,uVar3,uVar1,uVar2);
|
||||
uVar3 = extraout_r1_00;
|
||||
} while( true );
|
||||
}
|
||||
```
|
||||
|
||||
**Critical observation:** There are now **two** non-zero data constants — `DAT_10000254` and `DAT_10000258`. This is the key difference from the float exercise!
|
||||
|
||||
##### Step 6: Examine the Assembly Listing
|
||||
|
||||
Click on the **Listing** window and find the main function assembly:
|
||||
|
||||
```assembly
|
||||
10000238 push {r3,r4,r5,lr}
|
||||
1000023a adr r5, [0x10000254]
|
||||
1000023c ldrd r4, r5, [r5, #0x0] = 645A1CACh / 4045433Bh
|
||||
10000240 bl stdio_init_all
|
||||
```
|
||||
|
||||
**Key instruction: `ldrd r4, r5, [r5, #0x0]`**
|
||||
|
||||
This is a **load register double** instruction — it loads two consecutive 32-bit words in a single instruction:
|
||||
- `r4` gets the low word: `0x645A1CAC`
|
||||
- `r5` gets the high word: `0x4045433B`
|
||||
|
||||
Later in the loop:
|
||||
```assembly
|
||||
10000244 mov r2, r4 ; r2 = 0x645A1CAC (low)
|
||||
10000246 mov r3, r5 ; r3 = 0x4045433B (high)
|
||||
```
|
||||
|
||||
##### Step 7: Identify the Register Pair
|
||||
|
||||
| Register | Value | Role |
|
||||
| -------- | ------------ | ------------ |
|
||||
| `r2` | `0x645A1CAC` | Low 32 bits |
|
||||
| `r3` | `0x4045433B` | High 32 bits |
|
||||
|
||||
Together: `0x4045433B645A1CAC`
|
||||
|
||||
**Compare to the float exercise:**
|
||||
- Float `42.5`: r2 = `0x00000000`, r3 = `0x40454000` — low word is all zeros
|
||||
- Double `42.52525`: r2 = `0x645A1CAC`, r3 = `0x4045433B` — **both words are non-zero!**
|
||||
|
||||
This happens because `42.52525` has a repeating binary fraction that needs all 52 mantissa bits.
|
||||
|
||||
##### Step 8: Decode the Sign Bit
|
||||
|
||||
Convert r3 to binary and check bit 31:
|
||||
|
||||
```
|
||||
r3 = 0x4045433B = 0100 0000 0100 0101 0100 0011 0011 1011
|
||||
^
|
||||
bit 31 = 0 → Positive number ✓
|
||||
```
|
||||
|
||||
##### Step 9: Decode the Exponent
|
||||
|
||||
Extract bits 30–20 from r3:
|
||||
|
||||
```
|
||||
0x4045433B: 0 10000000100 01010100001100111011
|
||||
^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
|
||||
sign exponent mantissa (top 20)
|
||||
```
|
||||
|
||||
Exponent bits: `10000000100` = 2¹⁰ + 2² = 1024 + 4 = **1028**
|
||||
|
||||
$$\text{real exponent} = 1028 - 1023 = \mathbf{5}$$
|
||||
|
||||
##### Step 10: Decode the Mantissa
|
||||
|
||||
**High 20 bits** (r3 bits 19–0):
|
||||
```
|
||||
0 1 0 1 0 1 0 0 0 0 1 1 0 0 1 1 1 0 1 1
|
||||
```
|
||||
|
||||
**Low 32 bits** (all of r2 = `0x645A1CAC`):
|
||||
```
|
||||
0 1 1 0 0 1 0 0 0 1 0 1 1 0 1 0 0 0 0 1 1 1 0 0 1 0 1 0 1 1 0 0
|
||||
```
|
||||
|
||||
With the implied leading `1`:
|
||||
```
|
||||
1.0101010000110011101101100100010110100001110010101100
|
||||
```
|
||||
|
||||
##### Step 11: Reconstruct the Integer Part
|
||||
|
||||
$$1.0101010000110011..._2 \times 2^5$$
|
||||
|
||||
Shift the binary point 5 places right → `101010.1000011001110110...`
|
||||
|
||||
Integer part `101010`:
|
||||
|
||||
| Bit | Power | Value |
|
||||
|-----|-------|-------|
|
||||
| 1 | 2⁵ | 32 |
|
||||
| 0 | 2⁴ | 0 |
|
||||
| 1 | 2³ | 8 |
|
||||
| 0 | 2² | 0 |
|
||||
| 1 | 2¹ | 2 |
|
||||
| 0 | 2⁰ | 0 |
|
||||
|
||||
$$32 + 8 + 2 = \mathbf{42}$$
|
||||
|
||||
##### Step 12: Approximate the Fractional Part
|
||||
|
||||
The first few fractional bits `.10000110011...`:
|
||||
|
||||
| Bit | Power | Decimal |
|
||||
|------|--------|---------------|
|
||||
| 1 | 2⁻¹ | 0.5 |
|
||||
| 0 | 2⁻² | 0 |
|
||||
| 0 | 2⁻³ | 0 |
|
||||
| 0 | 2⁻⁴ | 0 |
|
||||
| 0 | 2⁻⁵ | 0 |
|
||||
| 1 | 2⁻⁶ | 0.015625 |
|
||||
| 1 | 2⁻⁷ | 0.0078125 |
|
||||
| 0 | 2⁻⁸ | 0 |
|
||||
| 0 | 2⁻⁹ | 0 |
|
||||
| 1 | 2⁻¹⁰ | 0.0009765625 |
|
||||
| 1 | 2⁻¹¹ | 0.00048828125 |
|
||||
|
||||
First 11 bits sum ≈ 0.5249. The remaining 36 fractional bits refine this to ≈ 0.52525.
|
||||
|
||||
$$42 + 0.52525 = \mathbf{42.52525} ✓$$
|
||||
|
||||
##### Step 13: Find the Format String
|
||||
|
||||
In the Listing view, locate:
|
||||
|
||||
```
|
||||
s_fav_num:_%lf_100034b0 ds "fav_num: %lf\r\n"
|
||||
```
|
||||
|
||||
Note the `%lf` format specifier — this program explicitly uses `double`, unlike the float program which used `%f`.
|
||||
|
||||
##### Step 14: Document Your Findings
|
||||
|
||||
| Item | Float (`42.5`) | Double (`42.52525`) |
|
||||
| ------------------------- | -------------------- | ------------------------ |
|
||||
| r2 (low word) | `0x00000000` | `0x645A1CAC` |
|
||||
| r3 (high word) | `0x40454000` | `0x4045433B` |
|
||||
| Low word is zero? | Yes | **No** |
|
||||
| Words to patch | 1 (r3 only) | **2 (both r2 and r3)** |
|
||||
| Format specifier | `%f` | `%lf` |
|
||||
| Assembly load instruction | `movs` + `ldr` | `ldrd` (load double) |
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should understand:
|
||||
- How the compiler loads a 64-bit double using `ldrd` (load register double)
|
||||
- Why `42.52525` requires non-zero data in both registers while `42.5` does not
|
||||
- How to decode a complex IEEE 754 double with a repeating binary fraction
|
||||
- The differences between float and double handling at the assembly level
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why does `42.5` have a zero low word but `42.52525` does not?
|
||||
|
||||
###### Question 2: The assembly uses `ldrd r4, r5, [r5, #0x0]` instead of two separate `ldr` instructions. What is the advantage?
|
||||
|
||||
###### Question 3: Both the float and double programs have the same exponent (stored as 1028, real exponent 5). Why?
|
||||
|
||||
###### Question 4: If you were patching this double, how many data constants would you need to modify compared to the float exercise?
|
||||
|
||||
#### Tips and Hints
|
||||
- Use Python to verify: `import struct; struct.pack('>d', 42.52525).hex()` gives `4045433b645a1cac`
|
||||
- The `ldrd` instruction always loads the lower-addressed word into the first register
|
||||
- A repeating binary fraction (like `0.52525`) can never be represented exactly — double precision uses the closest 52-bit approximation
|
||||
- Compare data addresses: the float binary has one `DAT_` constant; the double binary has two consecutive ones
|
||||
|
||||
#### Next Steps
|
||||
- Proceed to Exercise 4 to patch both register words
|
||||
- Compare the mantissa of `42.5` (clean: `010101 000...`) vs. `42.52525` (complex: `0101010000110011...`)
|
||||
- Think about what values would have a zero low word (hint: powers of 2, halves, quarters)
|
||||
|
||||
#### Additional Challenge
|
||||
Using the 52-bit mantissa `0101010000110011101101100100010110100001110010101100`, manually sum the first 20 fractional bits to see how close you get to `0.52525`. How many bits of precision does it take to get within 0.001 of the true value?
|
||||
@@ -0,0 +1,70 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 4 Solution: Patch the Double Binary — Changing 42.52525 to 99.99
|
||||
|
||||
#### Answers
|
||||
|
||||
##### IEEE 754 Encoding of 99.99
|
||||
|
||||
```
|
||||
Integer: 99 = 1100011₂
|
||||
Fractional: .99 ≈ .111111010111...₂ (repeating)
|
||||
Combined: 1100011.111111010111...₂
|
||||
Normalized: 1.100011111111010111...₂ × 2⁶
|
||||
|
||||
Sign: 0 (positive)
|
||||
Exponent: 6 + 1023 = 1029 = 10000000101₂
|
||||
Mantissa: 1000111111110101 11000010100011110101 11000010100011110...₂ (52 bits)
|
||||
|
||||
Full double: 0x4058FF5C28F5C28F
|
||||
```
|
||||
|
||||
Python verification: `struct.pack('>d', 99.99).hex()` → `4058ff5c28f5c28f` ✓
|
||||
|
||||
##### Patch Summary
|
||||
|
||||
| Register | Old Value (42.52525) | New Value (99.99) | Changed? |
|
||||
|----------|---------------------|-------------------|----------|
|
||||
| r2 | 0x645A1CAC | 0x28F5C28F | **Yes** |
|
||||
| r3 | 0x4045433B | 0x4058FF5C | **Yes** |
|
||||
|
||||
##### Ghidra Patches
|
||||
|
||||
**Low word (DAT_10000254):**
|
||||
```
|
||||
Before (little-endian): AC 1C 5A 64 → 0x645A1CAC
|
||||
After (little-endian): 8F C2 F5 28 → 0x28F5C28F
|
||||
```
|
||||
|
||||
**High word (DAT_10000258):**
|
||||
```
|
||||
Before (little-endian): 3B 43 45 40 → 0x4045433B
|
||||
After (little-endian): 5C FF 58 40 → 0x4058FF5C
|
||||
```
|
||||
|
||||
##### Serial Output
|
||||
|
||||
```
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
...
|
||||
```
|
||||
|
||||
#### Reflection Answers
|
||||
|
||||
1. **Why did both r2 and r3 change when patching 42.52525 → 99.99, but only r3 changed when patching 42.5 → 99.0?**
|
||||
Both 42.5 and 99.0 have "clean" fractional parts (0.5 and 0.0 respectively) that are exact in binary—they need very few mantissa bits, all fitting in the top 20 bits of r3. The low word (r2) remains `0x00000000` for both. In contrast, 42.52525 and 99.99 both have repeating binary fractions (0.52525 and 0.99 respectively) that require all 52 mantissa bits to approximate. Since the low 32 bits of the mantissa live in r2, changing from one repeating fraction to another necessarily changes both r2 and r3.
|
||||
|
||||
2. **The multiply-by-2 method for 0.99 produces a repeating pattern. What does this mean for the precision of the stored value?**
|
||||
It means 99.99 **cannot** be represented exactly as an IEEE 754 double. The binary fraction 0.111111010111... repeats indefinitely, but the mantissa only has 52 bits. The stored value is the closest 52-bit approximation, which is 99.98999999999999... (off by approximately 10⁻¹⁴). This is a fundamental limitation of binary floating-point: decimal fractions that aren't sums of negative powers of 2 always produce repeating binary expansions. The `printf` output rounds to `99.990000` because the default `%lf` precision (6 decimal places) hides the tiny error.
|
||||
|
||||
3. **If you wanted to patch the double to `100.0` instead of `99.99`, how many data constants would need to change?**
|
||||
**Both** would need to change—but for the opposite reason. Currently r2 = `0x645A1CAC` (non-zero). For 100.0: `struct.pack('>d', 100.0).hex()` = `4059000000000000`, so r3 = `0x40590000` and r2 = `0x00000000`. The r2 constant must be patched from `0x645A1CAC` to `0x00000000`, and r3 from `0x4045433B` to `0x40590000`. Even though the low word becomes zero, you still need to patch it because it was previously non-zero.
|
||||
|
||||
4. **Compare the Ghidra Listing for the float binary (Exercise 1) and the double binary (Exercise 3). How does the compiler load the double differently?**
|
||||
The float binary uses separate instructions: `movs r4, #0x0` (loads zero into r4 for the low word) and `ldr r5, [DAT_1000024c]` (loads the high word from a literal pool). The double binary uses a single `ldrd r4, r5, [r5, #0x0]` instruction that loads both words from consecutive memory addresses in one operation. The `ldrd` approach is more efficient (fewer instructions, single memory transaction) and is preferred when both words carry meaningful data. The float's approach works fine because one word is a trivially loaded zero.
|
||||
@@ -0,0 +1,217 @@
|
||||
# Embedded Systems Reverse Engineering
|
||||
[Repository](https://github.com/mytechnotalent/Embedded-Hacking)
|
||||
|
||||
## Week 5
|
||||
Integers and Floats in Embedded Systems: Debugging and Hacking Integers and Floats w/ Intermediate GPIO Output Assembler Analysis
|
||||
|
||||
### Non-Credit Practice Exercise 4: Patch the Double Binary — Changing 42.52525 to 99.99
|
||||
|
||||
#### Objective
|
||||
Calculate the IEEE 754 double-precision encoding of `99.99`, patch **both** register words in the double binary in Ghidra, export the patched binary, convert it to UF2 format, and flash it to the Pico 2 to verify the change.
|
||||
|
||||
#### Prerequisites
|
||||
- Completed Exercise 3 (double binary imported and analyzed in Ghidra)
|
||||
- Understanding of IEEE 754 double-precision encoding from Week 5 Parts 2.7 and 3.7
|
||||
- Knowledge of integer-to-binary conversion and the multiply-by-2 method for fractions
|
||||
- Python installed for UF2 conversion and verification
|
||||
- Raspberry Pi Pico 2 connected via USB
|
||||
|
||||
#### Task Description
|
||||
You will derive the IEEE 754 encoding of `99.99` step by step (integer part, fractional part, normalization, field extraction), patch both the low word and high word data constants in Ghidra, and verify on hardware that the serial output now prints `99.990000`. Unlike Exercise 2 where only one word changed, this exercise requires patching **both** registers.
|
||||
|
||||
#### Step-by-Step Instructions
|
||||
|
||||
##### Step 1: Convert the Integer Part (99) to Binary
|
||||
|
||||
Use repeated division by 2:
|
||||
|
||||
| Division | Quotient | Remainder |
|
||||
|----------|----------|-----------|
|
||||
| 99 ÷ 2 | 49 | **1** |
|
||||
| 49 ÷ 2 | 24 | **1** |
|
||||
| 24 ÷ 2 | 12 | **0** |
|
||||
| 12 ÷ 2 | 6 | **0** |
|
||||
| 6 ÷ 2 | 3 | **0** |
|
||||
| 3 ÷ 2 | 1 | **1** |
|
||||
| 1 ÷ 2 | 0 | **1** |
|
||||
|
||||
Read remainders bottom-to-top: $99_{10} = 1100011_2$
|
||||
|
||||
##### Step 2: Convert the Fractional Part (.99) to Binary
|
||||
|
||||
Use the multiply-by-2 method:
|
||||
|
||||
| Multiply | Result | Integer part | Remaining fraction |
|
||||
|----------------|--------|--------------|-------------------|
|
||||
| 0.99 × 2 | 1.98 | **1** | 0.98 |
|
||||
| 0.98 × 2 | 1.96 | **1** | 0.96 |
|
||||
| 0.96 × 2 | 1.92 | **1** | 0.92 |
|
||||
| 0.92 × 2 | 1.84 | **1** | 0.84 |
|
||||
| 0.84 × 2 | 1.68 | **1** | 0.68 |
|
||||
| 0.68 × 2 | 1.36 | **1** | 0.36 |
|
||||
| 0.36 × 2 | 0.72 | **0** | 0.72 |
|
||||
| 0.72 × 2 | 1.44 | **1** | 0.44 |
|
||||
| 0.44 × 2 | 0.88 | **0** | 0.88 |
|
||||
| 0.88 × 2 | 1.76 | **1** | 0.76 |
|
||||
| 0.76 × 2 | 1.52 | **1** | 0.52 |
|
||||
| 0.52 × 2 | 1.04 | **1** | 0.04 |
|
||||
| ... | ... | ... | *(continues — repeating fraction)* |
|
||||
|
||||
Reading the integer parts top-to-bottom: $0.99_{10} \approx 0.111111010111..._2$
|
||||
|
||||
This is a **repeating fraction** — it never terminates in binary.
|
||||
|
||||
##### Step 3: Combine Integer and Fractional Parts
|
||||
|
||||
$$99.99_{10} = 1100011.111111010111..._2$$
|
||||
|
||||
##### Step 4: Normalize to IEEE 754 Form
|
||||
|
||||
Move the binary point so there is exactly one `1` before it:
|
||||
|
||||
$$1100011.111111010111..._2 = 1.100011111111010111..._2 \times 2^6$$
|
||||
|
||||
We shifted the binary point 6 places left, so the exponent is **6**.
|
||||
|
||||
##### Step 5: Extract the IEEE 754 Fields
|
||||
|
||||
1. **Sign:** `0` (positive)
|
||||
2. **Exponent:** $6 + 1023 = 1029 = 10000000101_2$
|
||||
3. **Mantissa:** `1000111111110101110000101000111101011100001010001111...` (52 bits after the `1.`)
|
||||
4. **Full double:** `0x4058FF5C28F5C28F`
|
||||
|
||||
**Verify with Python:**
|
||||
```python
|
||||
>>> import struct
|
||||
>>> struct.pack('>d', 99.99).hex()
|
||||
'4058ff5c28f5c28f'
|
||||
```
|
||||
|
||||
##### Step 6: Split into Register Words
|
||||
|
||||
| Register | Old Value | New Value | Changed? |
|
||||
| -------- | ------------ | ------------ | -------- |
|
||||
| `r2` | `0x645A1CAC` | `0x28F5C28F` | **Yes** |
|
||||
| `r3` | `0x4045433B` | `0x4058FF5C` | **Yes** |
|
||||
|
||||
**Both registers change!** This is the key difference from Exercise 2 where only r3 changed.
|
||||
|
||||
##### Step 7: Locate the Data Constants in Ghidra
|
||||
|
||||
Open your Ghidra project from Exercise 3. In the Listing view, find the two data constants:
|
||||
|
||||
**Low word (loaded into r2):**
|
||||
```
|
||||
DAT_10000254
|
||||
10000254 ac 1c 5a 64 undefined4 645A1CACh
|
||||
```
|
||||
|
||||
**High word (loaded into r3):**
|
||||
```
|
||||
DAT_10000258
|
||||
10000258 3b 43 45 40 undefined4 4045433Bh
|
||||
```
|
||||
|
||||
##### Step 8: Patch the Low Word
|
||||
|
||||
1. Click on **Window** → **Bytes** to open the Bytes Editor
|
||||
2. Click the **Pencil Icon** to enable editing
|
||||
3. Navigate to address `10000254`
|
||||
4. The bytes read: `AC 1C 5A 64` (little-endian for `0x645A1CAC`)
|
||||
5. Change to: `8F C2 F5 28` (little-endian for `0x28F5C28F`)
|
||||
6. Press **Enter**
|
||||
|
||||
##### Step 9: Patch the High Word
|
||||
|
||||
1. Navigate to address `10000258`
|
||||
2. The bytes read: `3B 43 45 40` (little-endian for `0x4045433B`)
|
||||
3. Change to: `5C FF 58 40` (little-endian for `0x4058FF5C`)
|
||||
4. Press **Enter**
|
||||
|
||||
**Verify** in the Listing view:
|
||||
- `DAT_10000254` should show `28F5C28Fh`
|
||||
- `DAT_10000258` should show `4058FF5Ch`
|
||||
|
||||
Together: `0x4058FF5C28F5C28F` = `99.99` as a double ✓
|
||||
|
||||
##### Step 10: Export the Patched Binary
|
||||
|
||||
1. Click **File** → **Export Program**
|
||||
2. Set **Format** to **Raw Bytes**
|
||||
3. Navigate to your build directory
|
||||
4. Name the file: `0x0011_double-floating-point-data-type-h.bin`
|
||||
5. Click **OK**
|
||||
|
||||
##### Step 11: Convert to UF2 Format
|
||||
|
||||
Open a terminal:
|
||||
|
||||
```powershell
|
||||
cd Embedded-Hacking-main\0x0011_double-floating-point-data-type
|
||||
```
|
||||
|
||||
```powershell
|
||||
python ..\uf2conv.py build\0x0011_double-floating-point-data-type-h.bin --base 0x10000000 --family 0xe48bff59 --output build\hacked.uf2
|
||||
```
|
||||
|
||||
##### Step 12: Flash and Verify
|
||||
|
||||
1. Hold **BOOTSEL** and plug in your Pico 2
|
||||
2. Drag and drop `hacked.uf2` onto the RPI-RP2 drive
|
||||
3. Open your serial monitor
|
||||
|
||||
**Expected output:**
|
||||
|
||||
```
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
fav_num: 99.990000
|
||||
...
|
||||
```
|
||||
|
||||
🎉 **Success!** The value changed from `42.52525` to `99.99`!
|
||||
|
||||
#### Expected Output
|
||||
|
||||
After completing this exercise, you should:
|
||||
- See `fav_num: 99.990000` printing instead of `fav_num: 42.525250`
|
||||
- Have a patched binary file (`0x0011_double-floating-point-data-type-h.bin`)
|
||||
- Have a UF2 file (`hacked.uf2`)
|
||||
- Understand that patching doubles with repeating fractions requires modifying **both** register words
|
||||
|
||||
#### Questions for Reflection
|
||||
|
||||
###### Question 1: Why did both r2 and r3 change when patching 42.52525 → 99.99, but only r3 changed when patching 42.5 → 99.0?
|
||||
|
||||
###### Question 2: The multiply-by-2 method for 0.99 produces a repeating pattern. What does this mean for the precision of the stored value?
|
||||
|
||||
###### Question 3: If you wanted to patch the double to `100.0` instead of `99.99`, how many data constants would need to change?
|
||||
|
||||
###### Question 4: Compare the Ghidra Listing for the float binary (Exercise 1) and the double binary (Exercise 3). How does the compiler load the double differently?
|
||||
|
||||
#### Tips and Hints
|
||||
- Always verify your encoding with Python before patching
|
||||
- Little-endian byte order: `0x28F5C28F` is stored as `8F C2 F5 28` in memory
|
||||
- Use Ghidra's **Bytes** window (Window → Bytes) for precise hex editing
|
||||
- If `r2` was zero before and needs to be non-zero after, you need to patch the data constant — not the `movs r4, #0x0` instruction
|
||||
- The `ldrd` instruction loads r4 and r5 from two consecutive memory addresses — both must be correct
|
||||
|
||||
#### Next Steps
|
||||
- Review the complete patching workflow diagram in Week 5 Part 3.95
|
||||
- Try patching to `100.0` — since it has a zero low word, you'll need to change `r2` from non-zero to zero
|
||||
- Attempt the practice exercises at the end of Week 5
|
||||
|
||||
#### Additional Challenge
|
||||
Patch the double to `3.14159265358979` (pi). This requires extreme precision in all 52 mantissa bits. Use Python to get the exact encoding, then patch both words. Verify the output prints at least 6 correct decimal places. What happens to the precision if you only patch the high word and leave the low word as `0x645A1CAC`?
|
||||
|
||||
#### Verification Checklist
|
||||
|
||||
Before moving on, confirm:
|
||||
- [ ] Serial output shows `fav_num: 99.990000`
|
||||
- [ ] Both data constants were patched (low word and high word)
|
||||
- [ ] You can derive the IEEE 754 encoding of `99.99` from scratch
|
||||
- [ ] You understand why messy fractions require patching both register words
|
||||
- [ ] You can explain the difference between the float and double patching workflows
|
||||
- [ ] You successfully converted and flashed the UF2
|
||||
|
||||
**Congratulations!** You've completed all Week 5 exercises and mastered floating-point analysis, IEEE 754 decoding, and double-precision binary patching!
|
||||
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Background grid decoration -->
|
||||
<g opacity="0.06">
|
||||
<line x1="0" y1="100" x2="1200" y2="100" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="200" x2="1200" y2="200" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="300" x2="1200" y2="300" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="400" x2="1200" y2="400" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="500" x2="1200" y2="500" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="600" x2="1200" y2="600" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="0" y1="700" x2="1200" y2="700" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="200" y1="0" x2="200" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="400" y1="0" x2="400" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="600" y1="0" x2="600" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="800" y1="0" x2="800" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
<line x1="1000" y1="0" x2="1000" y2="800" stroke="#00ff41" stroke-width="1"/>
|
||||
</g>
|
||||
|
||||
<!-- Hex rain decoration -->
|
||||
<g opacity="0.04" font-family="'Courier New',monospace" font-size="14" fill="#00ff41">
|
||||
<text x="50" y="80">4F 70 65 6E 4F 43 44</text>
|
||||
<text x="900" y="120">10 00 02 34 08 B5 01</text>
|
||||
<text x="150" y="180">47 44 42 20 52 45 56</text>
|
||||
<text x="800" y="240">20 08 20 00 FF AA 00</text>
|
||||
<text x="80" y="350">52 50 32 33 35 30 00</text>
|
||||
<text x="950" y="380">0A 0A 0F 12 12 1A 1A</text>
|
||||
<text x="100" y="520">41 52 4D 76 38 2D 4D</text>
|
||||
<text x="870" y="560">00 FF 41 00 D4 FF 88</text>
|
||||
<text x="60" y="680">47 48 49 44 52 41 00</text>
|
||||
<text x="920" y="720">FF 00 40 C0 C0 C0 00</text>
|
||||
</g>
|
||||
|
||||
<!-- Corner accents -->
|
||||
<polyline points="30,30 30,80 80,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,30 1170,80 1120,80" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="30,770 30,720 80,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
<polyline points="1170,770 1170,720 1120,720" fill="none" stroke="#00ff41" stroke-width="2" opacity="0.3"/>
|
||||
|
||||
<!-- Top accent line -->
|
||||
<rect x="100" y="140" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- Course Title -->
|
||||
<text x="600" y="210" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Embedded Systems</text>
|
||||
<text x="600" y="278" text-anchor="middle" font-family="'Courier New',monospace" font-size="56" font-weight="bold" fill="#00ff41">Reverse Engineering</text>
|
||||
|
||||
<!-- Divider -->
|
||||
<rect x="300" y="310" width="600" height="2" fill="#00d4ff" opacity="0.6"/>
|
||||
|
||||
<!-- Week Number -->
|
||||
<text x="600" y="380" text-anchor="middle" font-family="'Courier New',monospace" font-size="42" font-weight="bold" fill="#00d4ff">// WEEK 05</text>
|
||||
|
||||
<!-- Week Topic -->
|
||||
<text x="600" y="440" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Integers and Floats in Embedded Systems:</text>
|
||||
<text x="600" y="478" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">Debugging and Hacking Integers and Floats</text>
|
||||
<text x="600" y="516" text-anchor="middle" font-family="'Courier New',monospace" font-size="28" fill="#c0c0c0">w/ Intermediate GPIO Output Analysis</text>
|
||||
|
||||
<!-- Bottom accent line -->
|
||||
<rect x="100" y="570" width="1000" height="2" fill="#00ff41" opacity="0.4"/>
|
||||
|
||||
<!-- University -->
|
||||
<text x="600" y="635" text-anchor="middle" font-family="'Courier New',monospace" font-size="36" font-weight="bold" fill="#ffaa00">George Mason University</text>
|
||||
|
||||
<!-- Bottom badge -->
|
||||
<rect x="400" y="670" width="400" height="40" rx="20" fill="none" stroke="#00ff41" stroke-width="1.5" opacity="0.5"/>
|
||||
<text x="600" y="697" text-anchor="middle" font-family="'Courier New',monospace" font-size="20" fill="#00ff41" opacity="0.7">RP2350 // ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,77 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Integer Data Types</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Fixed-Size Types for Embedded Systems</text>
|
||||
|
||||
<!-- uint8_t -->
|
||||
<rect x="40" y="110" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">uint8_t</text>
|
||||
<text x="60" y="185" class="grn">Unsigned 8-bit</text>
|
||||
<text x="360" y="185" class="txt">1 byte</text>
|
||||
<text x="60" y="218" class="txt">Range:</text>
|
||||
<text x="200" y="218" class="amb">0 to 255</text>
|
||||
<text x="60" y="245" class="dim">Ages, counts, always positive</text>
|
||||
|
||||
<!-- int8_t -->
|
||||
<rect x="620" y="110" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">int8_t</text>
|
||||
<text x="640" y="185" class="red">Signed 8-bit</text>
|
||||
<text x="940" y="185" class="txt">1 byte</text>
|
||||
<text x="640" y="218" class="txt">Range:</text>
|
||||
<text x="780" y="218" class="amb">-128 to 127</text>
|
||||
<text x="640" y="245" class="dim">Temperature, can be negative</text>
|
||||
|
||||
<!-- uint16_t -->
|
||||
<rect x="40" y="285" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="310" y="323" text-anchor="middle" class="sub">uint16_t</text>
|
||||
<text x="60" y="360" class="grn">Unsigned 16-bit</text>
|
||||
<text x="360" y="360" class="txt">2 bytes</text>
|
||||
<text x="60" y="393" class="txt">Range:</text>
|
||||
<text x="200" y="393" class="amb">0 to 65,535</text>
|
||||
<text x="60" y="420" class="dim">Sensor readings, medium values</text>
|
||||
|
||||
<!-- uint32_t -->
|
||||
<rect x="620" y="285" width="540" height="155" rx="8" class="pnl"/>
|
||||
<text x="890" y="323" text-anchor="middle" class="sub">uint32_t</text>
|
||||
<text x="640" y="360" class="cyn">Unsigned 32-bit</text>
|
||||
<text x="940" y="360" class="txt">4 bytes</text>
|
||||
<text x="640" y="393" class="txt">Range:</text>
|
||||
<text x="780" y="393" class="amb">0 to ~4 billion</text>
|
||||
<text x="640" y="420" class="dim">Addresses, timestamps</text>
|
||||
|
||||
<!-- Code Example -->
|
||||
<rect x="40" y="460" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="498" text-anchor="middle" class="sub">Code Example</text>
|
||||
<rect x="60" y="515" width="1080" height="80" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="548" class="amb">uint8_t age = 43;</text>
|
||||
<text x="500" y="548" class="dim">// unsigned, 0-255</text>
|
||||
<text x="80" y="578" class="red">int8_t range = -42;</text>
|
||||
<text x="500" y="578" class="dim">// signed, -128 to 127</text>
|
||||
|
||||
<!-- Key Insight -->
|
||||
<rect x="40" y="630" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="668" text-anchor="middle" class="sub">Key Insight</text>
|
||||
<text x="60" y="700" class="txt">The</text>
|
||||
<text x="120" y="700" class="grn">u</text>
|
||||
<text x="145" y="700" class="txt">prefix means</text>
|
||||
<text x="370" y="700" class="cyn">unsigned</text>
|
||||
<text x="540" y="700" class="txt">(no negatives)</text>
|
||||
<text x="60" y="730" class="txt">Without</text>
|
||||
<text x="210" y="730" class="grn">u</text>
|
||||
<text x="235" y="730" class="txt">= signed (allows negatives)</text>
|
||||
<text x="60" y="760" class="dim">Choose the smallest type that fits your data</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,79 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Two's Complement</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">How Negative Numbers are Stored</text>
|
||||
|
||||
<!-- Step-by-step: -42 encoding -->
|
||||
<rect x="40" y="110" width="1120" height="280" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Encoding -42 as int8_t</text>
|
||||
|
||||
<rect x="60" y="170" width="340" height="90" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="230" y="200" text-anchor="middle" class="cyn">Step 1: Start</text>
|
||||
<text x="230" y="235" text-anchor="middle" class="txt">42 = 0x2A</text>
|
||||
|
||||
<rect x="420" y="170" width="340" height="90" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="590" y="200" text-anchor="middle" class="amb">Step 2: Flip</text>
|
||||
<text x="590" y="235" text-anchor="middle" class="txt">~0x2A = 0xD5</text>
|
||||
|
||||
<rect x="780" y="170" width="340" height="90" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="950" y="200" text-anchor="middle" class="grn">Step 3: Add 1</text>
|
||||
<text x="950" y="235" text-anchor="middle" class="txt">0xD5+1 = 0xD6</text>
|
||||
|
||||
<text x="60" y="300" class="txt">Binary:</text>
|
||||
<text x="200" y="300" class="grn">00101010</text>
|
||||
<text x="400" y="300" class="amb">-></text>
|
||||
<text x="450" y="300" class="amb">11010101</text>
|
||||
<text x="650" y="300" class="grn">-></text>
|
||||
<text x="700" y="300" class="red">11010110</text>
|
||||
|
||||
<text x="60" y="340" class="dim">Result: -42 stored as 0xD6 in memory</text>
|
||||
<text x="60" y="368" class="dim">Top bit = 1 means negative</text>
|
||||
|
||||
<!-- Comparison Table -->
|
||||
<rect x="40" y="410" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="600" y="448" text-anchor="middle" class="sub">Signed vs Unsigned: Same Bits!</text>
|
||||
|
||||
<text x="80" y="488" class="cyn">Hex</text>
|
||||
<text x="280" y="488" class="cyn">Binary</text>
|
||||
<text x="580" y="488" class="cyn">uint8_t</text>
|
||||
<text x="800" y="488" class="cyn">int8_t</text>
|
||||
|
||||
<line x1="60" y1="500" x2="1140" y2="500" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<text x="80" y="530" class="amb">0x2A</text>
|
||||
<text x="280" y="530" class="txt">00101010</text>
|
||||
<text x="580" y="530" class="grn">42</text>
|
||||
<text x="800" y="530" class="grn">42</text>
|
||||
|
||||
<text x="80" y="565" class="amb">0xD6</text>
|
||||
<text x="280" y="565" class="txt">11010110</text>
|
||||
<text x="580" y="565" class="grn">214</text>
|
||||
<text x="800" y="565" class="red">-42</text>
|
||||
|
||||
<text x="60" y="590" class="dim">Same byte 0xD6 = 214 unsigned, -42 signed</text>
|
||||
|
||||
<!-- GDB Verification -->
|
||||
<rect x="40" y="630" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="668" text-anchor="middle" class="sub">GDB Verification</text>
|
||||
|
||||
<rect x="60" y="688" width="1080" height="75" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="718" class="grn">(gdb)</text>
|
||||
<text x="180" y="718" class="txt">x/1xb &range</text>
|
||||
<text x="80" y="745" class="amb">0x200003e7:</text>
|
||||
<text x="300" y="745" class="red">0xd6</text>
|
||||
<text x="440" y="745" class="dim">// -42 in memory</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,75 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Inline Assembly GPIO</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Direct Hardware Control via ASM</text>
|
||||
|
||||
<!-- Init Loop -->
|
||||
<rect x="40" y="110" width="1120" height="310" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">GPIO Init Loop (pins 16-19)</text>
|
||||
|
||||
<rect x="60" y="168" width="340" height="120" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="230" y="198" text-anchor="middle" class="cyn">1. Config Pad</text>
|
||||
<text x="80" y="228" class="dim">PADS_BANK0</text>
|
||||
<text x="80" y="255" class="dim">Clear OD+ISO, set IE</text>
|
||||
<text x="80" y="275" class="amb">0x40038000</text>
|
||||
|
||||
<rect x="420" y="168" width="340" height="120" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="590" y="198" text-anchor="middle" class="amb">2. Set Function</text>
|
||||
<text x="440" y="228" class="dim">IO_BANK0</text>
|
||||
<text x="440" y="255" class="dim">FUNCSEL = 5 (SIO)</text>
|
||||
<text x="440" y="275" class="grn">0x40028004</text>
|
||||
|
||||
<rect x="780" y="168" width="340" height="120" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="950" y="198" text-anchor="middle" class="grn">3. Enable Out</text>
|
||||
<text x="800" y="228" class="dim">GPIO Coprocessor</text>
|
||||
<text x="800" y="255" class="dim">mcrr p0,#4,r4,r5,c4</text>
|
||||
<text x="800" y="275" class="red">Output Enable</text>
|
||||
|
||||
<text x="60" y="330" class="txt">Loop: r0 = 16 to 19</text>
|
||||
<text x="400" y="330" class="dim">Red, Green, Blue, Yellow LEDs</text>
|
||||
<text x="60" y="398" class="dim">Each pin: pad config + function select + OE</text>
|
||||
|
||||
<!-- Blink Loop -->
|
||||
<rect x="40" y="440" width="540" height="190" rx="8" class="pnl"/>
|
||||
<text x="310" y="478" text-anchor="middle" class="sub">Blink Loop</text>
|
||||
|
||||
<rect x="60" y="498" width="500" height="40" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="525" class="grn">mcrr p0,#4,r4,r5,c0</text>
|
||||
|
||||
<text x="60" y="565" class="txt">r4 = pin, r5 = value</text>
|
||||
<text x="60" y="595" class="dim">c0 = output value register</text>
|
||||
<text x="60" y="615" class="dim">r5=1 ON, r5=0 OFF</text>
|
||||
|
||||
<!-- Pin Cycling -->
|
||||
<rect x="620" y="440" width="540" height="190" rx="8" class="pnl"/>
|
||||
<text x="890" y="478" text-anchor="middle" class="sub">Pin Cycling</text>
|
||||
|
||||
<rect x="640" y="498" width="500" height="75" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="660" y="528" class="amb">pin++;</text>
|
||||
<text x="660" y="558" class="txt">if (pin > 18) pin=16;</text>
|
||||
|
||||
<text x="640" y="600" class="dim">Cycles: 16 -> 17 -> 18 -> 16</text>
|
||||
<text x="640" y="620" class="dim">Red -> Green -> Blue -> repeat</text>
|
||||
|
||||
<!-- Key Takeaway -->
|
||||
<rect x="40" y="650" width="1120" height="130" rx="8" class="pnl"/>
|
||||
<text x="600" y="688" text-anchor="middle" class="sub">Why Inline Assembly?</text>
|
||||
<text x="60" y="722" class="txt">gpio_put(16,1) calls</text>
|
||||
<text x="390" y="722" class="grn">mcrr</text>
|
||||
<text x="470" y="722" class="txt">underneath</text>
|
||||
<text x="60" y="752" class="dim">Inline ASM shows what the SDK does at hardware level</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,76 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">IEEE 754 Float</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">32-bit Single Precision Encoding</text>
|
||||
|
||||
<!-- Field Layout -->
|
||||
<rect x="40" y="110" width="1120" height="150" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Float Bit Layout (32 bits)</text>
|
||||
|
||||
<rect x="60" y="168" width="80" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="2"/>
|
||||
<text x="100" y="200" text-anchor="middle" class="red">S</text>
|
||||
|
||||
<rect x="150" y="168" width="350" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="325" y="200" text-anchor="middle" class="amb">Exponent (8 bits)</text>
|
||||
|
||||
<rect x="510" y="168" width="630" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="2"/>
|
||||
<text x="825" y="200" text-anchor="middle" class="grn">Mantissa (23 bits)</text>
|
||||
|
||||
<text x="100" y="240" text-anchor="middle" class="dim">1 bit</text>
|
||||
<text x="325" y="240" text-anchor="middle" class="dim">bias = 127</text>
|
||||
<text x="825" y="240" text-anchor="middle" class="dim">implicit leading 1</text>
|
||||
|
||||
<!-- Formula -->
|
||||
<rect x="40" y="280" width="1120" height="80" rx="8" class="pnl"/>
|
||||
<text x="600" y="330" text-anchor="middle" class="txt">Value = (-1)^sign x 2^(exp-127) x 1.mantissa</text>
|
||||
|
||||
<!-- Example: 42.5 -->
|
||||
<rect x="40" y="380" width="1120" height="240" rx="8" class="pnl"/>
|
||||
<text x="600" y="418" text-anchor="middle" class="sub">Example: 42.5</text>
|
||||
|
||||
<text x="60" y="458" class="red">Sign: 0</text>
|
||||
<text x="300" y="458" class="dim">positive</text>
|
||||
|
||||
<text x="60" y="493" class="amb">Exponent: 10000100</text>
|
||||
<text x="430" y="493" class="dim">= 132</text>
|
||||
<text x="530" y="493" class="txt">132-127 = 5</text>
|
||||
|
||||
<text x="60" y="528" class="grn">Mantissa: 01010100...0</text>
|
||||
<text x="440" y="528" class="dim">= 1.010101</text>
|
||||
|
||||
<text x="60" y="563" class="txt">1.010101 x 2^5</text>
|
||||
<text x="350" y="563" class="grn">=</text>
|
||||
<text x="385" y="563" class="txt">101010.1</text>
|
||||
<text x="560" y="563" class="grn">=</text>
|
||||
<text x="595" y="563" class="amb">42.5</text>
|
||||
|
||||
<text x="60" y="598" class="dim">Hex: 0x422A0000</text>
|
||||
|
||||
<!-- Float vs Integer -->
|
||||
<rect x="40" y="640" width="1120" height="140" rx="8" class="pnl"/>
|
||||
<text x="600" y="678" text-anchor="middle" class="sub">Float vs Integer</text>
|
||||
|
||||
<text x="80" y="712" class="cyn">Integer</text>
|
||||
<text x="240" y="712" class="txt">exact, 1 byte</text>
|
||||
<text x="500" y="712" class="dim">%d</text>
|
||||
|
||||
<text x="620" y="712" class="amb">Float</text>
|
||||
<text x="760" y="712" class="txt">~7 digits, 4B</text>
|
||||
<text x="1020" y="712" class="dim">%f</text>
|
||||
|
||||
<text x="60" y="748" class="dim">Floats sacrifice exactness for huge range</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,76 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Float in Ghidra</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Analyzing 42.5 in the Binary</text>
|
||||
|
||||
<!-- Decompiled View -->
|
||||
<rect x="40" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Decompiled main()</text>
|
||||
|
||||
<rect x="60" y="168" width="500" height="205" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="198" class="txt">int main(void) {</text>
|
||||
<text x="100" y="228" class="cyn">stdio_init_all();</text>
|
||||
<text x="100" y="258" class="txt">uVar1 = DAT_1000024c;</text>
|
||||
<text x="100" y="288" class="txt">do {</text>
|
||||
<text x="120" y="318" class="amb">printf(fmt,0,uVar1);</text>
|
||||
<text x="100" y="348" class="txt">} while(true);</text>
|
||||
|
||||
<!-- Key Discovery -->
|
||||
<rect x="620" y="110" width="540" height="280" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Key Discovery</text>
|
||||
|
||||
<text x="640" y="190" class="txt">printf with %f always</text>
|
||||
<text x="640" y="220" class="txt">receives a</text>
|
||||
<text x="830" y="220" class="red">double</text>
|
||||
<text x="960" y="220" class="txt">(64-bit)</text>
|
||||
|
||||
<text x="640" y="260" class="dim">C promotes float to double</text>
|
||||
<text x="640" y="290" class="dim">for variadic functions!</text>
|
||||
|
||||
<rect x="640" y="310" width="500" height="60" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="2"/>
|
||||
<text x="890" y="348" text-anchor="middle" class="amb">42.5 sent as double</text>
|
||||
|
||||
<!-- Register Pair -->
|
||||
<rect x="40" y="410" width="1120" height="180" rx="8" class="pnl"/>
|
||||
<text x="600" y="448" text-anchor="middle" class="sub">Register Pair r2:r3</text>
|
||||
|
||||
<rect x="60" y="470" width="520" height="50" rx="4" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="80" y="502" class="cyn">r2 (low):</text>
|
||||
<text x="260" y="502" class="grn">0x00000000</text>
|
||||
|
||||
<rect x="600" y="470" width="540" height="50" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="620" y="502" class="amb">r3 (high):</text>
|
||||
<text x="810" y="502" class="grn">0x40454000</text>
|
||||
|
||||
<text x="60" y="565" class="txt">Combined: 0x4045400000000000</text>
|
||||
<text x="680" y="565" class="grn">= 42.5</text>
|
||||
|
||||
<!-- Assembly -->
|
||||
<rect x="40" y="610" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<text x="600" y="648" text-anchor="middle" class="sub">Assembly View</text>
|
||||
|
||||
<rect x="60" y="668" width="1080" height="90" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="80" y="698" class="grn">1000023a</text>
|
||||
<text x="260" y="698" class="amb">00 24</text>
|
||||
<text x="380" y="698" class="txt">movs r4, #0x0</text>
|
||||
<text x="640" y="698" class="dim">// r2 = 0</text>
|
||||
|
||||
<text x="80" y="733" class="grn">1000023c</text>
|
||||
<text x="260" y="733" class="amb">03 4d</text>
|
||||
<text x="380" y="733" class="txt">ldr r5,[DAT...]</text>
|
||||
<text x="640" y="733" class="dim">// r3 = 0x40454000</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,87 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Patching Float</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Changing 42.5 to 99.0 in Ghidra</text>
|
||||
|
||||
<!-- Calculate New Encoding -->
|
||||
<rect x="40" y="110" width="1120" height="230" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">Calculate 99.0 as Double</text>
|
||||
|
||||
<text x="60" y="188" class="txt">99 decimal =</text>
|
||||
<text x="290" y="188" class="grn">1100011</text>
|
||||
<text x="440" y="188" class="txt">binary</text>
|
||||
|
||||
<text x="60" y="223" class="txt">Normalize:</text>
|
||||
<text x="250" y="223" class="amb">1.100011 x 2^6</text>
|
||||
|
||||
<text x="60" y="258" class="red">Sign:</text>
|
||||
<text x="160" y="258" class="txt">0</text>
|
||||
<text x="300" y="258" class="amb">Exp:</text>
|
||||
<text x="380" y="258" class="txt">6+1023 = 1029</text>
|
||||
|
||||
<text x="60" y="293" class="grn">Mantissa:</text>
|
||||
<text x="240" y="293" class="txt">100011000...0</text>
|
||||
|
||||
<text x="60" y="328" class="dim">Full double: 0x4058C00000000000</text>
|
||||
|
||||
<!-- Before vs After -->
|
||||
<rect x="40" y="360" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="310" y="398" text-anchor="middle" class="sub">Before (42.5)</text>
|
||||
|
||||
<rect x="60" y="418" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="450" class="cyn">r2:</text>
|
||||
<text x="160" y="450" class="red">0x00000000</text>
|
||||
|
||||
<rect x="60" y="478" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="510" class="cyn">r3:</text>
|
||||
<text x="160" y="510" class="red">0x40454000</text>
|
||||
|
||||
<text x="60" y="548" class="dim">Output: fav_num: 42.500000</text>
|
||||
|
||||
<rect x="620" y="360" width="540" height="200" rx="8" class="pnl"/>
|
||||
<text x="890" y="398" text-anchor="middle" class="sub">After (99.0)</text>
|
||||
|
||||
<rect x="640" y="418" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="450" class="cyn">r2:</text>
|
||||
<text x="740" y="450" class="grn">0x00000000</text>
|
||||
<text x="960" y="450" class="dim">same!</text>
|
||||
|
||||
<rect x="640" y="478" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="510" class="cyn">r3:</text>
|
||||
<text x="740" y="510" class="grn">0x4058C000</text>
|
||||
<text x="960" y="510" class="amb">changed</text>
|
||||
|
||||
<text x="640" y="548" class="dim">Output: fav_num: 99.000000</text>
|
||||
|
||||
<!-- Patch Steps -->
|
||||
<rect x="40" y="580" width="1120" height="200" rx="8" class="pnl"/>
|
||||
<text x="600" y="618" text-anchor="middle" class="sub">Patch in Ghidra</text>
|
||||
|
||||
<rect x="60" y="640" width="340" height="65" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="230" y="668" text-anchor="middle" class="cyn">1. Window: Bytes</text>
|
||||
<text x="230" y="690" text-anchor="middle" class="dim">Open byte editor</text>
|
||||
|
||||
<rect x="420" y="640" width="340" height="65" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="590" y="668" text-anchor="middle" class="amb">2. Find 00404540</text>
|
||||
<text x="590" y="690" text-anchor="middle" class="dim">High word of 42.5</text>
|
||||
|
||||
<rect x="780" y="640" width="340" height="65" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="950" y="668" text-anchor="middle" class="grn">3. Patch 00C05840</text>
|
||||
<text x="950" y="690" text-anchor="middle" class="dim">High word of 99.0</text>
|
||||
|
||||
<text x="60" y="748" class="dim">Only one word to patch (low word is 0)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,75 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Double Precision</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">IEEE 754 64-bit Floating Point</text>
|
||||
|
||||
<!-- Bit Layout -->
|
||||
<rect x="40" y="110" width="1120" height="175" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">64-Bit Layout</text>
|
||||
|
||||
<rect x="60" y="168" width="80" height="72" rx="4" fill="#ff0040" stroke="#ff0040" stroke-width="1" opacity="0.3"/>
|
||||
<text x="100" y="197" text-anchor="middle" class="red">Sign</text>
|
||||
<text x="100" y="218" text-anchor="middle" class="dim">1 bit</text>
|
||||
|
||||
<rect x="160" y="168" width="300" height="72" rx="4" fill="#ffaa00" stroke="#ffaa00" stroke-width="1" opacity="0.2"/>
|
||||
<text x="310" y="197" text-anchor="middle" class="amb">Exponent</text>
|
||||
<text x="310" y="218" text-anchor="middle" class="dim">11 bits (bias 1023)</text>
|
||||
|
||||
<rect x="480" y="168" width="660" height="72" rx="4" fill="#00ff41" stroke="#00ff41" stroke-width="1" opacity="0.2"/>
|
||||
<text x="810" y="197" text-anchor="middle" class="grn">Mantissa (Fraction)</text>
|
||||
<text x="810" y="218" text-anchor="middle" class="dim">52 bits</text>
|
||||
|
||||
<text x="60" y="272" class="dim">Formula: (-1)^S x 1.Mantissa x 2^(Exp-1023)</text>
|
||||
|
||||
<!-- 42.52525 Example -->
|
||||
<rect x="40" y="305" width="1120" height="190" rx="8" class="pnl"/>
|
||||
<text x="600" y="340" text-anchor="middle" class="sub">Encoding 42.52525</text>
|
||||
|
||||
<text x="60" y="378" class="cyn">Sign:</text>
|
||||
<text x="170" y="378" class="txt">0 (positive)</text>
|
||||
|
||||
<text x="60" y="408" class="amb">Exponent:</text>
|
||||
<text x="230" y="408" class="txt">5 + 1023 = 1028</text>
|
||||
<text x="530" y="408" class="dim">= 0x404 (hex)</text>
|
||||
|
||||
<text x="60" y="438" class="grn">Mantissa:</text>
|
||||
<text x="230" y="438" class="txt">0101010000110011...</text>
|
||||
|
||||
<text x="60" y="468" class="dim">Full 64-bit hex:</text>
|
||||
<text x="310" y="468" class="grn">0x4045433B645A1CAC</text>
|
||||
|
||||
<!-- Float vs Double Comparison -->
|
||||
<rect x="40" y="515" width="540" height="265" rx="8" class="pnl"/>
|
||||
<text x="310" y="553" text-anchor="middle" class="sub">Float (32-bit)</text>
|
||||
|
||||
<text x="60" y="590" class="txt">Size: 4 bytes</text>
|
||||
<text x="60" y="620" class="txt">Exp: 8 bits</text>
|
||||
<text x="60" y="650" class="txt">Mantissa: 23 bits</text>
|
||||
<text x="60" y="680" class="txt">Precision: ~7 digits</text>
|
||||
<text x="60" y="710" class="txt">Bias: 127</text>
|
||||
<text x="60" y="740" class="dim">1 register (ARM)</text>
|
||||
|
||||
<rect x="620" y="515" width="540" height="265" rx="8" class="pnl"/>
|
||||
<text x="890" y="553" text-anchor="middle" class="sub">Double (64-bit)</text>
|
||||
|
||||
<text x="640" y="590" class="grn">Size: 8 bytes</text>
|
||||
<text x="640" y="620" class="grn">Exp: 11 bits</text>
|
||||
<text x="640" y="650" class="grn">Mantissa: 52 bits</text>
|
||||
<text x="640" y="680" class="grn">Precision: ~15 digits</text>
|
||||
<text x="640" y="710" class="grn">Bias: 1023</text>
|
||||
<text x="640" y="740" class="dim">2 registers (r2:r3)</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,71 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Double in Ghidra</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Analyzing 42.52525 in memory</text>
|
||||
|
||||
<!-- Decompiled View -->
|
||||
<rect x="40" y="110" width="540" height="230" rx="8" class="pnl"/>
|
||||
<text x="310" y="148" text-anchor="middle" class="sub">Decompiled main()</text>
|
||||
|
||||
<rect x="60" y="168" width="500" height="150" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="198" class="cyn">int main(void) {</text>
|
||||
<text x="110" y="228" class="txt">double fav_num</text>
|
||||
<text x="110" y="258" class="amb"> = 42.52525;</text>
|
||||
<text x="110" y="288" class="txt">stdio_init_all();</text>
|
||||
<text x="80" y="308" class="cyn">}</text>
|
||||
|
||||
<!-- Key Difference from Float -->
|
||||
<rect x="620" y="110" width="540" height="230" rx="8" class="pnl"/>
|
||||
<text x="890" y="148" text-anchor="middle" class="sub">Key Difference</text>
|
||||
|
||||
<text x="640" y="188" class="txt">Float (42.5):</text>
|
||||
<text x="640" y="218" class="dim">r2 = 0x00000000 (zero!)</text>
|
||||
<text x="640" y="248" class="dim">r3 = 0x40454000</text>
|
||||
|
||||
<text x="640" y="288" class="grn">Double (42.52525):</text>
|
||||
<text x="640" y="318" class="amb">r2 = 0x645A1CAC (non-zero!)</text>
|
||||
|
||||
<!-- Register Pair -->
|
||||
<rect x="40" y="360" width="1120" height="170" rx="8" class="pnl"/>
|
||||
<text x="600" y="398" text-anchor="middle" class="sub">Register Pair r2:r3</text>
|
||||
|
||||
<rect x="60" y="418" width="520" height="55" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="80" y="452" class="amb">r3 (HIGH):</text>
|
||||
<text x="280" y="452" class="grn">0x4045433B</text>
|
||||
|
||||
<rect x="620" y="418" width="520" height="55" rx="4" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="640" y="452" class="amb">r2 (LOW):</text>
|
||||
<text x="830" y="452" class="grn">0x645A1CAC</text>
|
||||
|
||||
<text x="60" y="510" class="dim">Combined: 0x4045433B645A1CAC = 42.52525</text>
|
||||
|
||||
<!-- Assembly View -->
|
||||
<rect x="40" y="550" width="1120" height="230" rx="8" class="pnl"/>
|
||||
<text x="600" y="588" text-anchor="middle" class="sub">Assembly (ldrd)</text>
|
||||
|
||||
<rect x="60" y="608" width="700" height="140" rx="4" fill="#0a0a0f" stroke="#1a1a2e" stroke-width="1"/>
|
||||
<text x="80" y="638" class="cyn">ldrd r2,r3,[PC,#0x10]</text>
|
||||
<text x="80" y="668" class="dim">; Loads BOTH words at once</text>
|
||||
<text x="80" y="698" class="dim">; r2 gets low word</text>
|
||||
<text x="80" y="728" class="dim">; r3 gets high word</text>
|
||||
|
||||
<rect x="780" y="608" width="360" height="140" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="800" y="648" class="grn">ldrd = Load</text>
|
||||
<text x="800" y="678" class="grn">Register</text>
|
||||
<text x="800" y="708" class="grn">Doubleword</text>
|
||||
<text x="800" y="738" class="dim">ARM Cortex-M33</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,88 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">Patching Double</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Changing 42.52525 to 99.99</text>
|
||||
|
||||
<!-- New Encoding Calc -->
|
||||
<rect x="40" y="110" width="1120" height="160" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">99.99 as IEEE 754 Double</text>
|
||||
|
||||
<text x="60" y="188" class="cyn">Sign:</text>
|
||||
<text x="160" y="188" class="txt">0</text>
|
||||
<text x="300" y="188" class="amb">Exp:</text>
|
||||
<text x="390" y="188" class="txt">6 + 1023 = 1029</text>
|
||||
|
||||
<text x="60" y="223" class="grn">Result:</text>
|
||||
<text x="200" y="223" class="grn">0x4058FF5C28F5C28F</text>
|
||||
|
||||
<text x="60" y="253" class="dim">r3 (HIGH) = 0x4058FF5C</text>
|
||||
<text x="540" y="253" class="dim">r2 (LOW) = 0x28F5C28F</text>
|
||||
|
||||
<!-- Before vs After -->
|
||||
<rect x="40" y="290" width="540" height="240" rx="8" class="pnl"/>
|
||||
<text x="310" y="328" text-anchor="middle" class="sub">Before (42.52525)</text>
|
||||
|
||||
<rect x="60" y="348" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="380" class="cyn">r3:</text>
|
||||
<text x="150" y="380" class="red">0x4045433B</text>
|
||||
|
||||
<rect x="60" y="408" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="80" y="440" class="cyn">r2:</text>
|
||||
<text x="150" y="440" class="red">0x645A1CAC</text>
|
||||
|
||||
<text x="60" y="485" class="dim">printf: 42.525250</text>
|
||||
<text x="60" y="515" class="dim">Both words non-zero</text>
|
||||
|
||||
<rect x="620" y="290" width="540" height="240" rx="8" class="pnl"/>
|
||||
<text x="890" y="328" text-anchor="middle" class="sub">After (99.99)</text>
|
||||
|
||||
<rect x="640" y="348" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="380" class="cyn">r3:</text>
|
||||
<text x="730" y="380" class="grn">0x4058FF5C</text>
|
||||
<text x="940" y="380" class="amb">changed</text>
|
||||
|
||||
<rect x="640" y="408" width="500" height="50" rx="4" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="660" y="440" class="cyn">r2:</text>
|
||||
<text x="730" y="440" class="grn">0x28F5C28F</text>
|
||||
<text x="940" y="440" class="amb">changed</text>
|
||||
|
||||
<text x="640" y="485" class="dim">printf: 99.990000</text>
|
||||
<text x="640" y="515" class="dim">BOTH words changed!</text>
|
||||
|
||||
<!-- Float vs Double Patching -->
|
||||
<rect x="40" y="550" width="540" height="230" rx="8" class="pnl"/>
|
||||
<text x="310" y="588" text-anchor="middle" class="sub">Float Patch</text>
|
||||
|
||||
<text x="60" y="628" class="txt">Words changed:</text>
|
||||
<text x="300" y="628" class="grn">1</text>
|
||||
<text x="60" y="663" class="txt">r2 (low):</text>
|
||||
<text x="260" y="663" class="dim">stays 0x0</text>
|
||||
<text x="60" y="698" class="txt">r3 (high):</text>
|
||||
<text x="280" y="698" class="amb">patched</text>
|
||||
<text x="60" y="733" class="dim">Easier to patch</text>
|
||||
|
||||
<rect x="620" y="550" width="540" height="230" rx="8" class="pnl"/>
|
||||
<text x="890" y="588" text-anchor="middle" class="sub">Double Patch</text>
|
||||
|
||||
<text x="640" y="628" class="txt">Words changed:</text>
|
||||
<text x="880" y="628" class="red">2</text>
|
||||
<text x="640" y="663" class="txt">r2 (low):</text>
|
||||
<text x="840" y="663" class="amb">patched</text>
|
||||
<text x="640" y="698" class="txt">r3 (high):</text>
|
||||
<text x="860" y="698" class="amb">patched</text>
|
||||
<text x="640" y="733" class="dim">Both words must change</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,101 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 800">
|
||||
<style>
|
||||
.bg{fill:#0a0a0f}.pnl{fill:#12121a;stroke:#1a1a2e}.hdr{fill:#12121a}
|
||||
.title{font:bold 42px 'Courier New',monospace;fill:#00ff41}
|
||||
.sub{font:bold 28px 'Courier New',monospace;fill:#00d4ff}
|
||||
.txt{font:24px 'Courier New',monospace;fill:#c0c0c0}
|
||||
.dim{font:20px 'Courier New',monospace;fill:#888}
|
||||
.grn{font:bold 24px 'Courier New',monospace;fill:#00ff41}
|
||||
.red{font:bold 24px 'Courier New',monospace;fill:#ff0040}
|
||||
.cyn{font:bold 24px 'Courier New',monospace;fill:#00d4ff}
|
||||
.amb{font:bold 24px 'Courier New',monospace;fill:#ffaa00}
|
||||
.badge{stroke:#00ff41;rx:14}
|
||||
</style>
|
||||
<rect class="bg" width="1200" height="800"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="600" y="52" text-anchor="middle" class="title">IEEE 754 & Data Types</text>
|
||||
<text x="600" y="88" text-anchor="middle" class="dim">Data Types and IEEE 754 Reference</text>
|
||||
|
||||
<!-- Reference Table -->
|
||||
<rect x="40" y="110" width="1120" height="330" rx="8" class="pnl"/>
|
||||
<text x="600" y="148" text-anchor="middle" class="sub">IEEE 754 Hex Values</text>
|
||||
|
||||
<!-- Table Header -->
|
||||
<text x="60" y="188" class="cyn">Value</text>
|
||||
<text x="260" y="188" class="cyn">Float (32b)</text>
|
||||
<text x="560" y="188" class="cyn">Double (64b)</text>
|
||||
|
||||
<line x1="60" y1="198" x2="1140" y2="198" stroke="#1a1a2e" stroke-width="1"/>
|
||||
|
||||
<!-- Row 1 -->
|
||||
<text x="60" y="228" class="txt">42.0</text>
|
||||
<text x="260" y="228" class="grn">0x42280000</text>
|
||||
<text x="560" y="228" class="grn">0x4045000000000000</text>
|
||||
|
||||
<!-- Row 2 -->
|
||||
<text x="60" y="258" class="txt">42.5</text>
|
||||
<text x="260" y="258" class="grn">0x422A0000</text>
|
||||
<text x="560" y="258" class="grn">0x4045400000000000</text>
|
||||
|
||||
<!-- Row 3 -->
|
||||
<text x="60" y="288" class="txt">99.0</text>
|
||||
<text x="260" y="288" class="amb">0x42C60000</text>
|
||||
<text x="560" y="288" class="amb">0x4058C00000000000</text>
|
||||
|
||||
<!-- Row 4 -->
|
||||
<text x="60" y="318" class="txt">99.99</text>
|
||||
<text x="260" y="318" class="amb">0x42C7F5C3</text>
|
||||
<text x="560" y="318" class="amb">0x4058FF5C28F5C28F</text>
|
||||
|
||||
<!-- Row 5 -->
|
||||
<text x="60" y="348" class="txt">3.14</text>
|
||||
<text x="260" y="348" class="red">0x4048F5C3</text>
|
||||
<text x="560" y="348" class="red">0x40091EB851EB851F</text>
|
||||
|
||||
<!-- Row 6 -->
|
||||
<text x="60" y="378" class="txt">100.0</text>
|
||||
<text x="260" y="378" class="red">0x42C80000</text>
|
||||
<text x="560" y="378" class="red">0x4059000000000000</text>
|
||||
|
||||
<text x="60" y="418" class="dim">Tip: float low word often 0x0; double low word usually non-zero</text>
|
||||
|
||||
<!-- Patching Workflow -->
|
||||
<rect x="40" y="460" width="1120" height="155" rx="8" class="pnl"/>
|
||||
<text x="600" y="498" text-anchor="middle" class="sub">Patching Workflow</text>
|
||||
|
||||
<rect x="60" y="518" width="200" height="70" rx="6" fill="#0a0a0f" stroke="#00d4ff" stroke-width="1"/>
|
||||
<text x="160" y="548" text-anchor="middle" class="cyn">1. Identify</text>
|
||||
<text x="160" y="570" text-anchor="middle" class="dim">float / double</text>
|
||||
|
||||
<rect x="280" y="518" width="200" height="70" rx="6" fill="#0a0a0f" stroke="#ffaa00" stroke-width="1"/>
|
||||
<text x="380" y="548" text-anchor="middle" class="amb">2. Check r2</text>
|
||||
<text x="380" y="570" text-anchor="middle" class="dim">zero = float</text>
|
||||
|
||||
<rect x="500" y="518" width="200" height="70" rx="6" fill="#0a0a0f" stroke="#ff0040" stroke-width="1"/>
|
||||
<text x="600" y="548" text-anchor="middle" class="red">3. Calculate</text>
|
||||
<text x="600" y="570" text-anchor="middle" class="dim">new hex value</text>
|
||||
|
||||
<rect x="720" y="518" width="200" height="70" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="820" y="548" text-anchor="middle" class="grn">4. Patch</text>
|
||||
<text x="820" y="570" text-anchor="middle" class="dim">in byte editor</text>
|
||||
|
||||
<rect x="940" y="518" width="200" height="70" rx="6" fill="#0a0a0f" stroke="#00ff41" stroke-width="1"/>
|
||||
<text x="1040" y="548" text-anchor="middle" class="grn">5. Export</text>
|
||||
<text x="1040" y="570" text-anchor="middle" class="dim">UF2 + test</text>
|
||||
|
||||
<!-- Key Takeaways -->
|
||||
<rect x="40" y="635" width="540" height="145" rx="8" class="pnl"/>
|
||||
<text x="310" y="670" text-anchor="middle" class="sub">Integer Types</text>
|
||||
|
||||
<text x="60" y="705" class="txt">uint8_t: 0-255</text>
|
||||
<text x="60" y="735" class="txt">int8_t: -128 to 127</text>
|
||||
<text x="60" y="765" class="dim">Two's complement for signed</text>
|
||||
|
||||
<rect x="620" y="635" width="540" height="145" rx="8" class="pnl"/>
|
||||
<text x="890" y="670" text-anchor="middle" class="sub">Key Insight</text>
|
||||
|
||||
<text x="640" y="705" class="txt">Float: patch 1 word</text>
|
||||
<text x="640" y="735" class="txt">Double: patch 2 words</text>
|
||||
<text x="640" y="765" class="dim">Check r2 to detect type</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |