Author Topic: Far jump from long mode  (Read 22936 times)

Offline Roman

  • Jr. Member
  • *
  • Posts: 10
Far jump from long mode
« on: August 14, 2012, 06:41:03 AM »
Hi, All!
Thanks for your help in the previous topics:)
I have a problem again:
I write code for leaving  long mode, and i need make a far jump to compatibility mode.
In all examples, which i found, it write as
Code: [Select]
; fasm
jump_value:
        dq jump_offset
        dd jump_selector
; ....
jmp tbyte [jump_value]
but NASM not supported it.
I try replace tbyte to tword and nasm write: "error: mismatch in operand sizes"
How i can make this?

P.S. sorry for my English :)

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Far jump from long mode
« Reply #1 on: August 14, 2012, 07:13:12 AM »
I'm surprised your jump_selector is dd. I would have expected dw. I think selectors are 16 bits, even in long mode, no? I don't think it makes any difference.

I think just:
Code: [Select]
jmp far [jump_value]
will do it. I can't test this, but it looks like plausible opcodes. If Fasm emits something different, get back to us...

Best,
Frank



Offline Roman

  • Jr. Member
  • *
  • Posts: 10
Re: Far jump from long mode
« Reply #2 on: August 14, 2012, 08:36:35 AM »
I'm surprised your jump_selector is dd. I would have expected dw.
Yes, of course, I confused :)
what you suggest does not work too.
Maybe I'm giving the wrong address to jump_offset...

Offline Roman

  • Jr. Member
  • *
  • Posts: 10
Re: Far jump from long mode
« Reply #3 on: August 14, 2012, 11:28:20 AM »
Address is right, i check it
Code: [Select]
mov rax, some_addr
jmp rax

some_addr:
    ; print "Hello"
but code:
Code: [Select]
jmp far [jump_value]
jump_value:
        dq some_addr
        dw  CODE_SELECTOR
don't work :(

Offline Roman

  • Jr. Member
  • *
  • Posts: 10
Re: Far jump from long mode
« Reply #4 on: August 14, 2012, 11:41:21 AM »
I try simple code
Code: [Select]
; in long mode
jmp [jmp_v]
jmp_v:
     dd ToLa(lbl)
lbl:
; some code
where ToLa() is macro for make linear address from offset
and it don't work

What I'm doing wrong?

Offline avcaballero

  • Full Member
  • **
  • Posts: 133
  • Country: es
    • Abre los Ojos al Ensamblador
Re: Far jump from long mode
« Reply #5 on: August 14, 2012, 12:28:20 PM »
Are you sure you need far jumps? Be careful with brackets

Example 1 (this one works fine):
Code: [Select]
[org 100h]
[section .text]
  jmp   Etiqueta
  msg   DB 'Hola, mundo!$'

Etiqueta:
  MOV   DX, msg
  MOV   AH, 9   
  INT   21h     
  MOV   AX, 4c00h
  INT   21h       


Example 2 (this other one not):
Code: [Select]
[org 100h]
[section .text]
  jmp   [Etiqueta]
  msg   DB 'Hola, mundo!$'

Etiqueta:
  MOV   DX, msg
  MOV   AH, 9   
  INT   21h     
  MOV   AX, 4c00h
  INT   21h       

Why Example 2 does not work?:
Code: [Select]
D:\Alfonso\AVCH>debug prueba2.com
-u
0D81:0100 FF261101      JMP     [0111]
0D81:0104 48            DEC     AX
0D81:0105 6F            DB      6F
0D81:0106 6C            DB      6C
0D81:0107 61            DB      61
0D81:0108 2C20          SUB     AL,20
0D81:010A 6D            DB      6D
0D81:010B 756E          JNZ     017B
0D81:010D 64            DB      64
0D81:010E 6F            DB      6F
0D81:010F 2124          AND     [SI],SP
0D81:0111 BA0401        MOV     DX,0104
0D81:0114 B409          MOV     AH,09
0D81:0116 CD21          INT     21
0D81:0118 B8004C        MOV     AX,4C00
0D81:011B CD21          INT     21
0D81:011D 64            DB      64
0D81:011E 69            DB      69
0D81:011F 7265          JB      0186
-p

AX=0000  BX=0000  CX=001D  DX=0000  SP=FFFE  BP=0000  SI=0000  DI=0000
DS=0D81  ES=0D81  SS=0D81  CS=0D81  IP=04BA   NV UP EI PL NZ NA PO NC
0D81:04BA 68            DB      68

You have jumped to the value saved in [0111] = BA04h (we are working in 16 bits), and because of little endians: 04BAh.

