Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ members = [
"userspace/vibix_abi",
"userspace/vibix_libc",
"userspace/vibix_libc_defs",
"userspace/ld_vibix",
"userspace/hello_dyn",
]
# tests/pjdfstest is a vendored copy of saidsay-so/pjdfstest (2-clause BSD). It
# is intentionally kept outside the workspace until #581 wires it into xtask —
Expand Down
3 changes: 3 additions & 0 deletions kernel/limine.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ serial: yes
module_path: boot():/boot/rootfs.tar
module_path: boot():/boot/ld-musl-x86_64.so.1
module_path: boot():/boot/stub_interp.elf
module_path: boot():/boot/ld-vibix.so
module_path: boot():/boot/libc.so
module_path: boot():/boot/userspace_hello_dyn.elf
2 changes: 1 addition & 1 deletion tests/fixtures/ext2_image.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a2b6c77f95269c4c3ce8feb64f6a1c0a6c1825ee4e9c3a829d1291fc855fac42
8322bed0e51dc05695bb4c097a0901091603f97a5af0f56fba0fda05d550b15f
14 changes: 14 additions & 0 deletions userspace/hello_dyn/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "userspace_hello_dyn"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description = "Dynamically-linked hello world test binary for ld-vibix.so"

[[bin]]
name = "userspace_hello_dyn"
path = "src/main.rs"

[dependencies]
vibix_libc = { path = "../vibix_libc" }
87 changes: 87 additions & 0 deletions userspace/hello_dyn/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* Linker script for dynamically-linked userspace binaries.
*
* Produces an ET_DYN (PIE) executable with a PT_INTERP segment pointing
* to /lib/ld-vibix.so. The kernel loads the interpreter at
* INTERP_LOAD_BASE and transfers control to it.
*
* Base address 0x400000 matches static executables. The binary still
* contains relocations (.rela.dyn) that the dynamic linker processes.
*/

OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)

PHDRS
{
interp PT_INTERP FLAGS(4); /* R */
text PT_LOAD FLAGS(5); /* R+X */
rodata PT_LOAD FLAGS(4); /* R */
data PT_LOAD FLAGS(6); /* R+W */
dynamic PT_DYNAMIC FLAGS(6); /* R+W */
}

SECTIONS
{
. = 0x0000000000400000;

.interp : {
*(.interp)
} :interp :text

.text : {
*(.text .text.*)
} :text

. = ALIGN(CONSTANT(MAXPAGESIZE));

.rodata : {
*(.rodata .rodata.*)
} :rodata

.rela.dyn : {
*(.rela.dyn .rela.dyn.*)
*(.rela.plt)
} :rodata

.dynsym : {
*(.dynsym)
} :rodata

.dynstr : {
*(.dynstr)
} :rodata

.hash : {
*(.hash)
} :rodata

.gnu.hash : {
*(.gnu.hash)
} :rodata

. = ALIGN(CONSTANT(MAXPAGESIZE));

.dynamic : {
*(.dynamic)
} :data :dynamic

.got : {
*(.got .got.plt)
} :data

.data : {
*(.data .data.*)
} :data

.bss : {
*(COMMON)
*(.bss .bss.*)
} :data

/DISCARD/ : {
*(.eh_frame*)
*(.note.*)
*(.comment)
}
}
67 changes: 67 additions & 0 deletions userspace/hello_dyn/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Dynamically-linked hello world — test binary for the vibix dynamic linker.
//!
//! This binary has `PT_INTERP = /lib/ld-vibix.so` in its program headers.
//! When execve'd, the kernel loads ld-vibix.so at INTERP_LOAD_BASE and
//! transfers control to it. The dynamic linker processes relocations and
//! then jumps to this binary's _start.
//!
//! Writes a marker to serial (fd 1) and exits. The marker is checked by
//! the integration test to confirm end-to-end dynamic linking works.

#![no_std]
#![no_main]

use core::panic::PanicInfo;

/// PT_INTERP path — placed in .interp section by the linker script.
#[used]
#[link_section = ".interp"]
static INTERP: [u8; 17] = *b"/lib/ld-vibix.so\0";

const MSG: &[u8] = b"hello_dyn: hello from dynamically-linked binary\n";

#[no_mangle]
pub extern "C" fn _start() -> ! {
// write(1, MSG, MSG.len())
unsafe {
core::arch::asm!(
"syscall",
inlateout("rax") 1u64 => _,
inlateout("rdi") 1u64 => _,
inlateout("rsi") MSG.as_ptr() as u64 => _,
inlateout("rdx") MSG.len() as u64 => _,
lateout("rcx") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
lateout("r11") _,
options(nostack, preserves_flags),
);
}
// exit(0)
unsafe {
core::arch::asm!(
"syscall",
inlateout("rax") 60u64 => _,
inlateout("rdi") 0u64 => _,
lateout("rcx") _,
lateout("rdx") _,
lateout("rsi") _,
lateout("r8") _,
lateout("r9") _,
lateout("r10") _,
lateout("r11") _,
options(nostack, preserves_flags),
);
}
loop {
core::hint::spin_loop();
}
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {
core::hint::spin_loop();
}
}
11 changes: 11 additions & 0 deletions userspace/ld_vibix/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "ld_vibix"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
description = "Minimal Rust-based dynamic linker for vibix (eager binding)"

