Regards.
Some hundred years ago I wrote a little assembly program for testing various types of jumps in DOS real mode (emulated by DOSBox); this is a simplified version of the source code JMP.ASM
; nasm -f obj jmp.asm
; link jmp.obj
CPU 386 ; 32 bit instructions set
%assign STACK_SIZE 0400h ; 1024 bytes for the stack
;############### code segment 1 ##################
SEGMENT CODESEGM1 ALIGN=16 PUBLIC USE16 CLASS=CODE
..start: ; entry point
; JMP direct inter-segment (Ptr16:Ptr16)
jmp far dest_label
return_label:
mov ah, 4ch ; Terminate Program
mov al, 00h ; exit code = 0
int 21h ; DOS INT
;############### code segment 2 #################
SEGMENT CODESEGM2 ALIGN=16 PUBLIC USE16 CLASS=CODE
dest_label:
; JMP direct inter-segment (Ptr16:Ptr16)
jmp far return_label
;################# stack segment ##################
SEGMENT STACKSEGM ALIGN=16 STACK USE16 CLASS=STACK
resb STACK_SIZE ; 1024 bytes for the stack
As you can see, there are two code segments. In CODESEGM1 there is a far jump (direct inter-segment) to CODESEGM2 and in CODESEGM2 there is a far jump (direct inter-segment) to CODESEGM1.
Assembling JMP.ASM with an old NASM version (2.11) and linking it with whatever linker for DOS (for example, LINK.EXE provided by MASM 6.11), I get an executable JMP.EXE that works properly; conversely, using the latest NASM 2.16.1, I get an executable that crashes!
More precisely (and this is really weird), the first far jump works, but the second far jump freezes DOSBox!
As a workaround, with NASM 2.16.1 I have to write:
jmp CODESEGM1:return_label
In order to investigate this problem, consider these two instructions for the second jump:
jmp CODESEGM1:return_label
jmp far return_label
Assembling with NASM 2.11, linking with LINK.EXE and disassembling with NDISASM, this is the result:
EA0A000000 jmp word 0x0:0xa
EA0A000000 jmp word 0x0:0xa
As you can see, both instructions produce the same opcodes; using NASM 2.16.1, instead, this is the result:
EA0A000000 jmp word 0x0:0xa
EA0A000A00 jmp word 0xa:0xa
The address in the second instruction is clearly wrong!
It seems something like JMP Offset:Offset; in fact, if I move return_label to another offset (for example, 0x3c), I get:
EA3C000000 jmp word 0x0:0x3c
EA3C003C00 jmp word 0x3c:0x3c
Again, JMP Offset:Offset!
If I am not wrong, this is a serious bug introduced by NASM 2.16.1.
In similar circumstances, this also happens with the "CALL far" instruction.