diff --git a/kernel/arch/i686/Thread.S b/kernel/arch/i686/Thread.S index 47ea765d..abe76971 100644 --- a/kernel/arch/i686/Thread.S +++ b/kernel/arch/i686/Thread.S @@ -41,15 +41,6 @@ start_userspace_thread: call get_thread_start_sp movl %eax, %esp - # STACK LAYOUT - # entry - # argc - # argv - # envp - # userspace stack - - call get_userspace_thread_stack_top - movw $(0x20 | 3), %bx movw %bx, %ds movw %bx, %es @@ -57,15 +48,4 @@ start_userspace_thread: movw %bx, %gs xorw %bx, %bx - popl %edi - popl %esi - popl %edx - popl %ecx - popl %ebx - - pushl $(0x20 | 3) - pushl %eax - pushl $0x202 - pushl $(0x18 | 3) - pushl %ebx iret diff --git a/kernel/arch/x86_64/Thread.S b/kernel/arch/x86_64/Thread.S index c5b449cd..ddc07b92 100644 --- a/kernel/arch/x86_64/Thread.S +++ b/kernel/arch/x86_64/Thread.S @@ -32,24 +32,4 @@ start_userspace_thread: call get_thread_start_sp movq %rax, %rsp - # STACK LAYOUT - # entry - # argc - # argv - # envp - # userspace stack - - call get_userspace_thread_stack_top - - popq %rdi - popq %rsi - popq %rdx - popq %rcx - popq %rbx - - pushq $(0x20 | 3) - pushq %rax - pushq $0x202 - pushq $(0x18 | 3) - pushq %rbx iretq diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 18900705..ad199cc5 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -34,15 +34,6 @@ namespace Kernel public: using entry_t = Thread::entry_t; - struct userspace_info_t - { - uintptr_t entry { 0 }; - int argc { 0 }; - char** argv { nullptr }; - char** envp { nullptr }; - int file_fd { -1 }; - }; - public: static Process* create_kernel(); static Process* create_kernel(entry_t, void*); @@ -183,7 +174,7 @@ namespace Kernel BAN::ErrorOr sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset); BAN::ErrorOr sys_yield(); - BAN::ErrorOr sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg); + BAN::ErrorOr sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg); BAN::ErrorOr sys_pthread_exit(void* value); BAN::ErrorOr sys_pthread_join(pthread_t thread, void** value); BAN::ErrorOr sys_pthread_self(); @@ -208,7 +199,6 @@ namespace Kernel size_t proc_environ(off_t offset, BAN::ByteSpan) const; bool is_userspace() const { return m_is_userspace; } - const userspace_info_t& userspace_info() const { return m_userspace_info; } // Returns error if page could not be allocated // Returns true if the page was allocated successfully @@ -315,7 +305,6 @@ namespace Kernel BAN::Vector m_environ; bool m_is_userspace { false }; - userspace_info_t m_userspace_info; SpinLock m_child_exit_lock; BAN::Vector m_child_exit_statuses; diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index a861a2bc..92933d49 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -41,9 +43,10 @@ namespace Kernel BAN::ErrorOr pthread_create(entry_t, void*); BAN::ErrorOr clone(Process*, uintptr_t sp, uintptr_t ip); - void setup_exec(); void setup_process_cleanup(); + BAN::ErrorOr initialize_userspace(vaddr_t entry, BAN::Span argv, BAN::Span envp, BAN::Span auxv); + // Returns true, if thread is going to trigger signal bool is_interrupted_by_signal() const; @@ -100,7 +103,7 @@ namespace Kernel private: Thread(pid_t tid, Process*); - void setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3); + void setup_exec(vaddr_t ip, vaddr_t sp); static void on_exit_trampoline(Thread*); void on_exit(); diff --git a/kernel/kernel/IDT.cpp b/kernel/kernel/IDT.cpp index 197ef5be..af662e1b 100644 --- a/kernel/kernel/IDT.cpp +++ b/kernel/kernel/IDT.cpp @@ -248,11 +248,7 @@ namespace Kernel } if (Thread::current().has_process() && Process::current().is_userspace()) - { - const char* const* argv = Process::current().userspace_info().argv; - if (argv && *argv) - process_name = *argv; - } + process_name = Process::current().name(); #if ARCH(x86_64) dwarnln( diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 95129040..6fc41015 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include #include @@ -116,76 +118,51 @@ namespace Kernel process->m_working_directory = VirtualFileSystem::get().root_file(); process->m_page_table = BAN::UniqPtr::adopt(MUST(PageTable::create_userspace())); - TRY(process->m_cmdline.push_back({})); + TRY(process->m_cmdline.emplace_back()); TRY(process->m_cmdline.back().append(path)); + for (auto argument : arguments) + { + TRY(process->m_cmdline.emplace_back()); + TRY(process->m_cmdline.back().append(argument)); + } LockGuard _(process->m_process_lock); - auto executable_inode = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC)).inode; + auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC)); + auto executable_inode = executable_file.inode; + auto executable = TRY(ELF::load_from_inode(executable_inode, process->m_credentials, process->page_table())); process->m_mapped_regions = BAN::move(executable.regions); - char** argv_addr = nullptr; - { - size_t needed_bytes = sizeof(char*) + path.size() + 1; - for (auto argument : arguments) - needed_bytes += sizeof(char*) + argument.size() + 1; - needed_bytes += sizeof(char*); - - if (auto rem = needed_bytes % PAGE_SIZE) - needed_bytes += PAGE_SIZE - rem; - - auto argv_region = MUST(MemoryBackedRegion::create( - process->page_table(), - needed_bytes, - { .start = 0x400000, .end = KERNEL_OFFSET }, - MemoryRegion::Type::PRIVATE, - PageTable::Flags::UserSupervisor | PageTable::Flags::Present - )); - argv_addr = reinterpret_cast(argv_region->vaddr()); - - uintptr_t offset = sizeof(char*) * (1 + arguments.size() + 1); - for (size_t i = 0; i <= arguments.size(); i++) - { - const uintptr_t addr = argv_region->vaddr() + offset; - TRY(argv_region->copy_data_to_region(i * sizeof(char*), reinterpret_cast(&addr), sizeof(char*))); - - const auto current = (i == 0) ? path : arguments[i - 1]; - TRY(argv_region->copy_data_to_region(offset, reinterpret_cast(current.data()), current.size())); - - const uint8_t zero = 0; - TRY(argv_region->copy_data_to_region(offset + current.size(), &zero, 1)); - - offset += current.size() + 1; - } - - const uintptr_t zero = 0; - TRY(argv_region->copy_data_to_region((1 + arguments.size()) * sizeof(char*), reinterpret_cast(&zero), sizeof(char*))); - - TRY(process->m_mapped_regions.push_back(BAN::move(argv_region))); - } - if (executable_inode->mode().mode & +Inode::Mode::ISUID) process->m_credentials.set_euid(executable_inode->uid()); if (executable_inode->mode().mode & +Inode::Mode::ISGID) process->m_credentials.set_egid(executable_inode->gid()); + BAN::Vector auxiliary_vector; + TRY(auxiliary_vector.reserve(1 + executable.open_execfd)); + if (executable.has_interpreter) { - VirtualFileSystem::File file; - TRY(file.canonical_path.append("")); - file.inode = executable_inode; - process->m_userspace_info.file_fd = TRY(process->m_open_file_descriptors.open(BAN::move(file), O_RDONLY)); + const int execfd = TRY(process->m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY)); + TRY(auxiliary_vector.push_back({ + .a_type = LibELF::AT_EXECFD, + .a_un = { .a_val = static_cast(execfd) }, + })); } - process->m_is_userspace = true; - process->m_userspace_info.entry = executable.entry_point; - process->m_userspace_info.argc = 1 + arguments.size(); - process->m_userspace_info.argv = argv_addr; - process->m_userspace_info.envp = nullptr; + TRY(auxiliary_vector.push_back({ + .a_type = LibELF::AT_NULL, + .a_un = { .a_val = 0 }, + })); auto* thread = MUST(Thread::create_userspace(process, process->page_table())); - thread->setup_exec(); + MUST(thread->initialize_userspace( + executable.entry_point, + process->m_cmdline.span(), + process->m_environ.span(), + auxiliary_vector.span() + )); process->add_thread(thread); process->register_to_scheduler(); @@ -534,7 +511,6 @@ namespace Kernel forked->m_open_file_descriptors = BAN::move(*open_file_descriptors); forked->m_mapped_regions = BAN::move(mapped_regions); forked->m_is_userspace = m_is_userspace; - forked->m_userspace_info = m_userspace_info; forked->m_has_called_exec = false; memcpy(forked->m_signal_handlers, m_signal_handlers, sizeof(m_signal_handlers)); @@ -561,77 +537,62 @@ namespace Kernel TRY(validate_string_access(path)); - auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC)); - auto executable_inode = executable_file.inode; - BAN::Vector str_argv; for (int i = 0; argv && argv[i]; i++) { TRY(validate_pointer_access(argv + i, sizeof(char*), false)); TRY(validate_string_access(argv[i])); - TRY(str_argv.emplace_back(argv[i])); + TRY(str_argv.emplace_back()); + TRY(str_argv.back().append(argv[i])); } BAN::Vector str_envp; for (int i = 0; envp && envp[i]; i++) { - TRY(validate_pointer_access(envp + 1, sizeof(char*), false)); + TRY(validate_pointer_access(envp + i, sizeof(char*), false)); TRY(validate_string_access(envp[i])); - TRY(str_envp.emplace_back(envp[i])); + TRY(str_envp.emplace_back()); + TRY(str_envp.back().append(envp[i])); } + auto executable_file = TRY(find_file(AT_FDCWD, path, O_EXEC)); + auto executable_inode = executable_file.inode; + auto executable = TRY(ELF::load_from_inode(executable_inode, m_credentials, *new_page_table)); auto new_mapped_regions = BAN::move(executable.regions); - int file_fd = -1; + BAN::Vector auxiliary_vector; + TRY(auxiliary_vector.reserve(1 + executable.open_execfd)); + + BAN::ScopeGuard execfd_guard([this, &auxiliary_vector] { + if (auxiliary_vector.empty()) + return; + if (auxiliary_vector.front().a_type != LibELF::AT_EXECFD) + return; + MUST(m_open_file_descriptors.close(auxiliary_vector.front().a_un.a_val)); + }); + if (executable.has_interpreter) { - VirtualFileSystem::File file; - file.canonical_path = BAN::move(executable_file.canonical_path); - file.inode = executable_inode; - file_fd = TRY(m_open_file_descriptors.open(BAN::move(file), O_RDONLY)); + const int execfd = TRY(m_open_file_descriptors.open(BAN::move(executable_file), O_RDONLY)); + TRY(auxiliary_vector.push_back({ + .a_type = LibELF::AT_EXECFD, + .a_un = { .a_val = static_cast(execfd) }, + })); } - BAN::ScopeGuard file_closer([&] { if (file_fd != -1) MUST(m_open_file_descriptors.close(file_fd)); }); - // allocate memory on the new process for arguments and environment - auto create_region = - [&](BAN::Span container) -> BAN::ErrorOr> - { - size_t bytes = sizeof(char*); - for (auto& elem : container) - bytes += sizeof(char*) + elem.size() + 1; - - if (auto rem = bytes % PAGE_SIZE) - bytes += PAGE_SIZE - rem; - - auto region = TRY(MemoryBackedRegion::create( - *new_page_table, - bytes, - { .start = executable.entry_point, .end = KERNEL_OFFSET }, - MemoryRegion::Type::PRIVATE, - PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present - )); - - size_t data_offset = sizeof(char*) * (container.size() + 1); - for (size_t i = 0; i < container.size(); i++) - { - uintptr_t ptr_addr = region->vaddr() + data_offset; - TRY(region->copy_data_to_region(sizeof(char*) * i, (const uint8_t*)&ptr_addr, sizeof(char*))); - TRY(region->copy_data_to_region(data_offset, (const uint8_t*)container[i].data(), container[i].size())); - data_offset += container[i].size() + 1; - } - - uintptr_t null = 0; - TRY(region->copy_data_to_region(sizeof(char*) * container.size(), (const uint8_t*)&null, sizeof(char*))); - - return BAN::UniqPtr(BAN::move(region)); - }; - - TRY(new_mapped_regions.reserve(new_mapped_regions.size() + 2)); - MUST(new_mapped_regions.push_back(TRY(create_region(str_argv.span())))); - MUST(new_mapped_regions.push_back(TRY(create_region(str_envp.span())))); + TRY(auxiliary_vector.push_back({ + .a_type = LibELF::AT_NULL, + .a_un = { .a_val = 0 }, + })); auto* new_thread = TRY(Thread::create_userspace(this, *new_page_table)); + TRY(new_thread->initialize_userspace( + executable.entry_point, + str_argv.span(), + str_envp.span(), + auxiliary_vector.span() + )); ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled); Processor::set_interrupt_state(InterruptState::Disabled); @@ -655,8 +616,8 @@ namespace Kernel m_threads.front()->m_process = nullptr; m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table)); + MUST(Processor::scheduler().add_thread(new_thread)); m_threads.front() = new_thread; - MUST(Processor::scheduler().add_thread(m_threads.front())); for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++) { @@ -673,21 +634,13 @@ namespace Kernel m_mapped_regions = BAN::move(new_mapped_regions); m_page_table = BAN::move(new_page_table); - file_closer.disable(); - - m_userspace_info.argc = str_argv.size(); - m_userspace_info.argv = reinterpret_cast(m_mapped_regions[m_mapped_regions.size() - 2]->vaddr()); - m_userspace_info.envp = reinterpret_cast(m_mapped_regions[m_mapped_regions.size() - 1]->vaddr()); - m_userspace_info.entry = executable.entry_point; - m_userspace_info.file_fd = file_fd; + execfd_guard.disable(); m_cmdline = BAN::move(str_argv); m_environ = BAN::move(str_envp); } m_has_called_exec = true; - - m_threads.front()->setup_exec(); Processor::yield(); ASSERT_NOT_REACHED(); } @@ -2084,7 +2037,7 @@ namespace Kernel return 0; } - BAN::ErrorOr Process::sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg) + BAN::ErrorOr Process::sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg) { if (attr != nullptr) { diff --git a/kernel/kernel/Syscall.cpp b/kernel/kernel/Syscall.cpp index 529683b1..3e33243a 100644 --- a/kernel/kernel/Syscall.cpp +++ b/kernel/kernel/Syscall.cpp @@ -44,11 +44,7 @@ namespace Kernel BAN::ErrorOr ret = BAN::Error::from_errno(ENOSYS); - const char* process_path = nullptr; - if (Process::current().userspace_info().argc > 0 && Process::current().userspace_info().argv) - process_path = Process::current().userspace_info().argv[0]; - if (process_path == nullptr) - process_path = ""; + const char* process_path = Process::current().name(); #if DUMP_ALL_SYSCALLS dprintln("{} pid {}: {}", process_path, Process::current().pid(), s_syscall_names[syscall]); diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 1f8b8e70..f6812b79 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -29,11 +29,6 @@ namespace Kernel return Thread::current().interrupt_stack().sp; } - extern "C" uintptr_t get_userspace_thread_stack_top() - { - return Thread::current().userspace_stack_top() - 4 * sizeof(uintptr_t); - } - extern "C" void load_thread_sse() { Thread::current().load_sse(); @@ -176,11 +171,12 @@ namespace Kernel save_sse(); memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage)); - thread->setup_exec_impl( - reinterpret_cast(entry), - reinterpret_cast(arg), - 0, 0, 0 - ); + PageTable::with_fast_page(thread->userspace_stack().paddr_of(thread->userspace_stack_top() - PAGE_SIZE), [=] { + PageTable::fast_page_as(PAGE_SIZE - sizeof(uintptr_t)) = arg; + }); + + const vaddr_t entry_addr = reinterpret_cast(entry); + thread->setup_exec(entry_addr, thread->userspace_stack_top() - sizeof(uintptr_t)); return thread; } @@ -222,21 +218,112 @@ namespace Kernel return thread; } - void Thread::setup_exec() + BAN::ErrorOr Thread::initialize_userspace(vaddr_t entry, BAN::Span argv, BAN::Span envp, BAN::Span auxv) { - const auto& userspace_info = process().userspace_info(); - ASSERT(userspace_info.entry); + // System V ABI: Initial process stack - setup_exec_impl( - userspace_info.entry, - userspace_info.argc, - reinterpret_cast(userspace_info.argv), - reinterpret_cast(userspace_info.envp), - userspace_info.file_fd - ); + ASSERT(m_is_userspace); + ASSERT(m_userspace_stack); + + size_t needed_size = 0; + + // argc + needed_size += sizeof(uintptr_t); + + // argv + needed_size += (argv.size() + 1) * sizeof(uintptr_t); + for (auto arg : argv) + needed_size += arg.size() + 1; + + // envp + needed_size += (envp.size() + 1) * sizeof(uintptr_t); + for (auto env : envp) + needed_size += env.size() + 1; + + // auxv + needed_size += auxv.size() * sizeof(LibELF::AuxiliaryVector); + + if (needed_size > m_userspace_stack->size()) + return BAN::Error::from_errno(ENOBUFS); + + vaddr_t vaddr = userspace_stack_top() - needed_size; + + const auto stack_copy_buf = + [this](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void + { + ASSERT(vaddr + buffer.size() <= userspace_stack_top()); + + size_t bytes_copied = 0; + while (bytes_copied < buffer.size()) + { + const size_t to_copy = BAN::Math::min(buffer.size() - bytes_copied, PAGE_SIZE - (vaddr % PAGE_SIZE)); + + PageTable::with_fast_page(userspace_stack().paddr_of(vaddr & PAGE_ADDR_MASK), [=]() { + memcpy(PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), buffer.data() + bytes_copied, to_copy); + }); + + vaddr += to_copy; + bytes_copied += to_copy; + } + }; + + const auto stack_push_buf = + [&stack_copy_buf, &vaddr](BAN::ConstByteSpan buffer) -> void + { + stack_copy_buf(buffer, vaddr); + vaddr += buffer.size(); + }; + + const auto stack_push_uint = + [&stack_push_buf](uintptr_t value) -> void + { + stack_push_buf(BAN::ConstByteSpan::from(value)); + }; + + const auto stack_push_str = + [&stack_push_buf](BAN::StringView string) -> void + { + const uint8_t* string_u8 = reinterpret_cast(string.data()); + stack_push_buf(BAN::ConstByteSpan(string_u8, string.size() + 1)); + }; + + // argc + stack_push_uint(argv.size()); + + // argv + const vaddr_t argv_vaddr = vaddr; + vaddr += argv.size() * sizeof(uintptr_t); + stack_push_uint(0); + + // envp + const vaddr_t envp_vaddr = vaddr; + vaddr += envp.size() * sizeof(uintptr_t); + stack_push_uint(0); + + // auxv + for (auto aux : auxv) + stack_push_buf(BAN::ConstByteSpan::from(aux)); + + // information + for (size_t i = 0; i < argv.size(); i++) + { + stack_copy_buf(BAN::ConstByteSpan::from(vaddr), argv_vaddr + i * sizeof(uintptr_t)); + stack_push_str(argv[i]); + } + for (size_t i = 0; i < envp.size(); i++) + { + stack_copy_buf(BAN::ConstByteSpan::from(vaddr), envp_vaddr + i * sizeof(uintptr_t)); + stack_push_str(envp[i]); + } + + ASSERT(vaddr == userspace_stack_top()); + + setup_exec(entry, userspace_stack_top() - needed_size); + + return {}; } - void Thread::setup_exec_impl(uintptr_t entry, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3) + void Thread::setup_exec(vaddr_t ip, vaddr_t sp) { ASSERT(is_userspace()); m_state = State::NotStarted; @@ -244,13 +331,13 @@ namespace Kernel // Signal mask is inherited // Initialize stack for returning - PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] { - uintptr_t sp = PageTable::fast_page() + PAGE_SIZE; - write_to_stack(sp, entry); - write_to_stack(sp, arg3); - write_to_stack(sp, arg2); - write_to_stack(sp, arg1); - write_to_stack(sp, arg0); + PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [=] { + uintptr_t cur_sp = PageTable::fast_page() + PAGE_SIZE; + write_to_stack(cur_sp, 0x20 | 3); + write_to_stack(cur_sp, sp); + write_to_stack(cur_sp, 0x202); + write_to_stack(cur_sp, 0x18 | 3); + write_to_stack(cur_sp, ip); }); m_interrupt_stack.ip = reinterpret_cast(start_userspace_thread); @@ -286,7 +373,7 @@ namespace Kernel m_signal_pending_mask = 0; m_signal_block_mask = ~0ull; - PageTable::with_fast_page(process().page_table().physical_address_of(kernel_stack_top() - PAGE_SIZE), [&] { + PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [&] { uintptr_t sp = PageTable::fast_page() + PAGE_SIZE; write_to_stack(sp, this); write_to_stack(sp, &Thread::on_exit_trampoline); diff --git a/userspace/libraries/LibC/arch/i686/crt0.S b/userspace/libraries/LibC/arch/i686/crt0.S index a1bb0202..af56ddd8 100644 --- a/userspace/libraries/LibC/arch/i686/crt0.S +++ b/userspace/libraries/LibC/arch/i686/crt0.S @@ -2,18 +2,22 @@ .global _start _start: - pushl $0 + # get argc, argv, envp + movl (%esp), %edi + leal 4(%esp), %esi + leal 4(%esi, %edi, 4), %edx + + # align stack + andl $-16, %esp + xorl %ebp, %ebp + + # save argc, argv, envp + subl $4, %esp pushl %edx pushl %esi pushl %edi - # STACK LAYOUT - # null - # argc - # argv - # envp - - xorl %ebp, %ebp + subl $4, %esp pushl $__fini_array_end pushl $__fini_array_start diff --git a/userspace/libraries/LibC/arch/x86_64/crt0.S b/userspace/libraries/LibC/arch/x86_64/crt0.S index 36d4a1da..75627909 100644 --- a/userspace/libraries/LibC/arch/x86_64/crt0.S +++ b/userspace/libraries/LibC/arch/x86_64/crt0.S @@ -2,21 +2,22 @@ .global _start _start: - pushq $0 + # get argc, argv, envp + movq (%rsp), %rdi + leaq 8(%rsp), %rsi + leaq 8(%rsi, %rdi, 8), %rdx + + # align stack + andq $-16, %rsp + xorq %rbp, %rbp + + # save argc, argv, envp + subq $8, %rsp pushq %rdi pushq %rsi pushq %rdx - # STACK LAYOUT - # null - # argc - # argv - # envp - - xorq %rbp, %rbp - - # init libc - movq 0(%rsp), %rdi + movq %rdx, %rdi # environ pushq $__fini_array_end pushq $__fini_array_start @@ -31,9 +32,10 @@ _start: addq $(6 * 8), %rsp # call main - movq 16(%rsp), %rdi - movq 8(%rsp), %rsi - movq 0(%rsp), %rdx + popq %rdx + popq %rsi + popq %rdi + addq $8, %rsp call main # call exit diff --git a/userspace/libraries/LibC/pthread.cpp b/userspace/libraries/LibC/pthread.cpp index 05bc406a..f309fa50 100644 --- a/userspace/libraries/LibC/pthread.cpp +++ b/userspace/libraries/LibC/pthread.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include #include #include @@ -16,15 +18,30 @@ struct pthread_trampoline_info_t }; // stack is 16 byte aligned on entry, this `call` is used to align it -extern "C" void pthread_trampoline(void*); -asm("pthread_trampoline: call pthread_trampoline_cpp"); +extern "C" void _pthread_trampoline(void*); +asm( +#if ARCH(x86_64) +"_pthread_trampoline:" + "popq %rdi;" + "andq $-16, %rsp;" + "xorq %rbp, %rbp;" + "call _pthread_trampoline_cpp" +#elif ARCH(i686) +"_pthread_trampoline:" + "ud2;" + "popl %edi;" + "andl $-16, %esp;" + "xorl %ebp, %ebp;" + "subl $12, %esp;" + "pushl %edi;" + "call _pthread_trampoline_cpp" +#endif +); -extern "C" void pthread_trampoline_cpp(void* arg) +extern "C" void _pthread_trampoline_cpp(void* arg) { - pthread_trampoline_info_t info; - memcpy(&info, arg, sizeof(pthread_trampoline_info_t)); + auto info = *reinterpret_cast(arg); free(arg); - pthread_exit(info.start_routine(info.arg)); ASSERT_NOT_REACHED(); } @@ -63,24 +80,30 @@ void pthread_cleanup_push(void (*routine)(void*), void* arg) s_cleanup_stack = cleanup; } -int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg) +int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg) { auto* info = static_cast(malloc(sizeof(pthread_trampoline_info_t))); if (info == nullptr) - return -1; - info->start_routine = start_routine; - info->arg = arg; + return errno; + + *info = { + .start_routine = start_routine, + .arg = arg, + }; const auto ret = syscall(SYS_PTHREAD_CREATE, attr, pthread_trampoline, info); if (ret == -1) - { - free(info); - return -1; - } + goto pthread_create_error; - if (thread) - *thread = ret; + + if (thread_id) + *thread_id = ret; return 0; + +pthread_create_error: + const int return_code = errno; + free(info); + return return_code; } void pthread_exit(void* value_ptr) diff --git a/userspace/programs/DynamicLoader/main.cpp b/userspace/programs/DynamicLoader/main.cpp index 28e5a958..2d381ccc 100644 --- a/userspace/programs/DynamicLoader/main.cpp +++ b/userspace/programs/DynamicLoader/main.cpp @@ -1,5 +1,6 @@ #include "utils.h" +#include #include #include @@ -15,42 +16,44 @@ void _start() { #if defined(__x86_64__) asm volatile( - "xorq %rbp, %rbp;" + "movq (%rsp), %rdi;" + "leaq 8(%rsp), %rsi;" + "leaq 8(%rsi, %rdi, 8), %rdx;" + + "movq %rsp, %rbp;" + "andq $-16, %rsp;" + "call _entry;" + + "movq %rbp, %rsp;" + "xorq %rbp, %rbp;" + + "jmp *%rax;" + "ud2;" ); #elif defined(__i686__) asm volatile( - "xorl %ebp, %ebp;" - "pushl %ecx;" + "movl (%esp), %edi;" + "leal 4(%esp), %esi;" + "leal 4(%esi, %edi, 4), %edx;" + + "movl %esp, %ebp;" + "andl $-16, %esp;" + + "subl $4, %esp;" "pushl %edx;" "pushl %esi;" "pushl %edi;" - "call _entry;" - "ud2;" - ); -#else - #error "unsupported architecture" -#endif -} -__attribute__((naked, noreturn)) -static void call_entry_point(int, char**, char**, uintptr_t) -{ -#if defined(__x86_64__) - asm volatile( - "andq $-16, %rsp;" - "jmp *%rcx;" - ); -#elif defined(__i686__) - asm volatile( - "addl $4, %esp;" - "popl %edi;" - "popl %esi;" - "popl %edx;" - "popl %ecx;" - "andl $-16, %esp;" - "jmp *%ecx;" + "call _entry;" + + "movl %ebp, %esp;" + "xorl %ebp, %ebp;" + + "jmp *%eax;" + + "ud2;" ); #else #error "unsupported architecture" @@ -901,16 +904,33 @@ static void call_init_funcs(LoadedElf& elf, bool is_main_elf) reinterpret_cast(elf.init)(); for (size_t i = 0; i < elf.init_arraysz / sizeof(init_t); i++) reinterpret_cast(elf.init_array)[i](); +} +static LibELF::AuxiliaryVector* find_auxv(char** envp) +{ + if (envp == nullptr) + return nullptr; + char** null_env = envp; + while (*null_env) + null_env++; + + return reinterpret_cast(null_env + 1); } extern "C" -__attribute__((used, noreturn)) -int _entry(int argc, char** argv, char** envp, int fd) +__attribute__((used)) +uintptr_t _entry(int argc, char* argv[], char* envp[]) { - const bool invoked_directly = (fd < 0); - if (invoked_directly) + int execfd = -1; + if (auto* auxv = find_auxv(envp)) + for (auto* aux = auxv; aux->a_type != LibELF::AT_NULL; aux++) + if (aux->a_type == LibELF::AT_EXECFD) { + execfd = aux->a_un.a_val; + aux->a_type = LibELF::AT_IGNORE; + } + + if (execfd == -1) { if (argc < 2) print_error_and_exit("missing program name", 0); @@ -918,18 +938,19 @@ int _entry(int argc, char** argv, char** envp, int fd) argc--; argv++; - fd = syscall(SYS_OPENAT, AT_FDCWD, argv[0], O_RDONLY); - if (fd < 0) - print_error_and_exit("could not open program", fd); + execfd = syscall(SYS_OPENAT, AT_FDCWD, argv[0], O_RDONLY); + if (execfd < 0) + print_error_and_exit("could not open program", execfd); } init_random(); - auto& elf = load_elf(argv[0], fd); + auto& elf = load_elf(argv[0], execfd); syscall(SYS_CLOSE, fd); fini_random(); relocate_elf(elf, true); initialize_environ(envp); call_init_funcs(elf, true); - call_entry_point(argc, argv, envp, elf.base + elf.file_header.e_entry); + + return elf.base + elf.file_header.e_entry; }