rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
97.09k stars 12.55k forks source link

global_asm! rejects real mode far jmp even if correct #84676

Open Qubasa opened 3 years ago

Qubasa commented 3 years ago

I tried this code:

.section .init_bootloader, "awx"
.intel_syntax noprefix

.code16
smp_trampoline:
    # clear the direction flag (e.g. go forward in memory when using
    # instructions like lodsb)
    cld
    # disable interrupts
    cli

    # zero data segment
    xor ax, ax
    mov ds, ax

    # Set the A20 line
    in    al, 0x92
    or    al, 2
    out 0x92, al

    # Load 32-bit GDT
    lgdt gdt32_pointer

    # Enable protected mode
    mov eax, cr0
    or  eax, (1 << 0)
    mov cr0, eax
    # normally this should be jmp 0x8:mylabel
    jmp 0x8:protected_mode_setup

.code32
protected_mode_setup:
    jmp protected_mode_setup

.align 4
gdt32:
    .quad 0x0000000000000000          # Null Descriptor - should be present.
    .quad 0xffff0000009acf00          # 32-bit code descriptor (exec/read).
    .quad 0xffff00000092cf00          # 32-bit data descriptor (read/write)
gdt32_end:

.align 4
gdt32_pointer:
   .word gdt32_end - gdt32 - 1  # 16-bit Size (Limit) of GDT.
   .long gdt32                  # 32-bit Base Address of GDT. (CPU will zero extend to 64-bit)

A repo with minimal sample code: https://github.com/Luis-Hebendanz/rust_asm_error

I expected to see this happen: Compile without errors because it is valid asm. The gas assembler can compile it without problems.

Instead, this happened: It fails with an error: unexpected token in argument list

Meta

rustc --version --verbose:

rustc 1.53.0-nightly (42816d61e 2021-04-24)
binary: rustc
commit-hash: 42816d61ead7e46d462df997958ccfd514f8c21c
commit-date: 2021-04-24
host: x86_64-unknown-linux-gnu
release: 1.53.0-nightly
LLVM version: 12.0.0
Backtrace

``` Compiling rust_err v0.1.0 (/home/lhebendanz/Projects/rust_err) error: unexpected token in argument list | note: instantiated into assembly here --> :33:12 | 33 | jmp 0x8:protected_mode_setup | ^ error: aborting due to previous error error: could not compile `rust_err` To learn more, run the command again with --verbose. ```

Soveu commented 3 years ago

For some reason, jmp segment:pointer doesn't work in inline asm ljmp segment, offset pointer has to be used

Soveu commented 3 years ago

@rustbot label: +A-inline-assembly +O-x86

nagisa commented 3 years ago

Compile without errors because it is valid asm. The gas assembler can compile it without problems.

To be very pedantic, what valid ASM for the purposes of rustc looks like is dictated by LLVM, not the GNU (or any other, for that matter) toolchain. As LLVM postdates use of the real mode by a lot it is very plausible that its assembly parser(s) will be quite spotty in that respect.

Ben-Lichtman commented 1 year ago

Inline asm seems to be even more restrictive:

unsafe {
    core::arch::asm!(
        "
        .code16
        ljmp 0, offset 1f
        1:
        int3
        .code64
        ",
        options(noreturn)
    )
}

seems to also be invalid syntax for inline asm with the same error (along with ljmp 0, 1f and ljmp 0:1f syntax). I'm not sure of any way to work around this problem...