Search code examples
assemblyx86dosx86-16tasm

Jumping back 1000 lines


I was trying to make a code, that when you're at the very end, it will ask you if you want to try again. If you press 'y', then it will jump back a 1000 lines, right at the beginning of the program.

Well obviously, it didn't work out, as I got the error "jump relative out of range". So I made jumps every 50 lines, having a total of 20 jumps, like

start:
.
s20: jmp start
.
.
.
s2: jmp s3
.
s1: jmp s2
.
jmp s1

Now after doing that, I ran the program, and when I pressed 'y', TASM kind of froze. It was just displaying the last screen, with the 'y' input, and a blinking _. I couldn't press a character anymore.


Solution

  • In x86 you don't need a cascading sequence of jumps, since jmp can jump over the whole segment. Just a conditional jump like jne has a limited range. So you can change an errorneous conditional jump to a combination of an unconditional near jump and a conditional short jump:

    As an example, change

    .MODEL small
    .STACK 1000h
    
    .CODE
    main:
    
    top:
        mov ax, 1
        jmp bottom
    
    
    ORG 1000h               ; A big block between top and bottom
    
    bottom:
        cmp ax, 0
    
        je top              ; **Error** Relative jump out of range by 0F85h bytes
    
        mov ax, 4C00h       ; Return 0
        int 21h
    
    END main
    

    to

    .MODEL small
    .STACK 1000h
    
    .CODE
    main:
    
    top:
        mov ax, 1
        jmp bottom
    
    
    ORG 1000h               ; A big block between top and bottom
    
    bottom:
        cmp ax, 0
    
        jne skip            ; Short conditional jump
        jmp top             ; Near unconditional jump
        skip:
    
        mov ax, 4C00h       ; Return 0
        int 21h
    
    END main
    

    TASM can do that automagically for you. Place a "JUMPS" at the beginning (or where you need it) of the file:

    JUMPS
    
    .MODEL small
    .STACK 1000h
    
    .CODE
    main:
    
    top:
        mov ax, 1
        jmp bottom
    
    
    ORG 1000h               ; A big block between top and bottom
    
    bottom:
        cmp ax, 0
    
        je top              ; TASM will change this line to a JNE-JMP combination
    
        mov ax, 4C00h       ; Return 0
        int 21h
    
    END main
    

    The 80386 instruction set (ISA) has an instruction for a near conditional jump. If your emulator supports the 80386 ISA (DOSBox does), you can tell TASM to use it. Insert a .386 directive:

    .MODEL small
    .386                    ; Use 80386 instruction set
    .STACK 1000h
    
    .CODE
    main:
    
    top:
        mov ax, 1
        jmp bottom
    
    
    ORG 1000h               ; A huge block between top and bottom
    
    bottom:
        cmp ax, 0
    
        je top              ; Correct jump because of '.386'
    
        mov ax, 4C00h       ; Return 0
        int 21h
    
    END main