diff --git a/src/arch/x86_64/i386_gotpcrel.s b/src/arch/x86_64/i386_gotpcrel.s new file mode 100644 index 00000000..1c1b7b3f --- /dev/null +++ b/src/arch/x86_64/i386_gotpcrel.s @@ -0,0 +1,27 @@ +//! PC-relative addressing on i386. + +/// Performs PC-relative addressing on i386. +/// +/// This macro puts the address of `sym` into `reg` using the GOT. +/// +/// On x86-64, this would just be the following line: +/// +/// ```asm +/// mov \reg, qword ptr [rip + \sym@GOTPCREL] +/// ``` +/// +/// On i386, though, there is no direct way to access EIP. +/// Thus, we need to push the current EIP to the stack via `call`. +/// Then, we to adjust it's value and resolve the symbol via the GOT. +.macro movgot reg, sym + call 2f +2: + pop \reg +3: +// LLVM currently rejects the equivalent Intel syntax: +// https://github.com/llvm/llvm-project/issues/161550 +.att_syntax prefix + addl $_GLOBAL_OFFSET_TABLE_ + (3b - 2b), %\reg +.intel_syntax noprefix + mov \reg, dword ptr [\reg + \sym@GOT] +.endm diff --git a/src/arch/x86_64/platform/linux/mod.rs b/src/arch/x86_64/platform/linux/mod.rs index b0bf04ab..e2924451 100644 --- a/src/arch/x86_64/platform/linux/mod.rs +++ b/src/arch/x86_64/platform/linux/mod.rs @@ -18,8 +18,10 @@ use crate::arch::x86_64::physicalmem::PhysAlloc; use crate::arch::x86_64::{KERNEL_STACK_SIZE, SERIAL_IO_PORT, page_tables}; use crate::fdt::Fdt; +#[allow(bad_asm_style)] mod entry { core::arch::global_asm!( + include_str!("../../i386_gotpcrel.s"), include_str!("entry.s"), rust_start = sym super::rust_start, stack = sym crate::arch::x86_64::stack::STACK, diff --git a/src/arch/x86_64/platform/multiboot/entry.s b/src/arch/x86_64/platform/multiboot/entry.s index 1cf64a67..e60f583d 100644 --- a/src/arch/x86_64/platform/multiboot/entry.s +++ b/src/arch/x86_64/platform/multiboot/entry.s @@ -29,10 +29,27 @@ mboot: .align 4 .global _start _start: + + movgot eax, {stack} + + call 2f +2: + pop ebx +// LLVM currently rejects the equivalent Intel syntax: +// https://github.com/llvm/llvm-project/issues/161550 +.att_syntax prefix + addl $_GLOBAL_OFFSET_TABLE_ + (3f - 2b), %ebx +3: +.intel_syntax noprefix + mov ecx, dword ptr [ebx + {stack}@GOTPCREL] + +2: + jmp 2b + cli # avoid any interrupt # Initialize stack pointer - mov esp, OFFSET {stack} + movgot esp, {stack} add esp, {stack_top_offset} # Move the 32-bit physical address of the Multiboot information structure into `RDI` as first argument to `rust_start`. @@ -72,7 +89,7 @@ cpu_init: jz Linvalid # They aren't, there is no long mode. # Set CR3 - mov eax, OFFSET {level_4_table} + movgot eax, {level_4_table} mov cr3, eax # we need to enable PAE modus @@ -102,11 +119,18 @@ cpu_init: or eax, (1 << 31) # enable paging mov cr0, eax - lgdt [{gdt_ptr}] # Load the 64-bit global descriptor table. + movgot eax, {gdt_ptr} + + lgdt [eax] # Load the 64-bit global descriptor table. + + push {kernel_code_selector} + movgot eax, start64 + push eax + retf # https://github.com/llvm/llvm-project/issues/46048 .att_syntax prefix # Set the code segment and enter 64-bit long mode. - ljmp ${kernel_code_selector}, $start64 + # ljmp ${kernel_code_selector}, $start64 .intel_syntax noprefix # there is no long mode @@ -125,7 +149,7 @@ start64: mov gs, eax cld # set default stack pointer - movabs rsp, OFFSET {stack} + mov rsp, [rip + {stack}@GOTPCREL] add rsp, {stack_top_offset} # jump to the boot processors's C code diff --git a/src/arch/x86_64/platform/multiboot/mod.rs b/src/arch/x86_64/platform/multiboot/mod.rs index aa0ae607..71991f1e 100644 --- a/src/arch/x86_64/platform/multiboot/mod.rs +++ b/src/arch/x86_64/platform/multiboot/mod.rs @@ -22,6 +22,7 @@ use crate::os::executable_end; #[allow(bad_asm_style)] mod entry { core::arch::global_asm!( + include_str!("../../i386_gotpcrel.s"), include_str!("entry.s"), rust_start = sym super::rust_start, stack = sym crate::arch::x86_64::stack::STACK, diff --git a/xtask/src/ci/qemu.rs b/xtask/src/ci/qemu.rs index d989d280..ca4d1d14 100644 --- a/xtask/src/ci/qemu.rs +++ b/xtask/src/ci/qemu.rs @@ -67,6 +67,7 @@ impl Qemu { let qemu = cmd!(sh, "{program} {arg...}") .args(&["-display", "none"]) .args(&["-serial", "stdio"]) + .args(&["-S", "-s"]) .args(self.machine_args()) .args(self.cpu_args()) .args(self.memory_args());