Author Topic: Wrong far jump address generated by NASM 2.16.1  (Read 7732 times)

Offline Ra.M.

  • Jr. Member
  • *
  • Posts: 5
Wrong far jump address generated by NASM 2.16.1
« on: April 16, 2023, 05:29:00 PM »
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: [Select]
; 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:
Code: [Select]
jmp CODESEGM1:return_labelIn order to investigate this problem, consider these two instructions for the second jump:
Code: [Select]
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:
Code: [Select]
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:
Code: [Select]
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:
Code: [Select]
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.
« Last Edit: April 16, 2023, 05:34:31 PM by Ra.M. »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 371
  • Country: br
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #1 on: April 17, 2023, 01:38:09 PM »
Aren't you forgetting about relocations?
Code: [Select]
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
Also:
Code: [Select]
C:\Work> tdump test.exe
...
Relocations:
    0000:0003     0001:0003

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).
« Last Edit: April 17, 2023, 01:40:49 PM by fredericopissarra »

Offline Ra.M.

  • Jr. Member
  • *
  • Posts: 5
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #2 on: April 17, 2023, 04:32:43 PM »
I know the "bug" is not about that, but I couldn't reproduce it (since I'm still using nasm 2.15).
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: [Select]
jmp     CODESEGM1:return_label
jmp     far return_label
NASM <= 2.15.x generates these two identical opcodes:
Code: [Select]
EA0A000000        jmp word 0x0:0xa
EA0A000000        jmp word 0x0:0xa
(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: [Select]
EA0A000000        jmp word 0x0:0xa
EA0A000A00        jmp word 0xa:0xa
As you can see, in the second instruction the Seg component of the far address is wrong!

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 371
  • Country: br
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #3 on: April 17, 2023, 05:07:53 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: [Select]
jmp     CODESEGM1:return_label
jmp     far return_label
NASM <= 2.15.x generates these two identical opcodes:
Code: [Select]
EA0A000000        jmp word 0x0:0xa
EA0A000000        jmp word 0x0:0xa
(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: [Select]
EA0A000000        jmp word 0x0:0xa
EA0A000A00        jmp word 0xa:0xa
As you can see, in the second instruction the Seg component of the far address is wrong!
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...
« Last Edit: April 17, 2023, 05:10:43 PM by fredericopissarra »

Offline Ra.M.

  • Jr. Member
  • *
  • Posts: 5
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #4 on: April 17, 2023, 06:27:07 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...
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: [Select]
; 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


Offline fredericopissarra

  • Full Member
  • **
  • Posts: 371
  • Country: br
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #5 on: April 18, 2023, 12:11:25 PM »
Yes, you are right; for simplicity, I have removed some instructions.
...
You can try this code with NASM 2.15.x and NASM 2.16.x

Well... I've tried and you are right, with msys2:
Code: [Select]
$ nasm -fobj -o test.obj test.asmIn DosBOX:
Code: [Select]
c:\work> tlink test.obj, test.exe
c:\work> tdump test.exe
...
Relocations

    0000:0003      0001:0003
Back on MSYS2:
Code: [Select]
$ 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  EA05000500        jmp 0x5:0x5
Yep... segment portion of second jmp far is wrong.
Anyway, I do prefer to specify segment:offset in far jumps (calls) instead leting the compiler figure it out. But, of course, I think it should!
« Last Edit: April 18, 2023, 12:23:48 PM by fredericopissarra »

Offline Ra.M.

  • Jr. Member
  • *
  • Posts: 5
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #6 on: April 19, 2023, 06:03:50 PM »
Anyway, I do prefer to specify segment:offset in far jumps (calls) instead leting the compiler figure it out. But, of course, I think it should!
In any case, this is a really serious bug. I think it would be better to file a bug report to bugzilla/nasm.
Do I need a different account to access bugzilla?

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 371
  • Country: br
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #7 on: April 21, 2023, 10:46:52 PM »
In any case, this is a really serious bug. I think it would be better to file a bug report to bugzilla/nasm.
Do I need a different account to access bugzilla?
I agree... I'm not a member of NASM development team (I believe Frank Kotler is), but the bugzilla URL is this one: https://bugzilla.nasm.us/. Don't know if requires a different login...

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #8 on: April 21, 2023, 11:16:37 PM »
  am old and tired and my memory is all shot. I am not in a position to test 16 bit  code. Should the instruction not be:

Code: [Select]
jmp far [dest_label]
?

Best,
Frank


Offline Ra.M.

  • Jr. Member
  • *
  • Posts: 5
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #9 on: April 22, 2023, 04:10:08 PM »
Should the instruction not be:
Code: [Select]
jmp far [dest_label]
?
That is a far jump indirect inter-segment; in that case, dest_label is a 32 bit variable containing a pair Seg:Offset.
For a far jump direct inter-segment, the syntax is:
Code: [Select]
jmp far dest_labelIn 16 bit real mode this means: "jump to the dest_label offset calculated with respect to the dest_label segment".
That instruction works properly with all NASM versions up to 2.15.x.
NASM 2.16.x, instead, generates an incorrect opcode; something like:
Code: [Select]
jmp Offset:OffsetAs you can see, NASM 2.16.x puts Offset instead of Seg.

I'm not sure but, this bug could also affect addresses in 32/64 bit protected mode.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #10 on: April 22, 2023, 04:58:33 PM »
Okay, I stand corrected.

Best,
Frank


Offline fredericopissarra

  • Full Member
  • **
  • Posts: 371
  • Country: br
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #11 on: April 22, 2023, 05:49:42 PM »
I'm not sure but, this bug could also affect addresses in 32/64 bit protected mode.
Probably not, because in 32/64 codes, usually, the memory model is FLAT. No need to do a jump intersegment.

Offline Deskman243

  • Jr. Member
  • *
  • Posts: 49
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #12 on: June 30, 2023, 09:16:47 PM »
Quote

As you can see, both instructions produce the same opcodes; using NASM 2.16.1, instead, this is the result:
Code: [Select]
EA0A000000        jmp word 0x0:0xa
EA0A000A00        jmp word 0xa:0xa
The address in the second instruction is clearly wrong!


Guess when I first looked at it hundreds of years ago it looked like both of the instructions had distinct opcodes because they were in fact not the same haha (joke)  :)

Offline ben321

  • Full Member
  • **
  • Posts: 182
Re: Wrong far jump address generated by NASM 2.16.1
« Reply #13 on: December 17, 2023, 02:01:58 AM »
Quote

As you can see, both instructions produce the same opcodes; using NASM 2.16.1, instead, this is the result:
Code: [Select]
EA0A000000        jmp word 0x0:0xa
EA0A000A00        jmp word 0xa:0xa
The address in the second instruction is clearly wrong!


Does this bug still exist in the latest RC (release candidate) version?
Guess when I first looked at it hundreds of years ago it looked like both of the instructions had distinct opcodes because they were in fact not the same haha (joke)  :)