NASM Forum > Using NASM
Wrong far jump address generated by NASM 2.16.1
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