Assisted-by: GLM 5.3
This commit is contained in:
+154
@@ -109,6 +109,160 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
lines entered the alignment width computation, and rendered `/ *`,
|
||||
`> >` sequences re-lexed as comments and shifts. The label, width and
|
||||
spacing rules now agree between passes.
|
||||
- **`gasm fmt` deleted the `|` separators from TEXT and GLOBL flag
|
||||
lists.** The lexer had no token for `|`, the formatter dropped the
|
||||
resulting illegal token, and an in-place format silently rewrote
|
||||
`NOSPLIT|DUPOK` as `NOSPLIT DUPOK`, which the Go assembler rejects.
|
||||
The bars now round-trip byte-identically, and `·foo<ABIInternal>(SB)`
|
||||
parses its ABI marker instead of swallowing `ABIInternal` and `SB`
|
||||
into the flags, which produced false lint warnings on the standard
|
||||
runtime spelling.
|
||||
- **A malformed TEXT declaration crashed `gasm lint` and the language
|
||||
server.** A TEXT line without a symbol left a nil name that lint and
|
||||
the LSP dereferenced; both now carry on with a diagnostic. A branch
|
||||
to a label at the end of a function body panicked the liveness
|
||||
analysis the same way. A real NUL byte truncated the token stream
|
||||
(everything after it was dropped); it is an illegal token now, invalid
|
||||
UTF-8 no longer inflates byte offsets, and CRLF files format to
|
||||
uniform LF.
|
||||
- **A frameless amd64 function containing a CALL read its arguments from
|
||||
the wrong stack slot.** The forced base-pointer frame shifted
|
||||
FP references by eight bytes (`x+0(FP)` resolved to SP+0x18 where the
|
||||
toolchain emits SP+0x10), so such functions loaded garbage. The
|
||||
class-2 stack guard had the sibling defect: whenever the underflow
|
||||
branch relaxed to its 32-bit form, its displacement ran four bytes
|
||||
past the target and into the morestack CALL.
|
||||
- **Immediate operands wrapped silently on amd64.** Shift counts,
|
||||
immediates beyond the operand's width and displacements beyond int32
|
||||
truncated without a diagnostic (`SHLQ $300` assembled as `$44`); they
|
||||
are range-checked now, matching `go tool asm`. EVEX scalar moves
|
||||
(`VMOVSS Z1, Z2`) accepted forms the toolchain rejects and emitted
|
||||
invalid encodings; `PUSHW`/`POPW` emit the 0x66-prefixed forms the
|
||||
toolchain emits; `PUSHL` is rejected as illegal in 64-bit mode; a bare
|
||||
zero-operand `JE` reports a diagnostic instead of panicking.
|
||||
- **The arm64 shift and divide instructions encoded entirely different
|
||||
operations.** `LSL`, `LSR`, `ASR` and `ROR`, immediate and register
|
||||
forms, all encoded as `ORR`; `SDIV`/`UDIV` sat in the wrong opcode
|
||||
space; `MADD`/`MSUB` never encoded the accumulate operand and silently
|
||||
read X0 for it. All now match the toolchain byte for byte (new
|
||||
differential kernels cover shifts, divides and multiplies), MADD
|
||||
takes its four operands in the toolchain's order, and shift amounts at
|
||||
or above the operand width are rejected.
|
||||
- **arm64 multi-chunk immediates corrupted every branch that followed
|
||||
them.** The size pass and the emitter disagreed on the expansion of
|
||||
constants with three or more non-zero 16-bit chunks and of `MOVW $-1`,
|
||||
so later label displacements were computed against the wrong offsets.
|
||||
The size now comes from the encoder itself. Large-frame stack guards
|
||||
(frames from roughly 64 KiB) branched to the wrong morestack entry,
|
||||
and the pcsp and DWARF CFA boundaries for materialised large frames
|
||||
are computed from the real prologue word counts.
|
||||
- **arm64 immediates and addressing wrapped instead of erroring.**
|
||||
Constants beyond the encodable range (`ADD $0x100000000`) wrapped to
|
||||
zero, memory offsets wrapped at 2^31, exclusive and atomic accesses
|
||||
silently ignored their offsets (`LDXR 8(R1)` read `[R1]`), and large
|
||||
register-based offsets were routed through SP instead of the operand's
|
||||
base. All four now either encode correctly or produce diagnostics.
|
||||
- **riscv64 compressed stores with certain offsets wrote to the wrong
|
||||
address.** The C.SD/C.SW/C.FSD immediate pattern dropped one bit, so
|
||||
any register-relative store with offset bit 4 or 5 set targeted a
|
||||
different address than the same-index load beside it. `FENCE`
|
||||
assembled as `fence 0,0` instead of `fence iorw, iorw`. Branch and
|
||||
jump displacements beyond ±4 KiB / ±1 MiB wrapped silently; they are
|
||||
diagnostics now. The GOROOT width spellings (`MOVW 4(SP), X9`)
|
||||
compress to their C.LW/C.SW forms exactly as the toolchain lowers
|
||||
them, restoring byte parity for those shapes.
|
||||
- **loong64 `MOVW $c, Fd` wrote a general register.** The immediate was
|
||||
routed to the GPR of the F register's number (`MOVW $2, F4` clobbered
|
||||
argument register R4), and the correct R30 + `movgr2fr.w` sequence was
|
||||
unreachable. Two-operand `BLTU R4, label` encoded as `beqz`
|
||||
(sometimes-taken where the toolchain's form is never-taken), and
|
||||
out-of-range FP constants and BSTRINS/BSTRPICK bit numbers wrapped
|
||||
silently; all are corrected or diagnosed.
|
||||
- **ELF objects carried wrong relocation records.** The amd64
|
||||
stack-guard TLS load relocated as R_X86_64_PC32 against the null
|
||||
symbol (every non-NOSPLIT object mislinked); arm64 SB references
|
||||
applied HI21 twice instead of the HI21/LO12 pair; riscv64 PCREL_LO12
|
||||
referenced the target instead of its AUIPC site, which the system
|
||||
linker rejects; riscv64 and loong64 e_flags declared the soft-float
|
||||
ABI, so standard linkers refused the merge.
|
||||
- **ELF DWARF was unparseable.** Eight abbrev-table constants were
|
||||
wrong, the version-5 line header carried DWARF2-shaped tables, the
|
||||
section count omitted `.debug_frame` (it sat past the section table,
|
||||
invisible to every tool), the CIE hardcoded one architecture's
|
||||
CFA and return-address registers for all four, and no DWARF address
|
||||
was ever relocated: the `.rela.debug_info` and `.rela.debug_line`
|
||||
records were computed and then discarded, so every address stayed
|
||||
zero after linking. The tables parse in readelf, the registers are
|
||||
per-architecture, `.rela.debug_info`, `.rela.debug_line` and
|
||||
`.rela.debug_frame` are emitted, and addresses resolve after the
|
||||
link; a data-only file emits a valid object instead of panicking, and
|
||||
the DWARF records the real source path.
|
||||
- **GOOBJ cross-package references resolved against the wrong object.**
|
||||
External package indices were zero-based against a table that
|
||||
reserves zero for the dummy invalid package, and symbol indices
|
||||
ignored the hashed definition blocks between the sections, so a
|
||||
reference into the first external package could bind to whatever
|
||||
object the loader saw first. An end-to-end cross-package link pins
|
||||
the chain. arm64 ADRP pairs now emit the toolchain's single 8-byte
|
||||
relocation (the previous twin 4-byte records were a hard link error),
|
||||
and symbols no longer claim the linkname flag the toolchain reserves
|
||||
for `//go:linkname` declarations.
|
||||
- **The arm64 JIT trampolines saved a scratch register as the stack
|
||||
pointer.** `enterJIT` and its checked twin stored R3, a plain
|
||||
caller-saved register on arm64, and restored RSP from it, so the
|
||||
first JIT call would have returned to a garbage stack. The loong64
|
||||
trampoline hands its leave address through the raw-symbol pattern the
|
||||
arm64 one uses, avoiding the ABI wrapper's prologue.
|
||||
- **The checked-ABI report flagged legal frames.** The red-zone canary
|
||||
sat 64 bytes below the entry stack, so any kernel with a larger
|
||||
declared frame reported "stack below SP written"; the guard now sizes
|
||||
itself from the kernel's frame. The amd64 JIT tests are gated to
|
||||
amd64 hosts (the suite previously SIGILL-crashed on the other three
|
||||
architectures), fuzz signatures wider than the TEXT frame report
|
||||
instead of panicking, `--buf` specifications are validated strictly
|
||||
(a typo no longer verifies against a zeroed buffer), and ABI0
|
||||
parameter sizes cover `string` and `complex` correctly.
|
||||
- **amd64 hardware watchpoints never armed.** The debug registers were
|
||||
poked at offsets inside `user_regs_struct`, corrupting five general
|
||||
registers while the REPL reported success; they now use the real
|
||||
u_debugreg window and stop on the watched address. loong64 watch
|
||||
goes through the kernel's HW_WATCH regset (riscv64 reports the
|
||||
kernel's interface as unsupported instead of failing obscurely).
|
||||
- **`gasm debug` hung on the first faulting kernel.** Genuine
|
||||
SIGSEGV/SIGBUS/SIGFPE/SIGILL stops were discarded as runtime noise
|
||||
and the faulting instruction restarted forever; faults now surface as
|
||||
reported stops. Conditional breakpoints with a false condition
|
||||
resumed mid-instruction, `next` and `finish` evaluated traps with
|
||||
stale registers and landed off instruction boundaries, and the
|
||||
breakpoint restore covered one byte of the four-byte traps (arm64
|
||||
silently skipped the instruction under it); the trap PCs follow the
|
||||
kernel's reporting on every architecture. `regs` reports YMM from
|
||||
the xstate (a struct-size overrun crashed FP register reads before),
|
||||
V register halves print correctly on arm64, `unwatch` accepts the
|
||||
architecture's slot range, `x <addr> -8` no longer crashes, break
|
||||
conditions accept memory operands, and session scratch directories
|
||||
are cleaned up.
|
||||
- **The language server died on one malformed frame and corrupted
|
||||
sources on rename.** A bad `Content-Length` or an unparsable JSON
|
||||
body terminated the process instead of answering `-32700` and
|
||||
continuing; rename and references covered the stripped name instead
|
||||
of the full `·name` token, so renaming produced `·helper` minus its
|
||||
last letter; documentHighlight never matched middle-dot symbols.
|
||||
Positions are UTF-16 code units in both directions (astral characters
|
||||
no longer shift columns) and responses always carry an explicit
|
||||
`result` member.
|
||||
- **The linter now recognises the `g` spelling of the goroutine
|
||||
register.** `MOVD R0, g` clobbered R28 on arm64 (and the equivalents
|
||||
on the other architectures) unflagged, and the numeric spellings the
|
||||
linter did track are rejected by the toolchain there, so `g` was the
|
||||
one spelling that escaped the audit. FUNCDATA and PCDATA literal
|
||||
indices are validated against the ranges the runtime defines.
|
||||
- **Usage errors exit 2 uniformly.** `audit-instructions` and
|
||||
`scaffold` argument errors and an unknown `asm --format` exited 1 (or,
|
||||
for `--format` without `-o`, exited 0 silently); the documented
|
||||
exit-2 contract now holds, `asm -o` no longer prints the hex dump it
|
||||
claimed to replace, and `verify --ground-truth` works for amd64
|
||||
kernels on non-amd64 hosts instead of refusing with JIT advice.
|
||||
|
||||
## [0.33.0] - 2026-09-14
|
||||
|
||||
|
||||
Reference in New Issue
Block a user