NASM JMP offset ignored

Programming, for all ages and all languages.
Post Reply
0b1
Member
Member
Posts: 35
Joined: Sun Feb 04, 2018 8:04 pm

NASM JMP offset ignored

Post by 0b1 »

I am new to NASM and i386 assembly. I did some 8 bit work back in the day, but ... enough said about that.

From various tutorials online, I have cobbled together a bootloader that reads a kernelette directly from sector 2 and transfers control.

My problem is that the final JMP instruction's offset address seems to be ignored. I can set JMP SEG:OFFSET to any value of offset and the kernelette still works. Even if the offset is way past the address where the instructions would have loaded (eg 0xFFFF) my kernelette still executes.

I have read all I can about the JMP instruction and nothing says real mode JMP immediate ignores the offset. My code is below.

I don't want code that works by accident, so if anyone can explain the JMP (or NASM's interpretation of JMP) better than what I've found online so far, I would be most grateful!

Thanks for reading.
DP

boot loader code

Code: Select all


;bootloader code
%assign KERNEL_BASE_SEGMENT			0x1000	; DPP: I added this.
%assign KERNEL_ENTRY_ADDRESS		        0x0000  ; DPP: I added this.
%assign KERNEL_SECTOR_START			1		; DPP: I added this.
%assign KERNEL_SECTOR_COUNT			12		; DPP: I added this.

%define BOOT_DRIVE_NUMBER 			        0x80
%assign BIOS_VIDEO_SERVICES			0x10
%assign BIOS_DISK_SERVICES			        0x13

%assign READ_DISK_SECTORS			        0x02

%assign SET_VIDEO_MODE				0x00	

[BITS 16]
[ORG 0x7C00]

	mov si,	MESSAGE_LOADING
	call print

	;load kernelette from sector 2 into 0x1000:0000
	MOV DL, 0x80   	;drive number
	MOV DH, 0x0 	;head (0=base)
	MOV CH, 0x0 	;track/cylinder
	MOV CL, 0x02 	;sector 
	
	MOV BX, 0x1000 	;can't update ES directly, so put destination segment into BX
	MOV ES, BX 		;place BX in pointer ES
	MOV BX, 0x0 	        ;BX is actually destination offset, so we want it to be zero.

	
read_disk:
	MOV AH, 0x02
	MOV AL, 0x01
	INT 0x13
	JC read_disk 	;infinite retry for now.

	;pointers to kernel segment (0x1000)
	MOV AX, 0x1000
	MOV DS, AX   	        ;DS (update data segment)
	MOV SS, AX		;SS (update stack segment)
	
	;ANY of these JMPs work. Offset is ignored. why?
	JMP 0x1000:0x0000   
	;JMP 0x1000:0x0200   
	;JMP 0x1000:0x0020   
	;JMP 0x1000:0xDADA   
	;JMP 0x1000:0xFFFF 

never_get_here:
	cli 
	hlt
	jmp $

print:
	mov bp,sp
	print_repeat:
	lodsb
	or al,al
	jz print_done
	mov ah,0x0e
	mov bx,0
	int BIOS_VIDEO_SERVICES
	jmp print_repeat
	
print_done:
	mov sp,bp
	ret

MESSAGE_LOADING db "Loading simple Kernel...",10,13,0
MESSAGE_LOADED db "Kernel Loaded. Transferring control",10,13,0

TIMES 510 - ($ - $$) db 0   ;pad to exact sector size (512) minus signature
DW 0xAA55 			;boot loader signature

kernel code

Code: Select all

;kernelette code

[BITS 16]

%assign BIOS_VIDEO_SERVICES			0x10

	mov AH, 0x0E 
	mov BH, 0x00 
	mov BL, 0x07 

hello_again:
	MOV SI, message_hello 	        ;move msg to SI-pointer
	CALL print 				;call function to print SI (msg)

	mov ah,0  				;wait for keypress
	int 16h

	jmp hello_again

print:
	mov bp,sp
	print_repeat:
	lodsb
	or al,al
	jz print_done
	mov ah,0x0e
	mov bx,0
	int BIOS_VIDEO_SERVICES
	jmp print_repeat
	
print_done:
	mov sp,bp
	ret

message_hello db 'Hello world from the kernel!', 13, 10, '  Press any key to continue!', 13, 10, 0

TIMES 512 - ($ - $$) db 0 ;pad the sector 
Code or code not. There is no try.
User avatar
TightCoderEx
Member
Member
Posts: 90
Joined: Sun Jan 13, 2013 6:24 pm
Location: Grande Prairie AB

Re: NASM JMP offset ignored

Post by TightCoderEx »

What you're read and your understanding of the instruction is correct.

The only way any of those combinations can work is if there is nothing preventing system from wrapping around. Therefore jumping to 0x1000:0xffff would work so long as the next 16 instructions at that address don't prevent wrap around. Have a look at your disk image or what the software you're using for testing is doing.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: NASM JMP offset ignored

Post by Brendan »

Hi,
davidpi wrote:I have read all I can about the JMP instruction and nothing says real mode JMP immediate ignores the offset. My code is below.
In real mode, JMP doesn't ignore the offset; therefore there must be a problem with how you're testing your code.

For example, maybe there's a problem with the makefiles/scripts/whatever you're using to build your project (e.g. maybe the file is assembled but a floppy image isn't updated, so the emulator you're using boots an old copy of the code from the floppy image and doesn't boot the new code with a different JMP offset).

For another example, maybe you're not using "single-step debugging", and maybe the JMP actually does work correctly; but the memory at those offsets (at 0x1000:0x0200, 0x1000:0xDADA, etc) is full of zeros so the CPU thinks they're ADD instructions and executes them until IP wraps around to 0x0000, and you see that the code at 0x1000:0x0000 does get executed (kernel still prints the hello message) and assume it's because the JMP didn't work when it actually did.

The best way to figure out what is going on is with something like the single-step debugger in Bochs, which displays the instruction from RAM (and not from a file) immediately before it's executed and lets you see "CS:IP" immediately after it's executed.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
0b1
Member
Member
Posts: 35
Joined: Sun Feb 04, 2018 8:04 pm

Re: NASM JMP offset ignored

Post by 0b1 »

Thank you both...both answers pointed me in the right direction.

After a bit of a learning curve on the bochs debugger, I found that the 'empty' segment data at the end of my 80 byte kernel was treated as a series of NOPs to the end of the stack, at which point a GPF was triggered. The GPF's RET effectively reset the IP to zero and continued execution at the start of the segment ... my kernelette's entry point!

So it was effectively a wrap-around and did need a single-step debugger to figure it out. =D>

A great learning experience, that got me started with the bochs debugger, not as daunting as I initially thought.

Now I feel much more confident, not quite so much of a NOOB.

Thanks again.

DP
Code or code not. There is no try.
Post Reply