diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3eb35bcb..8b90e6ca 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -11,6 +11,18 @@ time. ## [Unreleased](https://github.com/bboe/BBoeOS/compare/0.11.0...main) +- **Wire user/libbboeos clang exports into the shared blob.** + `user/libbboeos/libbboeos.a` (clang-compiled) now links into `build/libbboeos` + alongside the asm helpers via the existing ld pipeline; `-ffunction-sections` + + `--gc-sections` drop everything the pointer table doesn't reference, so the + blob pays only for what it actually exports. First entry: `strcmp`, with a + new `FUNCTION_STRCMP_PTR` constant at `FUNCTION_POINTER_TABLE + 52`. + Cc.py-side wiring (extern-call fallback that emits `call + [FUNCTION__PTR]` for unknown names) lands in a follow-up — this PR is + the build-pipeline plumbing. `VDSO_SIGRETURN_OFFSET` moves from `0x460` → + `0xFE0` so the helper region can grow past 1 KB without colliding with the + sigreturn trampoline; sigreturn now lives near the end of page 0 (past the + pointer table at `0x800..0x83C`). - **cc.py: fold byte-immediate store + movzx reload through local.** When a one-shot struct literal local is read via ``*(uint8_t *)&local`` — the driver port-I/O idiom — the compiler was emitting ``mov byte [ebp-N], @@ -22,7 +34,6 @@ time. ~5 bytes per fold and trims the kernel's per-function frame traffic for every bitfield-struct + ``kernel_outb`` site. Total kernel kasm reduction: 217 bytes. - - **Switch libbboeos build to nasm-elf + ld + linker script.** vdso.asm is now `nasm -f elf32`-assembled with section directives (`.libbboeos.function_table`, `.libbboeos.text`, `.libbboeos.rodata`, diff --git a/kernel/include/constants.asm b/kernel/include/constants.asm index b93d46db..a3d7b25b 100644 --- a/kernel/include/constants.asm +++ b/kernel/include/constants.asm @@ -102,6 +102,18 @@ %assign FUNCTION_PRINT_STRING_PTR FUNCTION_POINTER_TABLE + 40 %assign FUNCTION_PRINTF_PTR FUNCTION_POINTER_TABLE + 44 %assign FUNCTION_WRITE_STDOUT_PTR FUNCTION_POINTER_TABLE + 48 + ;; Clang-compiled libbboeos exports (Phase 3+). Sorted + ;; alphabetically — and stays that way until the cc.py extern-call + ;; fallback ships and the first program with a baked-in + ;; FUNCTION__PTR offset gets written to disk. After that + ;; the block becomes append-only (same ABI contract as the + ;; legacy block above) because reordering would shift offsets + ;; under existing on-disk bin/* binaries. Until then, treat + ;; new entries like a freely-reorderable sorted list — insert + ;; in alphabetical position and renumber accordingly. Order + ;; must match the LONG()s after the legacy block in + ;; user/libbboeos/libbboeos.ld. + %assign FUNCTION_STRCMP_PTR FUNCTION_POINTER_TABLE + 52 %assign IPPROTO_ICMP 1 ; Protocol argument to net_open for SOCK_DGRAM ICMP sockets %assign IPPROTO_UDP 17 ; Protocol argument to net_open for SOCK_DGRAM UDP sockets %assign KERNEL_VIRT_BASE 0FF800000h ; Lowest kernel-virt address. User pointers + lengths must stay strictly below this; idt.asm's user-fault triage and access_ok both gate on it. Equals USER_STACK_TOP and DIRECT_MAP_BASE — all three move in lockstep. @@ -280,7 +292,7 @@ %assign USER_DATA_SELECTOR 23h ; GDT[4] | RPL=3: ring-3 data segment (flat 4 GB) %assign USER_STACK_TOP 0FF800000h ; Ring-3 stack top (one past last user-virt page); 64 KB stack at 0xFF7F0000-0xFF800000, 64 KB guard at 0xFF7E0000-0xFF7F0000. Top sits exactly at the user/kernel boundary so ESP=USER_STACK_TOP can push 4 B into [0xFF7FFFFC, 0xFF800000) without crossing into the kernel half. %assign VDSO_PAGE_COUNT_MAX 4 ; Compile-time ceiling on how many 4 KB pages the kernel will map for the shared libbboeos image starting at FUNCTION_TABLE. vdso_install reads `lib/libbboeos` at boot and rounds up to ceil(size / 4096); this constant sizes the per-page phys-frame array (vdso_code_phys) and bounds the per-program map loop in build_child_program_state. Bumping it costs (4 * VDSO_PAGE_COUNT_MAX) bytes of kernel BSS. - %assign VDSO_SIGRETURN_OFFSET 0460h ; offset within the vDSO page (FUNCTION_TABLE) of the __kernel_sigreturn trampoline that ends every signal handler — `mov ah, SYS_SYS_SIGRETURN; int 30h`. + %assign VDSO_SIGRETURN_OFFSET 0FE0h ; offset within the vDSO page (FUNCTION_TABLE) of the __kernel_sigreturn trampoline that ends every signal handler — `mov ah, SYS_SYS_SIGRETURN; int 30h`. Anchored near the end of page 0 (past the pointer table at 0x800..0x83C) so libbboeos.text can grow well past 0x460 as clang-compiled exports accumulate. ;; PIT constants used by entry.asm's IRQ 0 hookup and rtc.c's ;; PIT-driven sleep / tick counter. PIC_EOI lives above with diff --git a/make_os.sh b/make_os.sh index bd12ccb2..45d16976 100755 --- a/make_os.sh +++ b/make_os.sh @@ -38,9 +38,14 @@ done # anchor; objcopy -O binary flattens the linked ELF into the on-disk # blob. mkdir -p build +make -C user/libbboeos libbboeos.a >/dev/null || exit 1 nasm -f elf32 -i kernel/include/ -o build/libbboeos.o user/vdso/vdso.asm || exit 1 +# --gc-sections drops every clang-compiled libbboeos function the +# pointer-table LONG()s don't reference, so the blob pays only for +# what it actually exports. ld -m elf_i386 -T user/libbboeos/libbboeos.ld -Map=build/libbboeos.map \ - -o build/libbboeos.elf build/libbboeos.o || exit 1 + --gc-sections -o build/libbboeos.elf \ + build/libbboeos.o user/libbboeos/libbboeos.a || exit 1 objcopy -O binary build/libbboeos.elf build/libbboeos || exit 1 # Two-pass build: assemble kernel.bin first, measure its sector count, diff --git a/user/libbboeos/Makefile b/user/libbboeos/Makefile index 3653d588..4b85e9f4 100644 --- a/user/libbboeos/Makefile +++ b/user/libbboeos/Makefile @@ -26,6 +26,7 @@ CC := clang # force clang — `?=` would lose to Make's built-in CC=cc CFLAGS := --target=i386-pc-none-elf -m32 -march=i386 -mno-mmx -mno-sse -mno-sse2 \ -mno-implicit-float -fno-vectorize -fno-slp-vectorize \ -ffreestanding -fno-pic -fno-stack-protector \ + -ffunction-sections -fdata-sections \ -nostdlib -nostdinc -O2 -Wall -Wextra -Werror -Iinclude C_SRCS := builtins.c ctype.c dirent.c errno.c math.c signal.c stdio.c stdlib.c string.c syscall.c OBJS = $(C_SRCS:.c=.o) $(S_SRCS:.S=.o) diff --git a/user/libbboeos/libbboeos.ld b/user/libbboeos/libbboeos.ld index 016d6a66..158cd42d 100644 --- a/user/libbboeos/libbboeos.ld +++ b/user/libbboeos/libbboeos.ld @@ -10,34 +10,47 @@ * 0x10046 .libbboeos.text shared_* helper bodies (ported * from src/lib/{proc,print}.asm). * ... .libbboeos.rodata print_datetime_month_lengths. - * 0x10460 .libbboeos.sigreturn __kernel_sigreturn trampoline + * 0x10FE0 .libbboeos.sigreturn __kernel_sigreturn trampoline * (matches VDSO_SIGRETURN_OFFSET). - * 0x10800 .libbboeos.pointer_table FUNCTION_POINTER_TABLE — 13 - * absolute LONG(shared_*) entries - * the linker resolves at link - * time, replacing the previous - * gen_libbboeos_pointers.py + - * python-concat dance. + * 0x10800 .libbboeos.pointer_table FUNCTION_POINTER_TABLE. 13 + * legacy LONG(shared_*) entries + * + a growing tail of clang- + * compiled libbboeos exports. + * Entry order MUST match the + * FUNCTION_*_PTR offsets in + * kernel/include/constants.asm. * - * Future libbboeos C bodies (Phase 3+) land in .libbboeos.text, growing - * the helper region until it bumps into the 0x10460 sigreturn anchor. - * objcopy -O binary flattens the linked ELF into build/libbboeos, which + * Clang-compiled libbboeos C bodies (string.c, etc.) land in + * .libbboeos.text via `*(.text .text.*)`; -ffunction-sections + ld + * --gc-sections drop any function the LONG()s below don't reference, + * so only what the blob actually exports gets paid for. objcopy -O + * binary flattens the linked ELF into build/libbboeos, which * make_os.sh adds to the disk image as `lib/libbboeos`. */ ENTRY(function_table) +/* Force ld to pull these archive members in (and seed --gc-sections). + * Without EXTERN, the LONG() references inside SECTIONS aren't enough + * to trigger archive resolution. */ +EXTERN(strcmp) + SECTIONS { . = 0x00010000; .libbboeos.function_table : { KEEP(*(.libbboeos.function_table)) } - .libbboeos.text : { *(.libbboeos.text) } - .libbboeos.rodata : { *(.libbboeos.rodata) } - - . = 0x00010460; - .libbboeos.sigreturn : { KEEP(*(.libbboeos.sigreturn)) } + .libbboeos.text : { + *(.libbboeos.text) + *(.text .text.*) + } + .libbboeos.rodata : { + *(.libbboeos.rodata) + *(.rodata .rodata.*) + } . = 0x00010800; .libbboeos.pointer_table : { + /* Legacy vDSO helpers (asm). Order pinned by FUNCTION_*_PTR in + * kernel/include/constants.asm — entries here align 1:1. */ LONG(shared_die); LONG(shared_exit); LONG(shared_get_character); @@ -51,8 +64,19 @@ SECTIONS { LONG(shared_print_string); LONG(shared_printf); LONG(shared_write_stdout); + /* Clang-compiled libbboeos exports. Sorted alphabetically. + * Stays freely-reorderable until the cc.py extern-call fallback + * ships and the first on-disk bin/* program bakes in an + * offset; from then on the block becomes append-only. Until + * then, insert new entries in alphabetical position and update + * the matching FUNCTION__PTR offsets in + * kernel/include/constants.asm together. */ + LONG(strcmp); } + . = 0x00010FE0; + .libbboeos.sigreturn : { KEEP(*(.libbboeos.sigreturn)) } + /DISCARD/ : { *(.note*) *(.comment)