From 5ea5978ee801f9791702f5afb79b66906edcd61d Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 29 Jan 2023 19:36:20 -0800 Subject: [PATCH] [kernel] Hide kernel symbols by default Using `-fvisibility=hidden` when building the kernel, and then `--discard-all` when stripping it, we shave almost 100KiB off of the resulting ELF file. Also dropped some unused symbols from the linker script, and rearranged the sections so that the file is able to be mapped directly into memory instead of having each section copied. --- configs/kernel-debug.yaml | 3 ++ configs/rules.ninja | 2 +- external/uefi/boot_services.h | 2 +- src/boot/allocator.cpp | 2 +- src/boot/allocator.h | 2 +- src/boot/loader.cpp | 64 +++++++++++++------------- src/boot/loader.h | 15 +++--- src/boot/main.cpp | 4 +- src/kernel/boot.s | 14 +++--- src/kernel/debug.s | 12 ++--- src/kernel/gdtidt.s | 8 ++-- src/kernel/interrupts.s | 12 ++--- src/kernel/kernel.ld | 86 +++++++++++++++++++---------------- src/kernel/smp.s | 8 ++-- src/kernel/syscall.s | 6 +-- src/kernel/task.s | 4 +- src/libraries/elf/elf/file.h | 2 +- 17 files changed, 126 insertions(+), 120 deletions(-) diff --git a/configs/kernel-debug.yaml b/configs/kernel-debug.yaml index 77fd39f..1d60d7b 100644 --- a/configs/kernel-debug.yaml +++ b/configs/kernel-debug.yaml @@ -15,11 +15,14 @@ variables: "-ffreestanding", "-nodefaultlibs", "-fno-builtin", + "-fno-plt", "-mno-sse", "-fno-omit-frame-pointer", "-mno-red-zone", "-mcmodel=kernel", + "-fvisibility=hidden", + "-fvisibility-inlines-hidden", "-g3", "-ggdb", diff --git a/configs/rules.ninja b/configs/rules.ninja index ad32296..ecfe1df 100644 --- a/configs/rules.ninja +++ b/configs/rules.ninja @@ -75,7 +75,7 @@ rule strip command = $ cp $in $out; $ objcopy --only-keep-debug $out $debug; $ - strip -g $out; $ + strip --discard-all -g $out; $ objcopy --add-gnu-debuglink=$debug $out rule touch diff --git a/external/uefi/boot_services.h b/external/uefi/boot_services.h index 363a9bb..2ac9f61 100644 --- a/external/uefi/boot_services.h +++ b/external/uefi/boot_services.h @@ -22,7 +22,7 @@ namespace bs_impl { using create_event = status (*)(evt, tpl, event_notify, void*, event*); using exit_boot_services = status (*)(handle, size_t); using locate_protocol = status (*)(const guid*, void*, void**); - using copy_mem = void (*)(void*, void*, size_t); + using copy_mem = void (*)(void*, const void*, size_t); using set_mem = void (*)(void*, uint64_t, uint8_t); } diff --git a/src/boot/allocator.cpp b/src/boot/allocator.cpp index e1ac31a..7bdc7c0 100644 --- a/src/boot/allocator.cpp +++ b/src/boot/allocator.cpp @@ -155,7 +155,7 @@ allocator::memset(void *start, size_t size, uint8_t value) } void -allocator::copy(void *to, void *from, size_t size) +allocator::copy(void *to, const void *from, size_t size) { m_bs.copy_mem(to, from, size); } diff --git a/src/boot/allocator.h b/src/boot/allocator.h index d0b0f7e..fcb53ff 100644 --- a/src/boot/allocator.h +++ b/src/boot/allocator.h @@ -35,7 +35,7 @@ public: module * allocate_module(); void memset(void *start, size_t size, uint8_t value); - void copy(void *to, void *from, size_t size); + void copy(void *to, const void *from, size_t size); inline void zero(void *start, size_t size) { memset(start, size, 0); } diff --git a/src/boot/loader.cpp b/src/boot/loader.cpp index 63b4075..7d0d3c9 100644 --- a/src/boot/loader.cpp +++ b/src/boot/loader.cpp @@ -35,15 +35,42 @@ load_file( return b; } +void +verify_kernel_header(elf::file &kernel, util::const_buffer data) +{ + status_line status {L"Verifying kernel header"}; + + // The header should be the first non-null section + const elf::section_header § = kernel.sections()[1]; + + const bootproto::header *header = + reinterpret_cast( + util::offset_pointer(data.pointer, sect.offset)); + + if (header->magic != bootproto::header_magic) + error::raise(uefi::status::load_error, L"Bad kernel magic number"); + + if (header->length < sizeof(bootproto::header)) + error::raise(uefi::status::load_error, L"Bad kernel header length"); + + if (header->version < bootproto::min_header_version) + error::raise(uefi::status::unsupported, L"Kernel header version not supported"); + + console::print(L" Loaded kernel vserion: %d.%d.%d %x\r\n", + header->version_major, header->version_minor, header->version_patch, + header->version_gitsha); +} + bootproto::program * load_program( fs::file &disk, const wchar_t *name, - const descriptor &desc) + const descriptor &desc, + bool verify) { status_line status(L"Loading program", name); - util::buffer data = load_file(disk, desc.path); + util::const_buffer data = load_file(disk, desc.path); elf::file program(data.pointer, data.count); if (!program.valid()) { @@ -60,6 +87,9 @@ load_program( error::raise(uefi::status::load_error, L"ELF file not valid"); } + if (verify) + verify_kernel_header(program, data); + size_t num_sections = 0; for (auto &seg : program.programs()) { if (seg.type == elf::segment_type::load) @@ -85,7 +115,7 @@ load_program( size_t page_count = memory::bytes_to_pages(mem_size); void *pages = g_alloc.allocate_pages(page_count, alloc_type::program, true); - void *source = util::offset_pointer(data.pointer, seg.offset); + const void *source = util::offset_pointer(data.pointer, seg.offset); g_alloc.copy(util::offset_pointer(pages, prelude), source, seg.file_size); section.phys_addr = reinterpret_cast(pages); section.virt_addr = virt_addr; @@ -116,33 +146,5 @@ load_module( mod->data = load_file(disk, path); } -void -verify_kernel_header(bootproto::program &program) -{ - status_line status(L"Verifying kernel header"); - - const bootproto::header *header = - reinterpret_cast(program.sections[0].phys_addr); - - if (header->magic != bootproto::header_magic) - error::raise(uefi::status::load_error, L"Bad kernel magic number"); - - if (header->length < sizeof(bootproto::header)) - error::raise(uefi::status::load_error, L"Bad kernel header length"); - - if (header->version < bootproto::min_header_version) - error::raise(uefi::status::unsupported, L"Kernel header version not supported"); - - console::print(L" Loaded kernel vserion: %d.%d.%d %x\r\n", - header->version_major, header->version_minor, header->version_patch, - header->version_gitsha); - - /* - for (auto §ion : program.sections) - console::print(L" Section: p:0x%lx v:0x%lx fs:0x%x ms:0x%x\r\n", - section.phys_addr, section.virt_addr, section.file_size, section.mem_size); - */ -} - } // namespace loader } // namespace boot diff --git a/src/boot/loader.h b/src/boot/loader.h index 3f6d9c1..7b713c2 100644 --- a/src/boot/loader.h +++ b/src/boot/loader.h @@ -28,14 +28,16 @@ load_file( const wchar_t *path); /// Parse and load an ELF file in memory into a loaded image. -/// \arg disk The opened UEFI filesystem to load from -/// \arg desc The descriptor identifying the program -/// \arg name The human-readable name of the program to load +/// \arg disk The opened UEFI filesystem to load from +/// \arg desc The descriptor identifying the program +/// \arg name The human-readable name of the program to load +/// \arg verify If this is the kernel and should have its header verified bootproto::program * load_program( fs::file &disk, const wchar_t *name, - const descriptor &desc); + const descriptor &desc, + bool verify = false); /// Load a file from disk into memory, creating an init args module /// \arg disk The opened UEFI filesystem to load from @@ -51,10 +53,5 @@ load_module( bootproto::module_type type, uint16_t subtype); -/// Verify that a loaded ELF has the j6 kernel header -/// \arg program The program to check for a header -void -verify_kernel_header(bootproto::program &program); - } // namespace loader } // namespace boot diff --git a/src/boot/main.cpp b/src/boot/main.cpp index 8dd03d9..029023b 100644 --- a/src/boot/main.cpp +++ b/src/boot/main.cpp @@ -75,7 +75,7 @@ load_resources(bootproto::args *args, video::screen *screen, uefi::handle image, fs::file bc_data = disk.open(L"jsix\\boot.conf"); bootconfig bc {bc_data.load(), bs}; - args->kernel = loader::load_program(disk, L"kernel", bc.kernel()); + args->kernel = loader::load_program(disk, L"kernel", bc.kernel(), true); args->init = loader::load_program(disk, L"init server", bc.init()); args->flags = static_cast(bc.flags()); @@ -106,8 +106,6 @@ load_resources(bootproto::args *args, video::screen *screen, uefi::handle image, } } } - - loader::verify_kernel_header(*args->kernel); } memory::efi_mem_map diff --git a/src/kernel/boot.s b/src/kernel/boot.s index 1ec9049..b8075c9 100644 --- a/src/kernel/boot.s +++ b/src/kernel/boot.s @@ -2,7 +2,7 @@ MAGIC equ 'j6KERNEL' ; jsix kernel header magic number section .header align 8 -global _kernel_header +global _kernel_header: data hidden _kernel_header: dq MAGIC ; Kernel header magic dw 32 ; Kernel header length @@ -16,8 +16,8 @@ _kernel_header: section .text align 16 -global _kernel_start:function (_kernel_start.end - _kernel_start) -global _kernel_start.real +global _kernel_start: function hidden (_kernel_start.end - _kernel_start) +global _kernel_start.real: function hidden _kernel_start: push rbp ; Never executed, fake function prelude mov rbp, rsp ; to calm down gdb @@ -36,18 +36,18 @@ _kernel_start: ; the scheduler to take over .end: -global bsp_idle:function (bsp_idle.end - bsp_idle) +global bsp_idle: function hidden (bsp_idle.end - bsp_idle) bsp_idle: hlt jmp bsp_idle .end: -global interrupts_enable +global interrupts_enable: function hidden interrupts_enable: sti ret -global interrupts_disable +global interrupts_disable: function hidden interrupts_disable: cli ret @@ -57,5 +57,5 @@ align 0x100 idle_stack_begin: resb 0x4000 ; 16KiB stack space -global idle_stack_end +global idle_stack_end: data hidden idle_stack_end: diff --git a/src/kernel/debug.s b/src/kernel/debug.s index f86130b..e7558ff 100644 --- a/src/kernel/debug.s +++ b/src/kernel/debug.s @@ -1,32 +1,32 @@ -global get_rsp +global get_rsp: function hidden get_rsp: mov rax, rsp ret -global get_rip +global get_rip: function hidden get_rip: pop rax ; do the same thing as 'ret', except with 'jmp' jmp rax ; with the return address still in rax -global get_caller +global get_caller: function hidden get_caller: ; No prelude - don't touch rsp or rbp mov rax, [rbp+8] ret -global get_grandcaller +global get_grandcaller: function hidden get_grandcaller: ; No prelude - don't touch rsp or rbp mov rax, [rbp] mov rax, [rax+8] ret -global get_gsbase +global get_gsbase: function hidden get_gsbase: rdgsbase rax ret -global _halt +global _halt: function hidden _halt: hlt jmp _halt diff --git a/src/kernel/gdtidt.s b/src/kernel/gdtidt.s index 33fd4db..5490263 100644 --- a/src/kernel/gdtidt.s +++ b/src/kernel/gdtidt.s @@ -1,15 +1,15 @@ -global idt_write +global idt_write: function hidden idt_write: lidt [rdi] ; first arg is the IDT pointer location ret -global idt_load +global idt_load: function hidden idt_load: sidt [rdi] ; first arg is where to write the idtr value ret -global gdt_write +global gdt_write: function hidden gdt_write: lgdt [rdi] ; first arg is the GDT pointer location @@ -28,7 +28,7 @@ gdt_write: ltr cx ; fourth arg is the TSS ret -global gdt_load +global gdt_load: function hidden gdt_load: sgdt [rdi] ; first arg is where to write the gdtr value ret diff --git a/src/kernel/interrupts.s b/src/kernel/interrupts.s index 67eae7a..abf4c19 100644 --- a/src/kernel/interrupts.s +++ b/src/kernel/interrupts.s @@ -3,7 +3,7 @@ section .text extern isr_handler -global isr_handler_prelude:function (isr_handler_prelude.end - isr_handler_prelude) +global isr_handler_prelude: function hidden (isr_handler_prelude.end - isr_handler_prelude) isr_handler_prelude: push rbp ; Never executed, fake function prelude mov rbp, rsp ; to calm down gdb @@ -19,7 +19,7 @@ isr_handler_prelude: .end: extern irq_handler -global irq_handler_prelude:function (irq_handler_prelude.end - irq_handler_prelude) +global irq_handler_prelude: function hidden (irq_handler_prelude.end - irq_handler_prelude) irq_handler_prelude: push rbp ; Never executed, fake function prelude mov rbp, rsp ; to calm down gdb @@ -35,7 +35,7 @@ irq_handler_prelude: ; fall through to isr_handler_return .end: -global isr_handler_return:function (isr_handler_return.end - isr_handler_return) +global isr_handler_return: function hidden (isr_handler_return.end - isr_handler_return) isr_handler_return: check_swap_gs pop_all @@ -45,7 +45,7 @@ isr_handler_return: .end: %macro EMIT_ISR 2 - global %1:function (%1.end - %1) + global %1:function hidden (%1.end - %1) %1: push 0 push %2 @@ -54,7 +54,7 @@ isr_handler_return: %endmacro %macro EMIT_EISR 2 - global %1:function (%1.end - %1) + global %1:function hidden (%1.end - %1) %1: push %2 jmp isr_handler_prelude.real @@ -62,7 +62,7 @@ isr_handler_return: %endmacro %macro EMIT_IRQ 2 - global %1:function (%1.end - %1) + global %1:function hidden (%1.end - %1) %1: push 0 push %2 diff --git a/src/kernel/kernel.ld b/src/kernel/kernel.ld index 3c4807d..34ef3fa 100755 --- a/src/kernel/kernel.ld +++ b/src/kernel/kernel.ld @@ -1,53 +1,59 @@ +PHDRS +{ + rodata PT_LOAD PHDRS FILEHDR FLAGS (4) /* read-only */; + text PT_LOAD ; + rwdata PT_LOAD ; + bss PT_LOAD ; +} + +MEMORY +{ + kernel (rwxa) : ORIGIN = 0xFFFF800000000000, LENGTH = 256M +} + ENTRY(_kernel_start.real) + SECTIONS { - . = 0xFFFF800000000000; - - .header : { - __header_start = .; + .header ORIGIN(kernel) + SIZEOF_HEADERS : { + HIDDEN(__header_start = .); KEEP(*(.header)) - __header_end = .; - } + HIDDEN(__header_end = .); + } :rodata - .text ALIGN(4096) : { - *(.text*) - KEEP(*(.isrs)) - } - - .data ALIGN(4096) : { - *(.data*) + .rodata : { *(.rodata*) - } + } :rodata - .ctors : ALIGN(8) { - __ctors = .; + .ap_startup : { + *(.ap_startup*) + } :rodata + + .ctors ALIGN(8) : { + HIDDEN(__ctors = .); KEEP(*(.ctors)) KEEP(*(.init_array)) - __ctors_end = .; - } + HIDDEN(__ctors_end = .); + } :rodata - .bss ALIGN(4096) : { - __bss_start = .; + .text ALIGN(4K) : { + *(.text*) + KEEP(*(.isrs)) + } :text + + .data ALIGN(4K) : { + *(.data*) + } :rwdata + + .syscall_registry : { + *(.syscall_registry*) + } :rwdata + + .bss ALIGN(4K) : { + HIDDEN(__bss_start = .); *(.bss*) - __bss_end = .; - } + HIDDEN(__bss_end = .); + } :bss - .note : { - *(.note.*) - } - - .eh_frame : { - __eh_frame_start = .; - KEEP(*(.eh_frame)) - __eh_frame_end = .; - } - - .eh_frame_hdr : { - KEEP(*(.eh_frame_hdr)) - } - - __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; - __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; - - kernel_end = ALIGN(4096); + HIDDEN(__kernel_end = ALIGN(4096)); } diff --git a/src/kernel/smp.s b/src/kernel/smp.s index d0a4611..1ed33d3 100644 --- a/src/kernel/smp.s +++ b/src/kernel/smp.s @@ -26,7 +26,7 @@ bits 16 default rel align 8 -global ap_startup +global ap_startup: function hidden ap_startup: jmp .start_real @@ -104,13 +104,13 @@ align 8 jmp rax -global ap_startup_code_size +global ap_startup_code_size: function hidden ap_startup_code_size: dq ($ - ap_startup) section .text -global init_ap_trampoline +global init_ap_trampoline: function hidden init_ap_trampoline: push rbp mov rbp, rsp @@ -131,7 +131,7 @@ init_ap_trampoline: ret extern long_ap_startup -global ap_idle:function (ap_idle.end - ap_idle) +global ap_idle:function hidden (ap_idle.end - ap_idle) ap_idle: call long_ap_startup sti diff --git a/src/kernel/syscall.s b/src/kernel/syscall.s index 69a4253..d4eb245 100644 --- a/src/kernel/syscall.s +++ b/src/kernel/syscall.s @@ -22,7 +22,7 @@ extern syscall_registry extern syscall_invalid -global syscall_handler_prelude:function (syscall_handler_prelude.end - syscall_handler_prelude) +global syscall_handler_prelude: function hidden (syscall_handler_prelude.end - syscall_handler_prelude) syscall_handler_prelude: push rbp ; Never executed, fake function prelude mov rbp, rsp ; to calm down gdb @@ -77,7 +77,7 @@ syscall_handler_prelude: call syscall_invalid .end: -global kernel_to_user_trampoline:function (kernel_to_user_trampoline.end - kernel_to_user_trampoline) +global kernel_to_user_trampoline: function hidden (kernel_to_user_trampoline.end - kernel_to_user_trampoline) kernel_to_user_trampoline: pop r15 pop r14 @@ -98,7 +98,7 @@ kernel_to_user_trampoline: o64 sysret .end: -global syscall_enable:function (syscall_enable.end - syscall_enable) +global syscall_enable: function hidden (syscall_enable.end - syscall_enable) syscall_enable: push rbp mov rbp, rsp diff --git a/src/kernel/task.s b/src/kernel/task.s index 0796ceb..6095c36 100644 --- a/src/kernel/task.s +++ b/src/kernel/task.s @@ -1,6 +1,6 @@ %include "tasking.inc" -global task_switch +global task_switch: function hidden task_switch: push rbp mov rbp, rsp @@ -61,7 +61,7 @@ task_switch: pop rbp ret -global _current_gsbase +global _current_gsbase: function hidden _current_gsbase: mov rax, [gs:CPU_DATA.self] ret diff --git a/src/libraries/elf/elf/file.h b/src/libraries/elf/elf/file.h index 6ce72d1..7b9edda 100644 --- a/src/libraries/elf/elf/file.h +++ b/src/libraries/elf/elf/file.h @@ -22,7 +22,7 @@ public: inline size_t size() const { return m_size; } inline unsigned count() const { return m_count; } - inline const T & operator [] (int i) const { return *util::offset_pointer(m_start, m_size*i); } + inline const T & operator [] (int i) const { return *util::offset_pointer(m_start, m_size*i); } inline const iterator begin() const { return iterator(m_start, m_size); } inline const iterator end() const { return util::offset_pointer(m_start, m_size*m_count); }