[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.
This commit is contained in:
Justin C. Miller
2023-01-29 19:36:20 -08:00
parent e2e1696b7e
commit 5ea5978ee8
17 changed files with 126 additions and 120 deletions

View File

@@ -15,11 +15,14 @@ variables:
"-ffreestanding", "-ffreestanding",
"-nodefaultlibs", "-nodefaultlibs",
"-fno-builtin", "-fno-builtin",
"-fno-plt",
"-mno-sse", "-mno-sse",
"-fno-omit-frame-pointer", "-fno-omit-frame-pointer",
"-mno-red-zone", "-mno-red-zone",
"-mcmodel=kernel", "-mcmodel=kernel",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-g3", "-g3",
"-ggdb", "-ggdb",

View File

@@ -75,7 +75,7 @@ rule strip
command = $ command = $
cp $in $out; $ cp $in $out; $
objcopy --only-keep-debug $out $debug; $ objcopy --only-keep-debug $out $debug; $
strip -g $out; $ strip --discard-all -g $out; $
objcopy --add-gnu-debuglink=$debug $out objcopy --add-gnu-debuglink=$debug $out
rule touch rule touch

View File

@@ -22,7 +22,7 @@ namespace bs_impl {
using create_event = status (*)(evt, tpl, event_notify, void*, event*); using create_event = status (*)(evt, tpl, event_notify, void*, event*);
using exit_boot_services = status (*)(handle, size_t); using exit_boot_services = status (*)(handle, size_t);
using locate_protocol = status (*)(const guid*, void*, void**); 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); using set_mem = void (*)(void*, uint64_t, uint8_t);
} }

View File

@@ -155,7 +155,7 @@ allocator::memset(void *start, size_t size, uint8_t value)
} }
void 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); m_bs.copy_mem(to, from, size);
} }

View File

@@ -35,7 +35,7 @@ public:
module * allocate_module(); module * allocate_module();
void memset(void *start, size_t size, uint8_t value); 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); } inline void zero(void *start, size_t size) { memset(start, size, 0); }

View File

