Page 1 of 1

general assembly help

Posted: Thu Jan 15, 2009 12:28 pm
by yemista
Ok, So I wrote a small program that tests to make sure I can get interrupts working in pmode by making 50 generic interrupt handlers that just return and making the kbd int print to the screen. This code is loaded by the boot loader to 0x00100001, just after the 1MB mark. Now I know the loader code works because before I loaded a different test program and verified it ran, but i run into a weird bug with the interrupt program. From what I debugged, it fails at a jmp instruction I have near the end, and dissassembled, this instruction looks like jmp ffffff01.
I dont have the exact address, but I know for sure it had a lot of f's and was a high address when it shouldve been a local jump. I have no clue what to think about this. should 32 bit pmode code be align 4 or align 8? Thats my only guess, but I still cant see how nasm is generating that address for a label in a 1500 byte program that starts at 0

Re: general assembly help

Posted: Thu Jan 15, 2009 1:11 pm
by Love4Boobies
Maybe you could show us some code? Also, 0x00100000 is where people usually load, you're wasting one precious byte :(

Re: general assembly help

Posted: Thu Jan 15, 2009 1:28 pm
by yemista
ok, as soon as i get home from work, i will post the code, the instruction where its failing, and
also the way that instruction looks dissassembled.

Re: general assembly help

Posted: Thu Jan 15, 2009 7:36 pm
by yemista
here is the code:

Code: Select all

[bits 32]			;[org 0x0011]			
[org 0x0001]
	
jmp idt_install


KERNEL_CODE_SEL    	equ		0x08

;;;;;;;;;;;;;;;;;;;;;;   JUST FOR NOW
isr_common_stub:
	; ack the pic
	mov al, 0x20
	out 0x20, al

	iret		


%macro CREATE_ISR 1 
	isr#%1:
	jmp isr_common_stub
%endmacro

%assign 	i 	0
%rep 51
	CREATE_ISR i
	%assign i (i + 1)
%endrep



; ------------------------------------------
; Interrupt Descriptor Table
; ------------------------------------------
; idt_entry is
; 0 base_low.w
; 2 code_segment_selector.w
; 4 always0.b
; 5 flags.b
; 6 base_high.w
; end idt_entry = 8 bytes


;;;;;;;;   section '.data' 




idtr: dw idt_end - idt - 1 	; IDT limit
	dd idt 				; address of IDT

; ------------------------------------------


%macro make_idt_entry 0
	dw 0 ; isr0 and 0xFFFF
	dw KERNEL_CODE_SEL
	db 0
	db 0x8E ; Access flags: Running in kernel mode (| 0x60 for usermode)
	dw 0 ; (isr#num shr 16) and 0xFFFF
%endmacro



idt: 
	%rep  51  
		make_idt_entry         ;(32+16+3) ; exceptions+interrupts+syscall
	%endrep
	


idt_end:



; IDT -> ISR installation
%macro set_idt_entry 1 
	; base_lo = isr0 and 0xFFFF
	mov eax, isr#%1
	mov [idt+ %1 * 8], ax
	; base_hi = (isr0 >> 16) and 0xFFFF
	shr eax, 16
	mov [idt + %1 * 8 + 6], ax
%endmacro


idt_install:

lidt [idtr]

; remap irq here

mov al, 0x11		; send ICW1
out 0x20, al
out 0xA0, al 

; ICW2
mov al, 0x20		; remap 1st half of PIC
out 0x21, al
mov al, 0x28		; then 2nd half
out 0xA1, al

; ICW3
mov al, 4
out 0x21, al
mov al, 2
out 0xA1, al

; ICW4
mov al, 0x01
out 0x21, al
out 0xA1, al

; disable interrupts
; mov al, 0xFF
; out 0x21, al

cli


%assign 	i 	0

%rep 50
	set_idt_entry i
	%assign i (i+1)
%endrep

jmp setup_kbd

;;;	CUSTOM TEST CODE


kbd_int:
	pusha
	in al, 0x60
	mov ecx, [counter]
	mov ebx, 0xb8000
	mov [es:ebx+ecx], al
	inc ecx
	mov [counter], ecx
	popa
	jmp isr_common_stub

; set 9th idt descriptor to point to kdb_int
setup_kbd:
	mov eax, kbd_int
	mov [idt + 9 * 8], ax
	; base_hi = (isr0 >> 16) and 0xFFFF
	shr eax, 16
	mov [idt + 9 * 8 + 6], ax
	mov ax, 0x18
	mov es, ax

sti

;; hang here to see if everything(or anything) works
wait_and_see:
	
	jmp wait_and_see
	
	
counter		db	0

Now the problem is that for some reason none of the jumps are resolving to the right address except the very first one. This is the disassembled code through bochs. all those jumps are the isr definitions and they should all be jumping to the same place, namely 0x00100001.

Code: Select all

00100001: (                    ): jmp .+0x00000209          ; e909020000
00100006: (                    ): mov al, 0x20              ; b020
00100008: (                    ): out 0x20, al              ; e620
0010000a: (                    ): iretd                     ; cf
0010000b: (                    ): jmp .+0xfffffff9          ; ebf9
0010000d: (                    ): jmp .+0xfffffff7          ; ebf7
0010000f: (                    ): jmp .+0xfffffff5          ; ebf5
00100011: (                    ): jmp .+0xfffffff3          ; ebf3
00100013: (                    ): jmp .+0xfffffff1          ; ebf1
00100015: (                    ): jmp .+0xffffffef          ; ebef
00100017: (                    ): jmp .+0xffffffed          ; ebed
00100019: (                    ): jmp .+0xffffffeb          ; ebeb
0010001b: (                    ): jmp .+0xffffffe9          ; ebe9
0010001d: (                    ): jmp .+0xffffffe7          ; ebe7
0010001f: (                    ): jmp .+0xffffffe5          ; ebe5

Re: general assembly help

Posted: Fri Jan 16, 2009 2:48 am
by AJ
Post fixed by the code tags police :) Please use code tags in future.

