From 3526060a19e0e8cfad7383b98a05484793e6efda Mon Sep 17 00:00:00 2001 From: slederer Date: Mon, 7 Apr 2025 00:25:32 +0200 Subject: [PATCH] sasm: bugfix for LBRANCH/LCBRANCH size changes - The LBRANCH and LCBRANCH directives create different instruction sequences depending on the jump distance. So the code size can shrink during the first pass when the jump distance can be determined (when the label that is the jump destination is parsed). In the long form, LOADREL/JUMP is used, which might or might not need 2 bytes of padding. With this bugfix, the padding is always added, either before or after the LOADREL indirect operand, so that the code size does not change depending on the padding required. Otherwise the code might shrink further on the second pass because a LBRANCH/LCBRANCH instruction no longer needs padding due to an earlier code size change. --- lib/runtime.s | 2 +- pcomp/sasm.pas | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/runtime.s b/lib/runtime.s index f4ad875..6f248b9 100644 --- a/lib/runtime.s +++ b/lib/runtime.s @@ -1616,7 +1616,7 @@ MEM_FREE_XT: ; Since the return stack is no longer valid afterwards, directly ; jumps to _MAIN instead of using RET. -; parameters: [ _MAIN entry point, start of heap address ] +; parameters: [ start of heap address ] _MEM_INIT: ; initialize anchor chunk with start of heap address ; and heap size - header size diff --git a/pcomp/sasm.pas b/pcomp/sasm.pas index ab5230b..7b01f32 100644 --- a/pcomp/sasm.pas +++ b/pcomp/sasm.pas @@ -1515,9 +1515,7 @@ begin end; if dref^.symboldata.value <> value then - (* writeln('////// label changed value ', keyword, ' ', - dref^.symboldata.value, ' -> ', value); *) - dref^.symboldata.value := value; + dref^.symboldata.value := value; end; end; @@ -1872,9 +1870,9 @@ begin if (pc and 3) = 0 then (* no padding *) begin pad := false; - (* total size 8 bytes *) + (* total size 10 bytes *) offset := 4; (* offset for LOADREL *) - shrinkage := 6; (* difference to short form size *) + shrinkage := 8; (* difference to short form size *) end else begin @@ -1892,9 +1890,17 @@ begin encodeInstruction('JUMP', 0, encoded); emitInstructionWord(encoded); + (* Padding is always done, so the length of the sequence does + not change depending on the position. The pad is either + placed before the address to align it on a word address, + or after, if it is already aligned. *) if pad then emitInstructionWord(0); + emitWord(value); + + if not pad then + emitInstructionWord(0); end else begin @@ -1937,9 +1943,9 @@ begin if (pc and 3) = 2 then (* no padding *) begin pad := false; - (* total size 10 bytes *) + (* total size 12 bytes *) offset := 4; (* offset for LOADREL *) - shrinkage := 8; (* difference to short form size *) + shrinkage := 10; (* difference to short form size *) end else begin @@ -1967,9 +1973,17 @@ begin encodeInstruction('JUMP', 0, encoded); emitInstructionWord(encoded); + (* Padding is always done, so the length of the sequence does + not change depending on the position. The pad is either + placed before the address to align it on a word address, + or after, if it is already aligned. *) if pad then emitInstructionWord(0); + emitWord(value); + + if not pad then + emitInstructionWord(0); end else begin