From c306bb3a7b3ef4b7e2392fc9dac7480d8f85a4ca Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Mon, 13 Apr 2026 16:47:24 -0700 Subject: disallow a target of rbp for indirect register moves via flatassembler this matches the behavior the Forth implementation has, and also the behavior of the other flatassembler moves. those versions were written later; it became obvious over the course of development that transparently remapping one variant of an instruction into another was a bad idea and would cause confusion. this change is happening now because, indeed, it caused confusion. the offending variant was used exactly once, in the pushcontrol macro. it has been changed to the disp8 version, which is already what was being output. we've carefully verified that this produces no unexpected binary changes either to the ELF or to the heap. it's kinda cool knowing for sure that the debugging process actually catches this sort of weirdness. Force-Push: yes Change-Id: I355fc0070bb95beeb94c7d14d46fa2cc50f3a30d --- quine.asm | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'quine.asm') diff --git a/quine.asm b/quine.asm index 3136a11..157e87b 100644 --- a/quine.asm +++ b/quine.asm @@ -471,10 +471,9 @@ end macro ; Take a 64-bit source register, store its value into the address pointed to ; by a 64-bit target register. ; -; For rbp, the only modes available also have displacement; we use an 8-bit -; one and set it to zero. The other registers could be encoded without the -; displacement, but for simplicity's sake we do the same thing for all of -; them. +; For a target of rbp, the only modes available also have displacement; we +; disallow that. Use mov.disp8.qreg.qreg for that case, and set a displacement +; of 0. ; ; In understanding this, pay close attention to the Op/En column in the opcode ; table. The "MR" variant means the ModRM byte's reg field (the middle one) @@ -495,17 +494,19 @@ end macro ; is for whichever register is specified in the R/M field. Sometimes that's ; the source, and sometimes it's the target, depending on the opcode. macro mov.indirect.qreg.qreg target, source + match =rbp, target + assert 0 + end match qwordreg sreg, source qwordreg treg, target rex.w db 0x89 - modrm 1, sreg, treg + modrm 0, sreg, treg match =rsp, target ; R/M = rsp is the SIB case sib 0, 4, treg ; no scaling, no indexing, target as base end match - db 0 end macro @@ -1038,7 +1039,7 @@ end macro ; ; We need to treat a target of rsp specially because it's the SIB case per ; table 2-2. -macro mov.disp8.qreg.qreg target, offset, source +macro mov.disp8.qreg.qreg offset, target, source qwordreg sreg, source qwordreg treg, target rex.w @@ -1723,7 +1724,7 @@ end macro ;;; macro pushcontrol source lea.qreg.disp8.qreg rbp, -8, rbp - mov.indirect.qreg.qreg rbp, source + mov.disp8.qreg.qreg 0, rbp, source end macro macro popcontrol target @@ -7229,7 +7230,9 @@ defword addressing_indirect_reg64, 0 dq dup, rbp, ne, zbranch, 23*8 ; Check whether the R/M register is rsp; save the test result for later. dq dup, rsp, eq, lit, 4, unroll + ; (equality result, output point, reg/op value, reg/mem name) dq reg64, lit, 0, unroll3, modrm + ; (equality result, output point) ; If the R/M register was rsp, we need an SIB byte; otherwise, skip it. dq swap, zbranch, 8*8, lit, 0, lit, 4, rsp, reg64, sib dq exit -- cgit 1.4.1