Cheers,
Adam

Re: general assembly help

Posted: Fri Jan 16, 2009 8:30 am
by yemista
the only thing i can think of is that these are unsigned numbers and showing up as negative jumps, but i thought a jump was to a real offset, not a relative offset.

Re: general assembly help

Posted: Fri Jan 16, 2009 9:58 am
by Brendan
Hi,
yemista wrote:the only thing i can think of is that these are unsigned numbers and showing up as negative jumps, but i thought a jump was to a real offset, not a relative offset.
The CPU supports absolute jumps and relative jumps (and indirect jumps). Relative jumps cost 2 bytes. Absolute jumps cost 3 bytes (16-bit code) or 5 bytes (32-bit code). Most assemblers, etc will use a relative jump to reduce code size (if the target can be reached with "eip + 8-bit signed offset").

This doesn't explain why the first jump isn't also a relative jump - I'm guessing you didn't enable the optimizer (e.g. "nasm -Ox") and the assembler couldn't figure out if the target could be reached with a relative jump or not because it only did a single pass.

Finally, that first jump looks like it jumps to the wrong address, while the relative jumps look like they jump to the correct address. The first jump is an absolute jump, which means the assembler needs to know which address the target will be. For the relative jumps, the assembler only needs to know how many bytes to jump forward or backward and doesn't need to know the address the target will be. From this I'd assume you didn't put "org 0x00100001" at the start of your code (and maybe you put "org 0x00000209" instead???); or perhaps your linker script isn't right.


Cheers,

Brendan

Re: general assembly help

Posted: Fri Jan 16, 2009 2:03 pm
by yemista
i put [org 0x0001] at the start of the code, not [org 0x00100001]. Maybe this is the problem? I will try again once I get home. How do you make it so that you can decide if it will be a relative jump or an absolute jump? I dont think that first jump is wrong, because the segmentation fault occurs at a jump much further down in the code, which means it must execute that first jump correctly.

Re: general assembly help

Posted: Sun Jan 18, 2009 12:28 am
by yemista
i changed org to 0x00100001, and i noticed that for some reason, it is falling through the first jmp in the file. I get the failure at the iret, which it should not be hitting if it does the jump correctly

Re: general assembly help

Posted: Sun Jan 18, 2009 5:33 am
by Brendan
Hi,
yemista wrote:i put [org 0x0001] at the start of the code, not [org 0x00100001]. Maybe this is the problem?
Telling the assembler your code is running at one address and then running that code at a different address might be part of the problem...
yemista wrote:How do you make it so that you can decide if it will be a relative jump or an absolute jump? I dont think that first jump is wrong, because the segmentation fault occurs at a jump much further down in the code, which means it must execute that first jump correctly.
I took a look at the JMP instruction in Intel's manual. All conditional branches (JC, JNE, etc) are always relative and so are normal JMP instructions (e.g. "JMP foo"); where the target of the jump is encoded as either an 8-bit signed number, a 16-bit signed number, or an 16-bit signed number, and is an offset from EIP. This means I was wrong before - the first jump is relative not absolute.

Absolute jumps are only done for far jumps (e.g. "jmp seg:offset"), and indirect jumps are absolute too (e.g. "jmp [foo]" where there's an absolute address stored at "foo").
yemista wrote:i changed org to 0x00100001, and i noticed that for some reason, it is falling through the first jmp in the file. I get the failure at the iret, which it should not be hitting if it does the jump correctly
Given that the first jump actually is relative, changing the ORG won't make any difference (for that jump).

I'm guessing that there's probably lots of other problems elsewhere. I'd also assume you're not using effective debugging techniques to find out what's actually going wrong, and working with misleading symptoms because of that..


Cheers,

Brendan