[[bin]]
name = "ld_vibix"
path = "src/main.rs"
71 changes: 71 additions & 0 deletions userspace/ld_vibix/link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* Linker script for ld-vibix.so — the vibix dynamic linker.
*
* Produces an ET_DYN (shared object) ELF loaded by the kernel at
* INTERP_LOAD_BASE (0x4000_0000). The linker uses vaddr 0 as its
* base so all addresses are offsets from the load base.
*/

OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)

SECTIONS
{
. = SIZEOF_HEADERS;

.text : {
*(.text .text.*)
}

. = ALIGN(4096);

.rodata : {
*(.rodata .rodata.*)
}

.rela.dyn : {
*(.rela.dyn .rela.dyn.*)
*(.rela.plt .rela.plt.*)
}

.dynsym : {
*(.dynsym)
}

.dynstr : {
*(.dynstr)
}

.hash : {
*(.hash)
}

.gnu.hash : {
*(.gnu.hash)
}

. = ALIGN(4096);

.dynamic : {
*(.dynamic)
}

.got : {
*(.got .got.plt)
}

.data : {
*(.data .data.*)
}

.bss : {
*(COMMON)
*(.bss .bss.*)
}

/DISCARD/ : {
*(.eh_frame*)
*(.note.*)
*(.comment)
}
}
118 changes: 118 additions & 0 deletions userspace/ld_vibix/src/elf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//! ELF64 structure definitions for the dynamic linker.

#![allow(dead_code)]

/// ELF64 file header.
#[repr(C)]
pub struct Elf64Ehdr {
pub e_ident: [u8; 16],
pub e_type: u16,
pub e_machine: u16,
pub e_version: u32,
pub e_entry: u64,
pub e_phoff: u64,
pub e_shoff: u64,
pub e_flags: u32,
pub e_ehsize: u16,
pub e_phentsize: u16,
pub e_phnum: u16,
pub e_shentsize: u16,
pub e_shnum: u16,
pub e_shstrndx: u16,
}

/// ELF64 program header.
#[repr(C)]
pub struct Elf64Phdr {
pub p_type: u32,
pub p_flags: u32,
pub p_offset: u64,
pub p_vaddr: u64,
pub p_paddr: u64,
pub p_filesz: u64,
pub p_memsz: u64,
pub p_align: u64,
}

/// ELF64 dynamic section entry.
#[repr(C)]
pub struct Elf64Dyn {
pub d_tag: i64,
pub d_val: u64,
}

/// ELF64 symbol table entry.
#[repr(C)]
pub struct Elf64Sym {
pub st_name: u32,
pub st_info: u8,
pub st_other: u8,
pub st_shndx: u16,
pub st_value: u64,
pub st_size: u64,
}

/// ELF64 relocation entry with addend.
#[repr(C)]
pub struct Elf64Rela {
pub r_offset: u64,
pub r_info: u64,
pub r_addend: i64,
}

// Program header types.
pub const PT_LOAD: u32 = 1;
pub const PT_DYNAMIC: u32 = 2;
pub const PT_TLS: u32 = 7;
pub const PT_GNU_RELRO: u32 = 0x6474E552;

// Program header flags.
pub const PF_X: u32 = 1;
pub const PF_W: u32 = 2;
pub const PF_R: u32 = 4;

// Dynamic section tags.
pub const DT_NULL: i64 = 0;
pub const DT_NEEDED: i64 = 1;
pub const DT_STRTAB: i64 = 5;
pub const DT_SYMTAB: i64 = 6;
pub const DT_RELA: i64 = 7;
pub const DT_RELASZ: i64 = 8;
pub const DT_STRSZ: i64 = 10;
pub const DT_SYMENT: i64 = 11;
pub const DT_SONAME: i64 = 14;
pub const DT_JMPREL: i64 = 23;
pub const DT_PLTRELSZ: i64 = 2;

// Relocation types (x86_64).
pub const R_X86_64_NONE: u32 = 0;
pub const R_X86_64_64: u32 = 1;
pub const R_X86_64_GLOB_DAT: u32 = 6;
pub const R_X86_64_JUMP_SLOT: u32 = 7;
pub const R_X86_64_RELATIVE: u32 = 8;

// Symbol binding (from st_info).
pub const STB_LOCAL: u8 = 0;
pub const STB_GLOBAL: u8 = 1;
pub const STB_WEAK: u8 = 2;

// Symbol type (from st_info).
pub const STT_NOTYPE: u8 = 0;
pub const STT_FUNC: u8 = 2;

// Special section index.
pub const SHN_UNDEF: u16 = 0;

impl Elf64Sym {
pub fn binding(&self) -> u8 {
self.st_info >> 4
}

pub fn sym_type(&self) -> u8 {
self.st_info & 0xf
}

pub fn is_defined(&self) -> bool {
self.st_shndx != SHN_UNDEF
}
}
Loading
Loading