@@ -35,15 +35,42 @@ load_file(
return b; 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 &sect = kernel.sections()[1];
const bootproto::header *header =
reinterpret_cast<const bootproto::header *>(
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 * bootproto::program *
load_program( load_program(
fs::file &disk, fs::file &disk,
const wchar_t *name, const wchar_t *name,
const descriptor &desc) const descriptor &desc,
bool verify)
{ {
status_line status(L"Loading program", name); 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); elf::file program(data.pointer, data.count);
if (!program.valid()) { if (!program.valid()) {
@@ -60,6 +87,9 @@ load_program(
error::raise(uefi::status::load_error, L"ELF file not valid"); error::raise(uefi::status::load_error, L"ELF file not valid");
} }
if (verify)
verify_kernel_header(program, data);
size_t num_sections = 0; size_t num_sections = 0;
for (auto &seg : program.programs()) { for (auto &seg : program.programs()) {
if (seg.type == elf::segment_type::load) if (seg.type == elf::segment_type::load)
@@ -85,7 +115,7 @@ load_program(
size_t page_count = memory::bytes_to_pages(mem_size); size_t page_count = memory::bytes_to_pages(mem_size);
void *pages = g_alloc.allocate_pages(page_count, alloc_type::program, true); 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); g_alloc.copy(util::offset_pointer(pages, prelude), source, seg.file_size);
section.phys_addr = reinterpret_cast<uintptr_t>(pages); section.phys_addr = reinterpret_cast<uintptr_t>(pages);
section.virt_addr = virt_addr; section.virt_addr = virt_addr;
@@ -116,33 +146,5 @@ load_module(
mod->data = load_file(disk, path); 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<const bootproto::header *>(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 &section : 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 loader
} // namespace boot } // namespace boot

View File

@@ -31,11 +31,13 @@ load_file(
/// \arg disk The opened UEFI filesystem to load from /// \arg disk The opened UEFI filesystem to load from
/// \arg desc The descriptor identifying the program /// \arg desc The descriptor identifying the program
/// \arg name The human-readable name of the program to load /// \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 * bootproto::program *
load_program( load_program(
fs::file &disk, fs::file &disk,
const wchar_t *name, 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 /// Load a file from disk into memory, creating an init args module
/// \arg disk The opened UEFI filesystem to load from /// \arg disk The opened UEFI filesystem to load from
@@ -51,10 +53,5 @@ load_module(
bootproto::module_type type, bootproto::module_type type,
uint16_t subtype); 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 loader
} // namespace boot } // namespace boot

View File

@@ -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"); fs::file bc_data = disk.open(L"jsix\\boot.conf");
bootconfig bc {bc_data.load(), bs}; 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->init = loader::load_program(disk, L"init server", bc.init());
args->flags = static_cast<bootproto::boot_flags>(bc.flags()); args->flags = static_cast<bootproto::boot_flags>(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 memory::efi_mem_map

View File

@@ -2,7 +2,7 @@ MAGIC equ 'j6KERNEL' ; jsix kernel header magic number
section .header section .header
align 8 align 8
global _kernel_header global _kernel_header: data hidden
_kernel_header: _kernel_header:
dq MAGIC ; Kernel header magic dq MAGIC ; Kernel header magic
dw 32 ; Kernel header length dw 32 ; Kernel header length
@@ -16,8 +16,8 @@ _kernel_header:
section .text section .text
align 16 align 16
global _kernel_start:function (_kernel_start.end - _kernel_start) global _kernel_start: function hidden (_kernel_start.end - _kernel_start)
global _kernel_start.real global _kernel_start.real: function hidden
_kernel_start: _kernel_start:
push rbp ; Never executed, fake function prelude push rbp ; Never executed, fake function prelude
mov rbp, rsp ; to calm down gdb mov rbp, rsp ; to calm down gdb
@@ -36,18 +36,18 @@ _kernel_start:
; the scheduler to take over ; the scheduler to take over
.end: .end:
global bsp_idle:function (bsp_idle.end - bsp_idle) global bsp_idle: function hidden (bsp_idle.end - bsp_idle)
bsp_idle: bsp_idle:
hlt hlt
jmp bsp_idle jmp bsp_idle
.end: .end:
global interrupts_enable global interrupts_enable: function hidden
interrupts_enable: interrupts_enable:
sti sti
ret ret
global interrupts_disable global interrupts_disable: function hidden
interrupts_disable: interrupts_disable:
cli cli
ret ret
@@ -57,5 +57,5 @@ align 0x100
idle_stack_begin: idle_stack_begin:
resb 0x4000 ; 16KiB stack space resb 0x4000 ; 16KiB stack space
global idle_stack_end global idle_stack_end: data hidden
idle_stack_end: idle_stack_end:

View File

@@ -1,32 +1,32 @@
global get_rsp global get_rsp: function hidden
get_rsp: get_rsp:
mov rax, rsp mov rax, rsp
ret ret
global get_rip global get_rip: function hidden
get_rip: get_rip:
pop rax ; do the same thing as 'ret', except with 'jmp' pop rax ; do the same thing as 'ret', except with 'jmp'
jmp rax ; with the return address still in rax jmp rax ; with the return address still in rax
global get_caller global get_caller: function hidden
get_caller: get_caller:
; No prelude - don't touch rsp or rbp ; No prelude - don't touch rsp or rbp
mov rax, [rbp+8] mov rax, [rbp+8]
ret ret
global get_grandcaller global get_grandcaller: function hidden
get_grandcaller: get_grandcaller:
; No prelude - don't touch rsp or rbp ; No prelude - don't touch rsp or rbp
mov rax, [rbp] mov rax, [rbp]
mov rax, [rax+8] mov rax, [rax+8]
ret ret
global get_gsbase global get_gsbase: function hidden
get_gsbase: get_gsbase:
rdgsbase rax rdgsbase rax
ret ret
global _halt global _halt: function hidden
_halt: _halt:
hlt hlt
jmp _halt jmp _halt

View File

@@ -1,15 +1,15 @@
global idt_write global idt_write: function hidden
idt_write: idt_write:
lidt [rdi] ; first arg is the IDT pointer location lidt [rdi] ; first arg is the IDT pointer location
ret ret
global idt_load global idt_load: function hidden
idt_load: idt_load:
sidt [rdi] ; first arg is where to write the idtr value sidt [rdi] ; first arg is where to write the idtr value
ret ret
global gdt_write global gdt_write: function hidden
gdt_write: gdt_write:
lgdt [rdi] ; first arg is the GDT pointer location lgdt [rdi] ; first arg is the GDT pointer location
@@ -28,7 +28,7 @@ gdt_write:
ltr cx ; fourth arg is the TSS ltr cx ; fourth arg is the TSS
ret ret
global gdt_load global gdt_load: function hidden
gdt_load: gdt_load:
sgdt [rdi] ; first arg is where to write the gdtr value sgdt [rdi] ; first arg is where to write the gdtr value
ret ret

View File

@@ -3,7 +3,7 @@
section .text section .text
extern isr_handler 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: isr_handler_prelude:
push rbp ; Never executed, fake function prelude push rbp ; Never executed, fake function prelude
mov rbp, rsp ; to calm down gdb mov rbp, rsp ; to calm down gdb
@@ -19,7 +19,7 @@ isr_handler_prelude:
.end: .end:
extern irq_handler 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: irq_handler_prelude:
push rbp ; Never executed, fake function prelude push rbp ; Never executed, fake function prelude
mov rbp, rsp ; to calm down gdb mov rbp, rsp ; to calm down gdb
@@ -35,7 +35,7 @@ irq_handler_prelude:
; fall through to isr_handler_return ; fall through to isr_handler_return
.end: .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: isr_handler_return:
check_swap_gs check_swap_gs
pop_all pop_all
@@ -45,7 +45,7 @@ isr_handler_return:
.end: .end:
%macro EMIT_ISR 2 %macro EMIT_ISR 2
global %1:function (%1.end - %1) global %1:function hidden (%1.end - %1)
%1: %1:
push 0 push 0
push %2 push %2
@@ -54,7 +54,7 @@ isr_handler_return:
%endmacro %endmacro
%macro EMIT_EISR 2 %macro EMIT_EISR 2
global %1:function (%1.end - %1) global %1:function hidden (%1.end - %1)
%1: %1:
push %2 push %2
jmp isr_handler_prelude.real jmp isr_handler_prelude.real
@@ -62,7 +62,7 @@ isr_handler_return:
%endmacro %endmacro
%macro EMIT_IRQ 2 %macro EMIT_IRQ 2
global %1:function (%1.end - %1) global %1:function hidden (%1.end - %1)
%1: %1:
push 0 push 0
push %2 push %2

View File

@@ -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) ENTRY(_kernel_start.real)
SECTIONS SECTIONS
{ {
. = 0xFFFF800000000000; .header ORIGIN(kernel) + SIZEOF_HEADERS : {
HIDDEN(__header_start = .);
.header : {
__header_start = .;
KEEP(*(.header)) KEEP(*(.header))
__header_end = .; HIDDEN(__header_end = .);
} } :rodata
.text ALIGN(4096) : { .rodata : {
*(.text*)
KEEP(*(.isrs))
}
.data ALIGN(4096) : {
*(.data*)
*(.rodata*) *(.rodata*)
} } :rodata
.ctors : ALIGN(8) { .ap_startup : {
__ctors = .; *(.ap_startup*)
} :rodata
.ctors ALIGN(8) : {
HIDDEN(__ctors = .);
KEEP(*(.ctors)) KEEP(*(.ctors))
KEEP(*(.init_array)) KEEP(*(.init_array))
__ctors_end = .; HIDDEN(__ctors_end = .);
} } :rodata
.bss ALIGN(4096) : { .text ALIGN(4K) : {
__bss_start = .; *(.text*)
KEEP(*(.isrs))
} :text
.data ALIGN(4K) : {
*(.data*)
} :rwdata
.syscall_registry : {
*(.syscall_registry*)
} :rwdata
.bss ALIGN(4K) : {
HIDDEN(__bss_start = .);
*(.bss*) *(.bss*)
__bss_end = .; HIDDEN(__bss_end = .);
} } :bss
.note : { HIDDEN(__kernel_end = ALIGN(4096));
*(.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);
} }

View File

@@ -26,7 +26,7 @@ bits 16
default rel default rel
align 8 align 8
global ap_startup global ap_startup: function hidden
ap_startup: ap_startup:
jmp .start_real jmp .start_real
@@ -104,13 +104,13 @@ align 8
jmp rax jmp rax
global ap_startup_code_size global ap_startup_code_size: function hidden
ap_startup_code_size: ap_startup_code_size:
dq ($ - ap_startup) dq ($ - ap_startup)
section .text section .text
global init_ap_trampoline global init_ap_trampoline: function hidden
init_ap_trampoline: init_ap_trampoline:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@@ -131,7 +131,7 @@ init_ap_trampoline:
ret ret
extern long_ap_startup 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: ap_idle:
call long_ap_startup call long_ap_startup
sti sti

View File

@@ -22,7 +22,7 @@ extern syscall_registry
extern syscall_invalid 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: syscall_handler_prelude:
push rbp ; Never executed, fake function prelude push rbp ; Never executed, fake function prelude
mov rbp, rsp ; to calm down gdb mov rbp, rsp ; to calm down gdb
@@ -77,7 +77,7 @@ syscall_handler_prelude:
call syscall_invalid call syscall_invalid
.end: .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: kernel_to_user_trampoline:
pop r15 pop r15
pop r14 pop r14
@@ -98,7 +98,7 @@ kernel_to_user_trampoline:
o64 sysret o64 sysret
.end: .end:
global syscall_enable:function (syscall_enable.end - syscall_enable) global syscall_enable: function hidden (syscall_enable.end - syscall_enable)
syscall_enable: syscall_enable:
push rbp push rbp
mov rbp, rsp mov rbp, rsp

View File

@@ -1,6 +1,6 @@
%include "tasking.inc" %include "tasking.inc"
global task_switch global task_switch: function hidden
task_switch: task_switch:
push rbp push rbp
mov rbp, rsp mov rbp, rsp
@@ -61,7 +61,7 @@ task_switch:
pop rbp pop rbp
ret ret
global _current_gsbase global _current_gsbase: function hidden
_current_gsbase: _current_gsbase:
mov rax, [gs:CPU_DATA.self] mov rax, [gs:CPU_DATA.self]
ret ret

View File

@@ -22,7 +22,7 @@ public:
inline size_t size() const { return m_size; } inline size_t size() const { return m_size; }
inline unsigned count() const { return m_count; } inline unsigned count() const { return m_count; }
inline const T & operator [] (int i) const { return *util::offset_pointer<T>(m_start, m_size*i); } inline const T & operator [] (int i) const { return *util::offset_pointer<const T>(m_start, m_size*i); }
inline const iterator begin() const { return iterator(m_start, m_size); } 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); } inline const iterator end() const { return util::offset_pointer(m_start, m_size*m_count); }