From c4061e49e61398ea21466f63d6b1430efa3b7627 Mon Sep 17 00:00:00 2001 From: "J. Gareth \"Curious Kit\" Moreton" Date: Tue, 17 Oct 2023 13:20:59 +0100 Subject: [PATCH] * ARM: Fixed issue where some offsets of ADR assembly instructions were incorrectly encoded by the internal assembler --- compiler/arm/aasmcpu.pas | 50 ++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/compiler/arm/aasmcpu.pas b/compiler/arm/aasmcpu.pas index b0c84327d5..a47639b85e 100644 --- a/compiler/arm/aasmcpu.pas +++ b/compiler/arm/aasmcpu.pas @@ -2814,6 +2814,8 @@ implementation refoper : poper; msb : longint; r: byte; + imm : dword; + count : integer; singlerec : tcompsinglerec; doublerec : tcompdoublerec; @@ -3870,17 +3872,51 @@ implementation if assigned(currsym) then offset:=currsym.offset-insoffset-8; offset:=offset+oper[1]^.ref^.offset; - if offset>=0 then + if opcode = A_ADR then begin - { set U flag } - bytes:=bytes or (1 shl 23); - bytes:=bytes or offset + { The encoding for an ADR instruction is that of an ADD instruction, + so the offset has to abide by immediate shifter rules, otherwise + it can't be encoded } + if is_shifter_const(offset,r) then + begin + bytes:=bytes or (1 shl 23); + end + else + begin + bytes:=bytes or (1 shl 22); + offset:=-offset; + end; + + { calc rotate and adjust imm } + count:=0; + r:=0; + imm:=dword(offset); + repeat + imm:=RolDWord(imm, 2); + inc(r); + inc(count); + if count > 32 then + begin + message1(asmw_e_invalid_opcode_and_operands, 'invalid shifter imm (offset)'); + exit; + end; + until (imm and $ff)=imm; + bytes:=bytes or (r shl 8) or imm; end else begin - bytes:=bytes or (1 shl 22); - offset:=-offset; - bytes:=bytes or offset + if offset>=0 then + begin + { set U flag } + bytes:=bytes or (1 shl 23); + bytes:=bytes or offset + end + else + begin + bytes:=bytes or (1 shl 22); + offset:=-offset; + bytes:=bytes or offset + end; end; end else