Long jump assembly

Hello,

I am trying to write some assembly to perform a long jump for entering long mode (in a kernel), with stable rust.

Here is the problem I have.

core::arch::asm!(
            ".code32
        ljmp $0x8, $2f",
            "2:",
            options(att_syntax)
        );

That statement gives me a compiler error:

error: invalid operand for instruction
   --> src/main.rs:165:5
    |
165 |     ljmp 0x08, long_mode
    |     ^
    |

I don't believe this is suppose to happen. Am I wrong or is the compiler having a bug?

1 Like

Could you share the small reproducible example? I've tried to just put this code in fn main() { unsafe { ... } } and got linker error, not rustc error, so there's definitely something else going on here.

Hmmm, well what's weird is it seems to work fine in godbolt's rust compiler.

fn main() {
unsafe { core::arch::asm!(
".code32
ljmp $0x8, $2f",
"2:",
options(att_syntax)
); }
}

godbolt says

main:
push rax
ljmp 8, offset .Ltmp1
.Ltmp1:
pop rax
ret

I ended up changing my assembly to the following.

core::arch::asm!(
".code32
movl $0x8, %eax
pushl %eax
movl $2f, %eax
pushl %eax
retl",
"2:",
options(att_syntax)
);

1 Like

I don't think that code is correct either. That code enters in 32bit mode but exits in 64bit mode. The compiler has no clue about this and will either emit 32bit code or 64bit code depending on the target. I think you will need to use two separate crates, one for 32bit and one for 64bit where the 32bit one contains this asm block except with a call of a function in the 64bit crate at the end which will never return. Or you could use global asm depending on how it enters the 32bit code.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.