Jump out of range solutions and how different instructions affect range

The problem with the conditional jump instructions in 16-bit assembler is that they’re limited to +127 or -128 bytes for the offset.

386 introduced the jcc rel16 encoding that is available in 16-bit mode, but only on 386 and later. Different assemblers have different options for enabling 386 instructions in 16-bit code

Some also have options to automatically do what’s described below: conditional jcc rel8 over a jmp rel16. For example, TASM has /jJUMPS.


Let’s say you have this:

    cmp al, '1'
    jnz ItsNot1
    ; lots of code here
ItsNot1:

If you get a jump out of range error you can re-code it like this:

    cmp al, '1'
    jz Its1
    jmp ItsNot1
Its1:
    ; lots of code here
ItsNot1:

All I did there is change the sense of the comparison and jump around the unconditional jump that takes you to the alternate code path.

It gets annoying sometimes if you have lots of conditional jumps. You’ll re-code one of those and it’ll trigger another. And then you refactor the code and discover some of those mangled conditionals can go away. Typically I don’t worry about it unless I’m seriously concerned about code size.

Some assemblers have a switch that will do automatic jump sizing for you so that you can always code the conditional jumps and they’ll do the jump-around-conditional-jump trick automatically.

Most likely the difference between

PRINT 'something'

and

call PTHIS
db 13, 10, 'something'

Is that the first one is a macro that expands to the full code for printing something, plus the string you want to print. The second is a simple call instruction (3 bytes), plus the string. Or, in C++ terms, the PRINT macro is like an inline function, and the call PTHIS is a normal (not inlined) function call.

Leave a Comment