aa5cb712b2571ffca5e5c926fcc0aeafc9147376
explain/tinyelf-arm.md
... | ... | @@ -8,17 +8,17 @@ Looks like breadbox didn't want to go down *this* rabbithole. So we'll have to d |
8 | 8 | * There's a "Thumb" mode, with reduced instructions (eg. no free shifts, no 3-operand instructions) where all instructions are 2 bytes wide |
9 | 9 | * Switch to Thumb like this: `add lr, pc, #1; bx lr` |
10 | 10 | * On older ARMs, it was possible to directly write to `pc` and switch mode, but this doesn't seem to be possible on ARMv6 anymore. |
11 | -* The `mov` opcode doesn't accept arbitrary immediate values, so you sometimes have to spill values to a "constant pool" |
|
11 | +* The `mov` opcode doesn't accept arbitrary immediate values, so you sometimes have to spill values to a "constant pool", or be creative with assignments and register write-backs in load/store ops |
|
12 | 12 | * Null bytes decode to `andeq r0, r0` in ARM mode, or to `movs r0, r0` in Thumb mode, both are no-ops, unlike in x86 where null bytes cause a segfault. |
13 | 13 | * Instruction encoding is relatively sane, so you can predict what low-value 32-bit ints will decode to so you can treat them as (almost-)no-ops. |
14 | 14 | * It's a RISC, so you don't have one-byte-instructions, flexible addressing modes or stringops, but there are a few useful parts in ARM: |
15 | 15 | * `pc`, `sp` etc. behave as regular registers |
16 | 16 | * You can shift one operand of an instruction by a constant value for free, it doesn't cost any bytes. (ARM mode only) This can also be used to do fixed-point multiplications etc. (eg. `add r0, r0, lsr #1` for `r0*1.5`) |
17 | 17 | * `ldmia`/`stmia` are great for copying stuff around |
18 | -* [`e_machine` seems to be the only checked header field](https://code.woboq.org/linux/linux/arch/arm/kernel/elf.c.html) (`e_entry` alignment checks are normal, because if it wouldn't be aligned, the code would segfault on entry.) |
|
19 | -* `phdr` parsing etc. is done architecture-independent, so the same tricks should be usable here as well. |
|
18 | +* [`e_machine` (and `e_type`) seem to be the only checked header fields](https://code.woboq.org/linux/linux/arch/arm/kernel/elf.c.html) (`e_entry` alignment checks are normal, because if it wouldn't be aligned, the code would segfault on entry.) |
|
19 | +* `phdr` parsing etc. is done architecture-independently, so the same tricks should be usable here as well. |
|
20 | 20 | * Turns out it's even more relaxed than x86 when messing with `p_paddr`, `p_padding` and `p_flags`. It seems to be the case that the kernel & CPU will happily let you execute code in read-write pages. |
21 | -* Apparently the kernel doesn't look at the immediate field of `swi` instructions __if it's configured as EABI-only__ (which we assume). |
|
21 | +* Apparently the kernel doesn't look at the immediate field of `swi` and `bkpt` instructions __if it's configured as EABI-only__ (which we assume). |
|
22 | 22 | * [Dynamic linking stuff](https://linux.weeaboo.software/explain/rtld#dynamic-linking_arm) |
23 | 23 | |
24 | 24 | ### Minimal ELF Poc |