NASM Forum > Using NASM

Wrong far jump address generated by NASM 2.16.1

(1/3) > >>

Ra.M.:
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

--- Code: ---; 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

--- End code ---
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:

--- Code: ---jmp CODESEGM1:return_label
--- End code ---
In order to investigate this problem, consider these two instructions for the second jump:

--- Code: ---jmp     CODESEGM1:return_label
jmp     far return_label

--- End code ---
Assembling with NASM 2.11, linking with LINK.EXE and disassembling with NDISASM, this is the result:

--- Code: ---EA0A000000        jmp word 0x0:0xa
EA0A000000        jmp word 0x0:0xa

--- End code ---
As you can see, both instructions produce the same opcodes; using NASM 2.16.1, instead, this is the result:

--- Code: ---EA0A000000        jmp word 0x0:0xa
EA0A000A00        jmp word 0xa:0xa

--- End code ---
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:

--- Code: ---EA3C000000        jmp word 0x0:0x3c
EA3C003C00        jmp word 0x3c:0x3c

--- End code ---
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.

fredericopissarra:
Aren't you forgetting about relocations?

--- Code: ---C:\work> nasm -fobj test.asm -o test.obj
C:\work> tlink test.obj, test.exe
C:\work> ndisasm -b 16-e 512 test.exe
00000000  EA00000100        jmp 0x1:0x0
00000005  B8004C            mov ax,0x4c00
00000008  CD21              int 0x21
0000000A  0000              add [bx+si],al
0000000C  0000              add [bx+si],al
0000000E  0000              add [bx+si],al
00000010  EA05000000        jmp 0x0:0x5
--- End code ---
Also:

--- Code: ---C:\Work> tdump test.exe
...
Relocations:
    0000:0003     0001:0003
--- End code ---

PS: 'mov ah,4Ch/mov al,0' is the same as 'mov ax,4C00h'.

I know the "bug" is not about that, but I couldn't reproduce it (since I'm still using nasm 2.15).

Ra.M.:

--- Quote from: fredericopissarra on April 17, 2023, 01:38:09 PM ---I know the "bug" is not about that, but I couldn't reproduce it (since I'm still using nasm 2.15).

--- End quote ---
Yes, all NASM versions up to 2.15.x work properly; this problem has appeared in NASM since version 2.16.x.

Probably, my explanation was not clear; in order to compare the two far addresses CODESEGM1:return_label and far return_label, I have put together the two instructions:

--- Code: ---jmp     CODESEGM1:return_label
jmp     far return_label

--- End code ---
NASM <= 2.15.x generates these two identical opcodes:

--- Code: ---EA0A000000        jmp word 0x0:0xa
EA0A000000        jmp word 0x0:0xa

--- End code ---
(0x0 is the Seg component and 0xa is the Offset component of the far address, before relocation)
NASM 2.16.x, instead, generates these two different opcodes:

--- Code: ---EA0A000000        jmp word 0x0:0xa
EA0A000A00        jmp word 0xa:0xa

--- End code ---
As you can see, in the second instruction the Seg component of the far address is wrong!

fredericopissarra:

--- Quote from: Ra.M. on April 17, 2023, 04:32:43 PM ---Probably, my explanation was not clear; in order to compare the two far addresses CODESEGM1:return_label and far return_label, I have put together the two instructions:

--- Code: ---jmp     CODESEGM1:return_label
jmp     far return_label

--- End code ---
NASM <= 2.15.x generates these two identical opcodes:

--- Code: ---EA0A000000        jmp word 0x0:0xa
EA0A000000        jmp word 0x0:0xa

--- End code ---
(0x0 is the Seg component and 0xa is the Offset component of the far address, before relocation)
NASM 2.16.x, instead, generates these two different opcodes:

--- Code: ---EA0A000000        jmp word 0x0:0xa
EA0A000A00        jmp word 0xa:0xa

--- End code ---
As you can see, in the second instruction the Seg component of the far address is wrong!

--- End quote ---
Yes, but there is something strange here. Since your segments are aligned by DQWORD (16 bytes), the initial offsets of both CODESEGM1 and CODESEGM2 should be 0x???0. There's no sense the first far jump jumping to 0xXXXX:0xXXXA (and the second should jump to 0xXXXX:0xXXX5). Unless that is not the entire code to test...

Ra.M.:

--- Quote from: fredericopissarra on April 17, 2023, 05:07:53 PM ---Yes, but there is something strange here. Since your segments are aligned by DQWORD (16 bytes), the initial offsets of both CODESEGM1 and CODESEGM2 should be 0x???0. There's no sense the first far jump jumping to 0xXXXX:0xXXXA (and the second should jump to 0xXXXX:0xXXX5). Unless that is not the entire code to test...

--- End quote ---
Yes, you are right; for simplicity, I have removed some instructions.
return_label offset is 0x5 (five bytes after jmp far dest_label), but it doesn't change anything; NASM 2.16.x generates a broken executable.
You can try this code with NASM 2.15.x and NASM 2.16.x

--- Code: ---; 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

--- End code ---

Navigation

[0] Message Index

[#] Next page

Go to full version