Just documenting an .if statement bug in MASM 14.0.23026 and newer. Conditional jumps besides jz/jnz generated from signed comparisons are short by one and end up trashing the resulting code if not accommodated.
COMMENT ~ ASM EXE
#
# ERRATA.ASM
#
# MASM Source - MASM Errata - version 1.0.0.0
#
# Noted differences between MASM versions, some causing problems.
#
# [WH]
#
# (C) All Rights Reserved
#~========================================================================================
include \masm32\include\masm32rt.inc
; int 3 align
align_int3 macro _:REQ
local $$, $$$
$$ equ $
align _
$$$ equ $ - $$
if $$$
org $$
db $$$ dup(0CCh)
endif
endm
; else align
align_else macro _:REQ
local $$, $$$
$$ equ $
align 16
$$$ equ $ - $$
if $$$
org $$
db -($$$ mod 16 lt _) * (16 + $$$ - _) dup(0CCh)
db (($$$ mod 16 lt _) + 1) * ($$$ - _) dup(0CCh)
endif
endm
; nop align
align_code macro _:REQ
local $$, $$$
$$ equ $
align _
$$$ equ $ - $$
if $$$
org $$
db -($$$ mod 4 ge 3) dup(66h)
db -($$$ mod 4 ge 2) dup(66h)
db -($$$ mod 4 ge 1) dup(90h)
dd $$$ / 4 dup(90666666h)
endif
endm
;~========================================================================================
.code
align_int3 16
db @CatStr(<!">,%@Version,<!">),0
align_else 5
EntryPoint textequ @CatStr(<EntryPoint>,%@Version)
call EntryPoint
;~........................................................................................
align_int3 16
EntryPoint proc <forceframe> uses ebx esi edi
local wRegisterLocal:WORD
int 3
align_code 16
; MASM ge 1400 jumps 1 byte short on signed comparisons (jz and jnz work)
.if sbyte ptr al >= "`"
sub al, 20h
.endif
.if sword ptr ax < "``"
sub al, 20h
.endif
.if sdword ptr eax <= "````"
sub al, 20h
.endif
align_code 16
; MASM ge 800 encoding change
cmp al, ah
align_code 16
; MASM lt 800 add unnecessary data size prefix to register mov
push ecx
mov [esp], ss
mov word ptr [esp], ss
mov wRegisterLocal, ss
pop ecx
align_code 16
ret
EntryPoint endp
;~........................................................................................
align_int3 16
end EntryPoint;*/
One potential workaround is to insert a nop before the .endif:
.if sbyte ptr al >= "a"
sub al, 20h
if @Version ge 1400
nop
endif;compat
.endif
(The nop gets consumed by the bug leaving only intended code.)
Note that the following works correctly:
.if sbyte ptr al & "a"
sub al, 20h
.endif
.if !(sbyte ptr al & "a")
sub al, 20h
.endif
.if sbyte ptr al == "a"
sub al, 20h
.endif
.if sbyte ptr al != "a"
sub al, 20h
.endif
This issue affects:
14.0.23026
14.0.23506
14.0.23918
14.0.24210
14.0.24218
14.10.25017
It doesn't affect:
12.0.40629 or older
Those are what I've checked personally, not sure if other builds in the 14.0 or 14.10 versions exist.
Queue