If I'm not wrong you need far jumps for different segments (I need review it ;-)). An example that I did some time ago that works
http://www.abreojosensamblador.net/Productos/AOE/html/Codigos/Cap12/RelojCN1.asm
Code: [Select]
JMP       FAR [CS:OldInt8h]
I needed use it in such a way because I handled a system interruption Int08, surely in other segment.

Cheers

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Far jump from long mode
« Reply #6 on: August 14, 2012, 12:51:11 PM »
Code: [Select]
jmp far [jump_value]
jump_value:
        dq some_addr
        dw  CODE_SELECTOR
don't work :(

The biggest problem with that code is architectural. The original AMD64 instruction set did not support/encode JMP FAR MEM16:64, therefore it is not universal and such code should be avoided.

The following code is three different ways that should put the processor into compatibility mode. It assumes that COMPAT_SEL is a valid (protected mode code, IIRC) GDT selector. Operative word being should, as my working knowledge is a bit rusty and some minor changes may be needed.

Also note that o64 retf should probably be its own instruction called retfq, akin to iretq. It was probably overlooked due to imprecise instruction set documentation. However, %define retfq o64 retf should suffice in the interim.

Code: [Select]
[BITS 64]
%define retfq o64 retf
%define COMPAT_SEL 8 ;Compatibility Mode GDT Selector (change as needed)

;Indirect 32-bit Far Jump Version
jmp far DWORD[ptr] ;JMP FAR MEM16:32 (works on all x86-64 processors)
ptr:
DD COMPAT_START ;EIP of Compatibility Mode Entrypoint
DW COMPAT_SEL ;Compatibility Mode GDT Selector

;RETFQ Version
push COMPAT_SEL ;Push Compatibility Mode GDT Selector
push COMPAT_START ;Push RIP of Compatibility Mode Entrypoint
retfq ;64-bit RETF

;IRETQ Version
mov rbx,rsp ;Current Stack Pointer
mov ax,ss ;Segment Selector
movzx eax,ax ;Zero Extend top 48-bits of RAX
push rax ;Push QWORD Aligned SS
push rbx ;Push Desired Stack Pointer
pushfq ;Push RFLAGS
push COMPAT_SEL ;Push Compatibility Mode GDT Selector
push COMPAT_START ;Push RIP of Compatibility Mode Entrypoint
iretq ;Return from Long Mode Interrupt

[BITS 32]
;Compatibility Mode Entrypoint
COMPAT_START:
jmp $

HtH.

Offline Roman

  • Jr. Member
  • *
  • Posts: 10
Re: Far jump from long mode
« Reply #7 on: August 14, 2012, 01:51:00 PM »
avcaballero, thanks, but your examples for 16 bit mode.
Keith Kanios, Thank you very much!
I have some questions:
Can i use protected mode code selector instead of COMPAT_SEL?
Do I need to first calculate the linear address of the label COMPAT_START or i should use COMPAT_START as is?

Offline Roman

  • Jr. Member
  • *
  • Posts: 10
Re: Far jump from long mode
« Reply #8 on: August 15, 2012, 06:29:50 AM »
Code: [Select]
;RETFQ Version
push COMPAT_SEL ;Push Compatibility Mode GDT Selector
push COMPAT_START ;Push RIP of Compatibility Mode Entrypoint
retfq ;64-bit RETF
It's work for me :)

and i have answers for my questions
Quote
Can i use protected mode code selector instead of COMPAT_SEL?
Yes
Quote
Do I need to first calculate the linear address of the label COMPAT_START or i should use COMPAT_START as is?
]
use label as is

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Far jump from long mode
« Reply #9 on: August 15, 2012, 10:27:36 AM »
Code: [Select]
;RETFQ Version
push COMPAT_SEL ;Push Compatibility Mode GDT Selector
push COMPAT_START ;Push RIP of Compatibility Mode Entrypoint
retfq ;64-bit RETF
It's work for me :)

Good. Thanks for letting us know that said method does work.

I think most OS code will use the IRETQ method since the interrupt handler is already there and will also work as-is for returning to a compatibility mode process.

and i have answers for my questions
Quote
Can i use protected mode code selector instead of COMPAT_SEL?
Yes

Yep. As alluded to in my initial reply -- (protected mode code, IIRC) -- a compatibility mode selector is the same as you would use for 32-bit protected mode.

Quote
Do I need to first calculate the linear address of the label COMPAT_START or i should use COMPAT_START as is?
]
use label as is

Yes, as long as the reference is absolute, which it should be in the above code context.